• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.hardware.camera2.cts.testcases;
18 
19 import static android.hardware.camera2.cts.CameraTestUtils.*;
20 import static com.android.ex.camera2.blocking.BlockingStateCallback.*;
21 
22 import android.content.Context;
23 import android.graphics.ImageFormat;
24 import android.graphics.Rect;
25 import android.hardware.camera2.CameraCaptureSession;
26 import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
27 import android.hardware.camera2.CameraCharacteristics;
28 import android.hardware.camera2.CameraDevice;
29 import android.hardware.camera2.CameraManager;
30 import android.hardware.camera2.CaptureRequest;
31 import android.hardware.camera2.params.MandatoryStreamCombination;
32 import android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation;
33 import android.hardware.camera2.params.OutputConfiguration;
34 import android.hardware.camera2.cts.Camera2ParameterizedTestCase;
35 import android.hardware.camera2.cts.CameraTestUtils;
36 import android.hardware.camera2.cts.helpers.CameraErrorCollector;
37 import android.hardware.camera2.cts.helpers.StaticMetadata;
38 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel;
39 import android.os.Handler;
40 import android.os.HandlerThread;
41 import android.test.AndroidTestCase;
42 import android.util.Log;
43 import android.view.Surface;
44 import android.view.WindowManager;
45 
46 import com.android.ex.camera2.blocking.BlockingSessionCallback;
47 import com.android.ex.camera2.blocking.BlockingStateCallback;
48 
49 import java.io.File;
50 import java.nio.ByteBuffer;
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.HashMap;
54 import java.util.List;
55 import java.util.Set;
56 
57 public class Camera2ConcurrentAndroidTestCase extends Camera2ParameterizedTestCase {
58     private static final String TAG = "Camera2ConcurrentAndroidTestCase";
59     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
60     public static class CameraTestInfo {
61         public String mCameraId;
62         public CameraDevice mCamera;
63         public StaticMetadata mStaticInfo;
64         public MandatoryStreamCombination[] mMandatoryStreamCombinations;
65         public CameraCaptureSession mCameraSession;
66         public BlockingSessionCallback mCameraSessionListener;
67         public BlockingStateCallback mCameraListener;
CameraTestInfo(String cameraId, StaticMetadata staticInfo, MandatoryStreamCombination[] mandatoryStreamCombinations, BlockingStateCallback cameraListener)68         public CameraTestInfo(String cameraId, StaticMetadata staticInfo,
69                 MandatoryStreamCombination[] mandatoryStreamCombinations,
70                 BlockingStateCallback cameraListener) {
71             mCameraId = cameraId;
72             mStaticInfo = staticInfo;
73             mMandatoryStreamCombinations = mandatoryStreamCombinations;
74             mCameraListener = cameraListener;
75         }
76     };
77     protected Set<Set<String>> mConcurrentCameraIdCombinations;
78     protected HashMap<String, CameraTestInfo> mCameraTestInfos;
79     // include both standalone camera IDs and "hidden" physical camera IDs
80     protected String[] mAllCameraIds;
81     protected HashMap<String, StaticMetadata> mAllStaticInfo;
82     protected Handler mHandler;
83     protected HandlerThread mHandlerThread;
84     protected CameraErrorCollector mCollector;
85     protected String mDebugFileNameBase;
86 
87     protected WindowManager mWindowManager;
88 
89     /**
90      * Set up the camera2 test case required environments, including CameraManager,
91      * HandlerThread, Camera IDs, and CameraStateCallback etc.
92      */
93     @Override
setUp()94     public void setUp() throws Exception {
95         super.setUp();
96         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
97         mHandlerThread = new HandlerThread(TAG);
98         mHandlerThread.start();
99         mHandler = new Handler(mHandlerThread.getLooper());
100         mCollector = new CameraErrorCollector();
101 
102         File filesDir = mContext.getPackageManager().isInstantApp()
103                 ? mContext.getFilesDir()
104                 : mContext.getExternalFilesDir(null);
105 
106         mDebugFileNameBase = filesDir.getPath();
107         mAllStaticInfo = new HashMap<String, StaticMetadata>();
108         List<String> hiddenPhysicalIds = new ArrayList<>();
109         for (String cameraId : mCameraIdsUnderTest) {
110             CameraCharacteristics props = mCameraManager.getCameraCharacteristics(cameraId);
111             StaticMetadata staticMetadata = new StaticMetadata(props,
112                     CheckLevel.ASSERT, /*collector*/null);
113             mAllStaticInfo.put(cameraId, staticMetadata);
114             for (String physicalId : props.getPhysicalCameraIds()) {
115                 if (!Arrays.asList(mCameraIdsUnderTest).contains(physicalId) &&
116                         !hiddenPhysicalIds.contains(physicalId)) {
117                     hiddenPhysicalIds.add(physicalId);
118                     props = mCameraManager.getCameraCharacteristics(physicalId);
119                     staticMetadata = new StaticMetadata(
120                             mCameraManager.getCameraCharacteristics(physicalId),
121                             CheckLevel.ASSERT, /*collector*/null);
122                     mAllStaticInfo.put(physicalId, staticMetadata);
123                 }
124             }
125         }
126         mConcurrentCameraIdCombinations =
127                 CameraTestUtils.getConcurrentCameraIds(mCameraManager, mAdoptShellPerm);
128         assertNotNull("Unable to get concurrent camera combinations",
129                 mConcurrentCameraIdCombinations);
130         mCameraTestInfos = new HashMap<String, CameraTestInfo>();
131         for (Set<String> cameraIdComb : mConcurrentCameraIdCombinations) {
132             for (String cameraId : cameraIdComb) {
133                 if (!mCameraTestInfos.containsKey(cameraId)) {
134                     StaticMetadata staticMetadata = mAllStaticInfo.get(cameraId);
135                     assertTrue("camera id" + cameraId + "'s metadata not found in mAllStaticInfo",
136                             staticMetadata != null);
137                     CameraCharacteristics.Key<MandatoryStreamCombination[]> mandatoryStreamsKey =
138                             CameraCharacteristics.SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS;
139                     MandatoryStreamCombination[] combinations =
140                             staticMetadata.getCharacteristics().get(mandatoryStreamsKey);
141                     assertTrue("Concurrent streaming camera id " + cameraId +
142                             "  MUST have mandatory stream combinations",
143                             (combinations != null) && (combinations.length > 0));
144                     mCameraTestInfos.put(cameraId,
145                             new CameraTestInfo(cameraId, staticMetadata, combinations,
146                                   new BlockingStateCallback()));
147                 }
148             }
149         }
150 
151         mAllCameraIds = new String[mCameraIdsUnderTest.length + hiddenPhysicalIds.size()];
152         System.arraycopy(mCameraIdsUnderTest, 0, mAllCameraIds, 0, mCameraIdsUnderTest.length);
153         for (int i = 0; i < hiddenPhysicalIds.size(); i++) {
154             mAllCameraIds[mCameraIdsUnderTest.length + i] = hiddenPhysicalIds.get(i);
155         }
156     }
157 
158     @Override
tearDown()159     public void tearDown() throws Exception {
160         try {
161             if (mHandlerThread != null) {
162                 mHandlerThread.quitSafely();
163             }
164             mHandler = null;
165 
166             if (mCollector != null) {
167                 mCollector.verify();
168             }
169         } catch (Throwable e) {
170             // When new Exception(e) is used, exception info will be printed twice.
171             throw new Exception(e.getMessage());
172         } finally {
173             super.tearDown();
174         }
175     }
176 
177     /**
178      * Start capture with given {@link #CaptureRequest}.
179      *
180      * @param request The {@link #CaptureRequest} to be captured.
181      * @param repeating If the capture is single capture or repeating.
182      * @param listener The {@link #CaptureCallback} camera device used to notify callbacks.
183      * @param handler The handler camera device used to post callbacks.
184      */
startCapture(String cameraId, CaptureRequest request, boolean repeating, CaptureCallback listener, Handler handler)185     protected void startCapture(String cameraId, CaptureRequest request, boolean repeating,
186             CaptureCallback listener, Handler handler) throws Exception {
187         if (VERBOSE) Log.v(TAG, "Starting capture from device");
188         CameraTestInfo info = mCameraTestInfos.get(cameraId);
189         assertTrue("CameraTestInfo not found for camera id " + cameraId, info != null);
190         if (repeating) {
191             info.mCameraSession.setRepeatingRequest(request, listener, handler);
192         } else {
193             info.mCameraSession.capture(request, listener, handler);
194         }
195     }
196 
197     /**
198      * Stop the current active capture.
199      *
200      * @param fast When it is true, {@link CameraDevice#flush} is called, the stop capture
201      * could be faster.
202      */
stopCapture(String cameraId, boolean fast)203     protected void stopCapture(String cameraId, boolean fast) throws Exception {
204         if (VERBOSE) Log.v(TAG, "Stopping capture");
205 
206         CameraTestInfo info = mCameraTestInfos.get(cameraId);
207         assertTrue("CameraTest info not found for camera id " + cameraId, info != null);
208         if (fast) {
209             /**
210              * Flush is useful for canceling long exposure single capture, it also could help
211              * to make the streaming capture stop sooner.
212              */
213             info.mCameraSession.abortCaptures();
214             info.mCameraSessionListener.getStateWaiter().
215                     waitForState(BlockingSessionCallback.SESSION_READY, CAMERA_IDLE_TIMEOUT_MS);
216         } else {
217             info.mCameraSession.close();
218             info.mCameraSessionListener.getStateWaiter().
219                     waitForState(BlockingSessionCallback.SESSION_CLOSED, CAMERA_IDLE_TIMEOUT_MS);
220         }
221     }
222 
223     /**
224      * Open a {@link #CameraDevice camera device} and get the StaticMetadata for a given camera id.
225      * The default mCameraListener is used to wait for states.
226      *
227      * @param cameraId The id of the camera device to be opened.
228      */
openDevice(String cameraId)229     protected void openDevice(String cameraId) throws Exception {
230         CameraTestInfo info = mCameraTestInfos.get(cameraId);
231         assertTrue("CameraTest info not found for camera id " + cameraId, info != null);
232         openDevice(cameraId, info.mCameraListener);
233     }
234 
235     /**
236      * Open a {@link #CameraDevice} and get the StaticMetadata for a given camera id and listener.
237      *
238      * @param cameraId The id of the camera device to be opened.
239      * @param listener The {@link #BlockingStateCallback} used to wait for states.
240      */
openDevice(String cameraId, BlockingStateCallback listener)241     protected void openDevice(String cameraId, BlockingStateCallback listener) throws Exception {
242         CameraTestInfo info = mCameraTestInfos.get(cameraId);
243         assertTrue("CameraTest info not found for camera id " + cameraId, info != null);
244 
245         info.mCamera = CameraTestUtils.openCamera(
246                 mCameraManager, cameraId, listener, mHandler);
247         mCollector.setCameraId(cameraId);
248         if (VERBOSE) {
249             Log.v(TAG, "Camera " + cameraId + " is opened");
250         }
251     }
252 
253     /**
254      * Create a {@link #CameraCaptureSession} using the currently open camera with
255      * OutputConfigurations.
256      *
257      * @param outputSurfaces The set of output surfaces to configure for this session
258      */
createSessionByConfigs(String cameraId, List<OutputConfiguration> outputConfigs)259     protected void createSessionByConfigs(String cameraId,
260             List<OutputConfiguration> outputConfigs) throws Exception {
261         CameraTestInfo info = mCameraTestInfos.get(cameraId);
262         assertTrue("CameraTest info not found for camera id " + cameraId, info != null);
263 
264         info.mCameraSessionListener = new BlockingSessionCallback();
265         info.mCameraSession = CameraTestUtils.configureCameraSessionWithConfig(info.mCamera,
266                 outputConfigs, info.mCameraSessionListener, mHandler);
267     }
268 
269     /**
270      * Close a {@link #CameraDevice camera device} and clear the associated StaticInfo field for a
271      * given camera id. The default mCameraListener is used to wait for states.
272      * <p>
273      * This function must be used along with the {@link #openDevice} for the
274      * same camera id.
275      * </p>
276      *
277      * @param cameraId The id of the {@link #CameraDevice camera device} to be closed.
278      */
closeDevice(String cameraId)279     protected void closeDevice(String cameraId) {
280         CameraTestInfo info = mCameraTestInfos.get(cameraId);
281         assertTrue("CameraTest info not found for camera id " + cameraId, info != null);
282         closeDevice(cameraId, info.mCameraListener);
283     }
284 
285     /**
286      * Close a {@link #CameraDevice camera device} and clear the associated StaticInfo field for a
287      * given camera id and listener.
288      * <p>
289      * This function must be used along with the {@link #openDevice} for the
290      * same camera id.
291      * </p>
292      *
293      * @param cameraId The id of the camera device to be closed.
294      * @param listener The BlockingStateCallback used to wait for states.
295      */
closeDevice(String cameraId, BlockingStateCallback listener)296     protected void closeDevice(String cameraId, BlockingStateCallback listener) {
297         CameraTestInfo info = mCameraTestInfos.get(cameraId);
298         assertTrue("CameraTest info not found for camera id " + cameraId, info != null);
299 
300         if (info.mCamera != null) {
301             info.mCamera.close();
302             listener.waitForState(STATE_CLOSED, CAMERA_CLOSE_TIMEOUT_MS);
303             info.mCamera = null;
304             info.mCameraSession = null;
305             info.mCameraSessionListener = null;
306             if (VERBOSE) {
307                 Log.v(TAG, "Camera " + cameraId + " is closed");
308             }
309         }
310     }
311 
312 }
313