blob: 772e7a599cbd24c9609c7e8d7c6e3b4884b2eeb2 [file] [log] [blame]
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.camera.cts.api31test;
import static android.hardware.camera2.cts.CameraTestUtils.*;
import android.content.Context;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.cts.CameraTestUtils;
import android.hardware.camera2.cts.CameraTestUtils.SimpleImageReaderListener;
import android.hardware.camera2.cts.helpers.CameraErrorCollector;
import android.hardware.camera2.cts.helpers.StaticMetadata;
import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.TotalCaptureResult;
import android.media.Image;
import android.media.ImageReader;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.test.AndroidTestCase;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import com.android.compatibility.common.util.CddTest;
import com.android.ex.camera2.blocking.BlockingSessionCallback;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import static junit.framework.Assert.*;
import static org.mockito.Mockito.*;
public class SPerfClassTest extends AndroidTestCase {
private static final String TAG = "SPerfClassTest";
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
private static final Size FULLHD = new Size(1920, 1080);
private static final Size VGA = new Size(640, 480);
private static final int CONFIGURE_TIMEOUT = 5000; //ms
private static final int CAPTURE_TIMEOUT = 1500; //ms
private CameraManager mCameraManager;
private String[] mCameraIds;
private Handler mHandler;
private HandlerThread mHandlerThread;
private CameraErrorCollector mCollector;
@Override
public void setContext(Context context) {
super.setContext(context);
mCameraManager = context.getSystemService(CameraManager.class);
assertNotNull("Can't connect to camera manager!", mCameraManager);
}
@Override
protected void setUp() throws Exception {
super.setUp();
mCameraIds = mCameraManager.getCameraIdList();
assertNotNull("Camera ids shouldn't be null", mCameraIds);
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
mCollector = new CameraErrorCollector();
}
@Override
protected void tearDown() throws Exception {
mHandlerThread.quitSafely();
mHandler = null;
try {
mCollector.verify();
} catch (Throwable e) {
// When new Exception(e) is used, exception info will be printed twice.
throw new Exception(e.getMessage());
} finally {
super.tearDown();
}
}
// Verify primary camera devices's supported JPEG sizes are at least 1080p.
private void testSPerfClassJpegSizesByCamera(String cameraId) throws Exception {
boolean isPrimaryRear = CameraTestUtils.isPrimaryRearFacingCamera(
mCameraManager, cameraId);
boolean isPrimaryFront = CameraTestUtils.isPrimaryFrontFacingCamera(
mCameraManager, cameraId);
if (!isPrimaryRear && !isPrimaryFront) {
return;
}
CameraCharacteristics c = mCameraManager.getCameraCharacteristics(cameraId);
StaticMetadata staticInfo = new StaticMetadata(c, CheckLevel.ASSERT, mCollector);
Size[] jpegSizes = staticInfo.getJpegOutputSizesChecked();
assertTrue("Primary cameras must support JPEG formats",
jpegSizes != null && jpegSizes.length > 0);
for (Size jpegSize : jpegSizes) {
mCollector.expectTrue(
"Primary camera's JPEG size must be at least 1080p, but is " +
jpegSize,
jpegSize.getWidth() >= FULLHD.getWidth() &&
jpegSize.getHeight() >= FULLHD.getHeight());
}
CameraDevice camera = null;
ImageReader jpegTarget = null;
Image image = null;
try {
camera = CameraTestUtils.openCamera(mCameraManager, cameraId,
/*listener*/null, mHandler);
List<OutputConfiguration> outputConfigs = new ArrayList<>();
SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
jpegTarget = CameraTestUtils.makeImageReader(VGA,
ImageFormat.JPEG, 1 /*maxNumImages*/, imageListener, mHandler);
Surface jpegSurface = jpegTarget.getSurface();
outputConfigs.add(new OutputConfiguration(jpegSurface));
// isSessionConfigurationSupported will return true for JPEG sizes smaller
// than 1080P, due to framework rouding up to closest supported size (1080p).
SessionConfigSupport sessionConfigSupport = isSessionConfigSupported(
camera, mHandler, outputConfigs, /*inputConfig*/ null,
SessionConfiguration.SESSION_REGULAR, true/*defaultSupport*/);
mCollector.expectTrue("isSessionConfiguration fails with error",
!sessionConfigSupport.error);
mCollector.expectTrue("isSessionConfiguration returns false for JPEG < 1080p",
sessionConfigSupport.configSupported);
// Session creation for JPEG sizes smaller than 1080p will succeed, and the
// result JPEG image dimension is rounded up to closest supported size (1080p).
CaptureRequest.Builder request =
camera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
request.addTarget(jpegSurface);
CameraCaptureSession.StateCallback sessionListener =
mock(CameraCaptureSession.StateCallback.class);
CameraCaptureSession session = configureCameraSessionWithConfig(
camera, outputConfigs, sessionListener, mHandler);
verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()).
onConfigured(any(CameraCaptureSession.class));
verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()).
onReady(any(CameraCaptureSession.class));
verify(sessionListener, never()).onConfigureFailed(any(CameraCaptureSession.class));
verify(sessionListener, never()).onActive(any(CameraCaptureSession.class));
verify(sessionListener, never()).onClosed(any(CameraCaptureSession.class));
CameraCaptureSession.CaptureCallback captureListener =
mock(CameraCaptureSession.CaptureCallback.class);
session.capture(request.build(), captureListener, mHandler);
verify(captureListener, timeout(CAPTURE_TIMEOUT).atLeastOnce()).
onCaptureCompleted(any(CameraCaptureSession.class),
any(CaptureRequest.class), any(TotalCaptureResult.class));
verify(captureListener, never()).onCaptureFailed(any(CameraCaptureSession.class),
any(CaptureRequest.class), any(CaptureFailure.class));
image = imageListener.getImage(CAPTURE_TIMEOUT);
assertNotNull("Image must be valid", image);
assertEquals("Image format isn't JPEG", image.getFormat(), ImageFormat.JPEG);
byte[] data = CameraTestUtils.getDataFromImage(image);
assertTrue("Invalid image data", data != null && data.length > 0);
CameraTestUtils.validateJpegData(data, FULLHD.getWidth(), FULLHD.getHeight(),
null /*filePath*/);
} finally {
if (camera != null) {
camera.close();
}
if (jpegTarget != null) {
jpegTarget.close();
}
if (image != null) {
image.close();
}
}
}
/**
* Check JPEG size overrides for devices claiming S Performance class requirement via
* Version.MEDIA_PERFORMANCE_CLASS
*/
public void testSPerfClassJpegSizes() throws Exception {
final boolean isAtLeastSPerfClass =
(Build.VERSION.MEDIA_PERFORMANCE_CLASS >= Build.VERSION_CODES.S);
if (!isAtLeastSPerfClass) {
return;
}
for (int i = 0; i < mCameraIds.length; i++) {
testSPerfClassJpegSizesByCamera(mCameraIds[i]);
}
}
}