/* * Copyright (C) 2014 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.hardware.camera2.cts.testcases; import static android.hardware.camera2.cts.CameraTestUtils.*; import static com.android.ex.camera2.blocking.BlockingStateCallback.STATE_CLOSED; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.ImageReader; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.test.ActivityInstrumentationTestCase2; import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; import android.view.View; import android.view.WindowManager; import android.content.Context; import android.graphics.ImageFormat; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCaptureSession.CaptureCallback; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.util.Size; import android.util.Range; import android.hardware.camera2.cts.Camera2SurfaceViewCtsActivity; import android.hardware.camera2.cts.CameraTestUtils; import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; import android.hardware.camera2.cts.helpers.CameraErrorCollector; import android.hardware.camera2.cts.helpers.StaticMetadata; import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel; import com.android.ex.camera2.blocking.BlockingSessionCallback; import com.android.ex.camera2.blocking.BlockingStateCallback; import com.android.ex.camera2.exceptions.TimeoutRuntimeException; import java.util.Arrays; import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * Camera2 Preview test case base class by using SurfaceView as rendering target. * *
This class encapsulates the SurfaceView based preview common functionalities. * The setup and teardown of CameraManager, test HandlerThread, Activity, Camera IDs * and CameraStateCallback are handled in this class. Some basic preview related utility * functions are provided to facilitate the derived preview-based test classes. *
*/ public class Camera2SurfaceViewTestCase extends ActivityInstrumentationTestCase2* If preview is already started, calling this function will stop the * current preview stream and start a new preview stream with given * parameters. No need to call stopPreview between two startPreview calls. *
* * @param request The request builder used to start the preview. * @param previewSz The size of the camera device output preview stream. * @param listener The callbacks the camera device will notify when preview * capture is available. */ protected void startPreview(CaptureRequest.Builder request, Size previewSz, CaptureCallback listener) throws Exception { // Update preview size. updatePreviewSurface(previewSz); if (VERBOSE) { Log.v(TAG, "start preview with size " + mPreviewSize.toString()); } configurePreviewOutput(request); mSession.setRepeatingRequest(request.build(), listener, mHandler); } /** * Configure the preview output stream. * * @param request The request to be configured with preview surface */ protected void configurePreviewOutput(CaptureRequest.Builder request) throws CameraAccessException { List* The default max number of image is set to image reader. *
* * @param previewRequest The capture request to be used for preview * @param stillRequest The capture request to be used for still capture * @param previewSz Preview size * @param stillSz The still capture size * @param resultListener Capture result listener * @param imageListener The still capture image listener */ protected void prepareStillCaptureAndStartPreview(CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest, Size previewSz, Size stillSz, CaptureCallback resultListener, ImageReader.OnImageAvailableListener imageListener) throws Exception { prepareCaptureAndStartPreview(previewRequest, stillRequest, previewSz, stillSz, ImageFormat.JPEG, resultListener, MAX_READER_IMAGES, imageListener); } /** * Setup still (JPEG) capture configuration and start preview. * * @param previewRequest The capture request to be used for preview * @param stillRequest The capture request to be used for still capture * @param previewSz Preview size * @param stillSz The still capture size * @param resultListener Capture result listener * @param maxNumImages The max number of images set to the image reader * @param imageListener The still capture image listener */ protected void prepareStillCaptureAndStartPreview(CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest, Size previewSz, Size stillSz, CaptureCallback resultListener, int maxNumImages, ImageReader.OnImageAvailableListener imageListener) throws Exception { prepareCaptureAndStartPreview(previewRequest, stillRequest, previewSz, stillSz, ImageFormat.JPEG, resultListener, maxNumImages, imageListener); } /** * Setup raw capture configuration and start preview. * ** The default max number of image is set to image reader. *
* * @param previewRequest The capture request to be used for preview * @param rawRequest The capture request to be used for raw capture * @param previewSz Preview size * @param rawSz The raw capture size * @param resultListener Capture result listener * @param imageListener The raw capture image listener */ protected void prepareRawCaptureAndStartPreview(CaptureRequest.Builder previewRequest, CaptureRequest.Builder rawRequest, Size previewSz, Size rawSz, CaptureCallback resultListener, ImageReader.OnImageAvailableListener imageListener) throws Exception { prepareCaptureAndStartPreview(previewRequest, rawRequest, previewSz, rawSz, ImageFormat.RAW_SENSOR, resultListener, MAX_READER_IMAGES, imageListener); } /** * Wait for expected result key value available in a certain number of results. * ** Check the result immediately if numFramesWait is 0. *
* * @param listener The capture listener to get capture result * @param resultKey The capture result key associated with the result value * @param expectedValue The result value need to be waited for * @param numResultsWait Number of frame to wait before times out * @throws TimeoutRuntimeException If more than numResultsWait results are * seen before the result matching myRequest arrives, or each individual wait * for result times out after {@value #WAIT_FOR_RESULT_TIMEOUT_MS}ms. */ protected static* Check the result immediately if numFramesWait is 0. *
* * @param listener The capture listener to get capture result. * @param resultKey The capture result key associated with the result value. * @param expectedValues The list of result value need to be waited for, * return immediately if the list is empty. * @param numResultsWait Number of frame to wait before times out. * @throws TimeoutRuntimeException If more than numResultsWait results are. * seen before the result matching myRequest arrives, or each individual wait * for result times out after {@value #WAIT_FOR_RESULT_TIMEOUT_MS}ms. */ protected static* The additional capture count is determined by android.sync.maxLatency (or * a fixed {@value #NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY}) captures if maxLatency is unknown). *
* *Returns the number of captures that were submitted (at least 1), which is useful * with {@link #waitForNumResults}.
* * @param request capture request to forward to {@link CameraDevice#capture} * @param listener request listener to forward to {@link CameraDevice#capture} * @param handler handler to forward to {@link CameraDevice#capture} * * @return the number of captures that were submitted * * @throws CameraAccessException if capturing failed */ protected int captureRequestsSynchronized( CaptureRequest request, CaptureCallback listener, Handler handler) throws CameraAccessException { return captureRequestsSynchronized(request, /*count*/1, listener, handler); } /** * Submit a capture {@code count} times, then submit additional captures in order to ensure that * the camera will be synchronized. * ** The additional capture count is determined by android.sync.maxLatency (or * a fixed {@value #NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY}) captures if maxLatency is unknown). *
* *Returns the number of captures that were submitted (at least 1), which is useful * with {@link #waitForNumResults}.
* * @param request capture request to forward to {@link CameraDevice#capture} * @param count the number of times to submit the request (minimally), must be at least 1 * @param listener request listener to forward to {@link CameraDevice#capture} * @param handler handler to forward to {@link CameraDevice#capture} * * @return the number of captures that were submitted * * @throws IllegalArgumentException if {@code count} was not at least 1 * @throws CameraAccessException if capturing failed */ protected int captureRequestsSynchronized( CaptureRequest request, int count, CaptureCallback listener, Handler handler) throws CameraAccessException { if (count < 1) { throw new IllegalArgumentException("count must be positive"); } int maxLatency = mStaticInfo.getSyncMaxLatency(); if (maxLatency == CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN) { maxLatency = NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY; } assertTrue("maxLatency is non-negative", maxLatency >= 0); int numCaptures = maxLatency + count; for (int i = 0; i < numCaptures; ++i) { mSession.capture(request, listener, handler); } return numCaptures; } /** * Wait for numResultWait frames * * @param resultListener The capture listener to get capture result back. * @param numResultsWait Number of frame to wait * * @return the last result, or {@code null} if there was none */ protected static CaptureResult waitForNumResults(SimpleCaptureCallback resultListener, int numResultsWait) { if (numResultsWait < 0 || resultListener == null) { throw new IllegalArgumentException( "Input must be positive number and listener must be non-null"); } CaptureResult result = null; for (int i = 0; i < numResultsWait; i++) { result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); } return result; } /** * Wait for enough results for settings to be applied * * @param resultListener The capture listener to get capture result back. * @param numResultWaitForUnknownLatency Number of frame to wait if camera device latency is * unknown. */ protected void waitForSettingsApplied(SimpleCaptureCallback resultListener, int numResultWaitForUnknownLatency) { int maxLatency = mStaticInfo.getSyncMaxLatency(); if (maxLatency == CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN) { maxLatency = numResultWaitForUnknownLatency; } // Wait for settings to take effect waitForNumResults(resultListener, maxLatency); } /** * Wait for AE to be stabilized before capture: CONVERGED or FLASH_REQUIRED. * *Waits for {@code android.sync.maxLatency} number of results first, to make sure * that the result is synchronized (or {@code numResultWaitForUnknownLatency} if the latency * is unknown.
* *This is a no-op for {@code LEGACY} devices since they don't report * the {@code aeState} result.
* * @param resultListener The capture listener to get capture result back. * @param numResultWaitForUnknownLatency Number of frame to wait if camera device latency is * unknown. */ protected void waitForAeStable(SimpleCaptureCallback resultListener, int numResultWaitForUnknownLatency) { waitForSettingsApplied(resultListener, numResultWaitForUnknownLatency); if (!mStaticInfo.isHardwareLevelAtLeastLimited()) { // No-op for metadata return; } ListWaits for {@code android.sync.maxLatency} number of results first, to make sure * that the result is synchronized (or {@code numResultWaitForUnknownLatency} if the latency * is unknown.
* *This is a no-op for {@code LEGACY} devices since they don't report * the {@code aeState} result.
* * @param resultListener The capture listener to get capture result back. * @param numResultWaitForUnknownLatency Number of frame to wait if camera device latency is * unknown. */ protected void waitForAeLocked(SimpleCaptureCallback resultListener, int numResultWaitForUnknownLatency) { waitForSettingsApplied(resultListener, numResultWaitForUnknownLatency); if (!mStaticInfo.isHardwareLevelAtLeastLimited()) { // No-op for legacy devices return; } List