• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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.multiprocess.camera.cts;
18 
19 import static android.hardware.camera2.cts.CameraTestUtils.*;
20 
21 import static org.mockito.Mockito.*;
22 
23 import android.graphics.ImageFormat;
24 import android.hardware.camera2.CameraAccessException;
25 import android.hardware.camera2.CameraCaptureSession;
26 import android.hardware.camera2.CameraCharacteristics;
27 import android.hardware.camera2.CameraDevice;
28 import android.hardware.camera2.CameraExtensionCharacteristics;
29 import android.hardware.camera2.CameraExtensionSession;
30 import android.hardware.camera2.CameraManager;
31 import android.hardware.camera2.CameraOfflineSession;
32 import android.hardware.camera2.CameraSharedCaptureSession;
33 import android.hardware.camera2.CaptureRequest;
34 import android.hardware.camera2.cts.Camera2SurfaceViewCtsActivity;
35 import android.hardware.camera2.cts.CameraTestUtils;
36 import android.hardware.camera2.cts.CameraTestUtils.HandlerExecutor;
37 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback;
38 import android.hardware.camera2.params.ExtensionSessionConfiguration;
39 import android.hardware.camera2.params.InputConfiguration;
40 import android.hardware.camera2.params.OutputConfiguration;
41 import android.hardware.camera2.params.SessionConfiguration;
42 import android.hardware.camera2.params.SharedSessionConfiguration;
43 import android.hardware.camera2.params.SharedSessionConfiguration.SharedOutputConfiguration;
44 import android.media.ImageReader;
45 import android.os.Bundle;
46 import android.os.Handler;
47 import android.os.HandlerThread;
48 import android.os.Message;
49 import android.os.Messenger;
50 import android.os.Process;
51 import android.os.ResultReceiver;
52 import android.util.Log;
53 import android.util.Size;
54 import android.view.Surface;
55 import android.view.SurfaceHolder;
56 
57 import com.android.ex.camera2.blocking.BlockingExtensionSessionCallback;
58 import com.android.ex.camera2.blocking.BlockingSessionCallback;
59 import com.android.ex.camera2.utils.StateWaiter;
60 
61 import java.util.ArrayList;
62 import java.util.List;
63 import java.util.concurrent.Executor;
64 
65 /**
66  * Activity implementing basic access of the shared camera API.
67  *
68  * <p>This will log all errors to {@link
69  * android.hardware.multiprocess.camera.cts.ErrorLoggingService}.
70  */
71 public class SharedCameraActivity extends Camera2SurfaceViewCtsActivity {
72     private static final String TAG = "SharedCameraActivity";
73     private static final int CAPTURE_RESULT_TIMEOUT_MS = 3000;
74     private static final int NUM_MAX_IMAGES = 10;
75     ErrorLoggingService.ErrorServiceConnection mErrorServiceConnection;
76     CameraManager mCameraManager;
77     StateCallback mStateCallback;
78     SessionCallback mSessionCallback;
79     Handler mCameraHandler;
80     HandlerThread mCameraHandlerThread;
81     String mCameraId;
82     Messenger mMessenger;
83     CameraDevice mCameraDevice;
84     CameraSharedCaptureSession mSession;
85     BlockingSessionCallback mSessionMockListener;
86     CaptureRequest.Builder mCaptureRequestBuilder;
87     Surface mPreviewSurface;
88     int mCaptureSequenceId;
89     SimpleCaptureCallback mCaptureListener;
90     SimpleImageReaderListener mImageListener;
91     SharedSessionConfiguration mSharedSessionConfig;
92     ImageReader mReader;
93     Surface mReaderSurface;
94     boolean mIsSurfaceViewPresent = false;
95     boolean mIsImageReaderPresent = false;
96     Size mImageReaderSize;
97     int mImageReaderFormat;
98     Size mSurfaceViewSize;
99     boolean mIsPrimary = true;
100 
101     @Override
onCreate(Bundle savedInstanceState)102     protected void onCreate(Bundle savedInstanceState) {
103         Log.i(TAG, "onCreate called: uid " + Process.myUid() + ".");
104         super.onCreate(savedInstanceState);
105 
106         mMessenger = new Messenger(new IncomingHandler());
107         ResultReceiver resultReceiver = getIntent().getParcelableExtra(
108                 TestConstants.EXTRA_RESULT_RECEIVER);
109         Bundle resultData = new Bundle();
110         resultData.putParcelable(TestConstants.EXTRA_REMOTE_MESSENGER, mMessenger);
111         resultReceiver.send(RESULT_OK, resultData);
112         mCameraHandlerThread = new HandlerThread("CameraHandlerThread");
113         mCameraHandlerThread.start();
114         mCameraHandler = new Handler(mCameraHandlerThread.getLooper());
115         mErrorServiceConnection = new ErrorLoggingService.ErrorServiceConnection(this);
116         mErrorServiceConnection.start();
117     }
118 
119     @Override
onResume()120     protected void onResume() {
121         Log.i(TAG, "onResume called.");
122         super.onResume();
123         mCameraManager = getSystemService(CameraManager.class);
124         if (mCameraManager == null) {
125             mErrorServiceConnection.logAsync(TestConstants.EVENT_CAMERA_ERROR, TAG
126                     + " could not connect camera service");
127             return;
128         }
129     }
130 
131     @Override
onDestroy()132     protected void onDestroy() {
133         Log.i(TAG, "onDestroy called.");
134         super.onDestroy();
135 
136         if (mSession != null) {
137             mSession.close();
138             mSession = null;
139         }
140         mCameraHandlerThread.quitSafely();
141 
142         if (mErrorServiceConnection != null) {
143             mErrorServiceConnection.stop();
144             mErrorServiceConnection = null;
145         }
146     }
147 
148     private class StateCallback extends CameraDevice.StateCallback {
149         String mChosenCameraId;
150 
StateCallback(String camId)151         StateCallback(String camId) {
152             mChosenCameraId = camId;
153         }
154 
155         @Override
onOpened(CameraDevice cameraDevice)156         public void onOpened(CameraDevice cameraDevice) {
157             mCameraDevice = cameraDevice;
158             mErrorServiceConnection.logAsync(TestConstants.EVENT_CAMERA_CONNECT, mChosenCameraId);
159             Log.i(TAG, "Camera " + mChosenCameraId + " is opened");
160         }
161 
162         @Override
onOpenedInSharedMode(CameraDevice cameraDevice, boolean isPrimary)163         public void onOpenedInSharedMode(CameraDevice cameraDevice, boolean isPrimary) {
164             mCameraDevice = cameraDevice;
165             mIsPrimary = isPrimary;
166             if (isPrimary) {
167                 mErrorServiceConnection.logAsync(TestConstants.EVENT_CAMERA_CONNECT_SHARED_PRIMARY,
168                         mChosenCameraId);
169             } else {
170                 mErrorServiceConnection.logAsync(
171                         TestConstants.EVENT_CAMERA_CONNECT_SHARED_SECONDARY, mChosenCameraId);
172             }
173             Log.i(
174                     TAG,
175                     "Camera " + mChosenCameraId + " is opened in shared mode primary=" + isPrimary);
176         }
177 
178         @Override
onClosed(CameraDevice cameraDevice)179         public void onClosed(CameraDevice cameraDevice) {
180             mErrorServiceConnection.logAsync(TestConstants.EVENT_CAMERA_CLOSED, mChosenCameraId);
181             Log.i(TAG, "Camera " + mChosenCameraId + " is closed");
182         }
183 
184         @Override
onDisconnected(CameraDevice cameraDevice)185         public void onDisconnected(CameraDevice cameraDevice) {
186             mErrorServiceConnection.logAsync(
187                     TestConstants.EVENT_CAMERA_DISCONNECTED, mChosenCameraId);
188             Log.i(TAG, "Camera " + mChosenCameraId + " is disconnected");
189         }
190 
191         @Override
onError(CameraDevice cameraDevice, int i)192         public void onError(CameraDevice cameraDevice, int i) {
193             mErrorServiceConnection.logAsync(
194                     TestConstants.EVENT_CAMERA_ERROR,
195                     TAG + " Camera " + mChosenCameraId + " experienced error " + i);
196             Log.e(TAG, "Camera " + mChosenCameraId + " onError called with error " + i);
197         }
198 
199         @Override
onClientSharedAccessPriorityChanged(CameraDevice camera, boolean isPrimary)200         public void onClientSharedAccessPriorityChanged(CameraDevice camera, boolean isPrimary) {
201             mIsPrimary = isPrimary;
202             if (isPrimary) {
203                 mErrorServiceConnection.logAsync(
204                         TestConstants.EVENT_CLIENT_ACCESS_PRIORITIES_CHANGED_TO_PRIMARY,
205                         mChosenCameraId);
206             } else {
207                 mErrorServiceConnection.logAsync(
208                         TestConstants.EVENT_CLIENT_ACCESS_PRIORITIES_CHANGED_TO_SECONDARY,
209                         mChosenCameraId);
210             }
211             Log.i(
212                     TAG,
213                     "Camera "
214                             + mChosenCameraId
215                             + " onClientSharedAccessPriorityChanged primary="
216                             + isPrimary);
217         }
218     }
219 
220     private class SessionCallback extends CameraCaptureSession.StateCallback {
221         String mChosenCameraId;
222 
SessionCallback(String camId)223         SessionCallback(String camId) {
224             mChosenCameraId = camId;
225         }
226 
227         @Override
onClosed(CameraCaptureSession session)228         public void onClosed(CameraCaptureSession session) {
229             mSession = null;
230             mErrorServiceConnection.logAsync(
231                     TestConstants.EVENT_CAMERA_SESSION_CLOSED, mChosenCameraId);
232             Log.i(TAG, "Camera capture session for camera " + mChosenCameraId + " is closed");
233         }
234 
235         @Override
onConfigured(CameraCaptureSession session)236         public void onConfigured(CameraCaptureSession session) {
237             mSession = (CameraSharedCaptureSession) session;
238             mErrorServiceConnection.logAsync(
239                     TestConstants.EVENT_CAMERA_SESSION_CONFIGURED, mChosenCameraId);
240             Log.i(TAG, "Camera capture session for camera " + mChosenCameraId + " is configured");
241         }
242 
243         @Override
onConfigureFailed(CameraCaptureSession session)244         public void onConfigureFailed(CameraCaptureSession session) {
245             mSession = null;
246             mErrorServiceConnection.logAsync(
247                     TestConstants.EVENT_CAMERA_SESSION_CONFIGURE_FAILED, mChosenCameraId);
248             Log.i(TAG, "Camera capture session creation for camera " + mChosenCameraId + " failed");
249         }
250     }
251 
252     private static class ExtensionSessionCallback extends CameraExtensionSession.StateCallback {
253 
254         @Override
onClosed(CameraExtensionSession session)255         public void onClosed(CameraExtensionSession session) {
256             // do nothing
257         }
258 
259         @Override
onConfigured(CameraExtensionSession session)260         public void onConfigured(CameraExtensionSession session) {
261             // do nothing
262         }
263 
264         @Override
onConfigureFailed(CameraExtensionSession session)265         public void onConfigureFailed(CameraExtensionSession session) {
266             // do nothing
267         }
268     }
269 
270     private static class OfflineSessionCallback
271             extends CameraOfflineSession.CameraOfflineSessionCallback {
272 
273         @Override
onReady(CameraOfflineSession session)274         public void onReady(CameraOfflineSession session) {
275             // do nothing
276         }
277 
278         @Override
onSwitchFailed(CameraOfflineSession session)279         public void onSwitchFailed(CameraOfflineSession session) {
280             // do nothing
281         }
282 
283         @Override
onIdle(CameraOfflineSession session)284         public void onIdle(CameraOfflineSession session) {
285             // do nothing
286         }
287 
288         @Override
onError(CameraOfflineSession session, int status)289         public void onError(CameraOfflineSession session, int status) {
290             // do nothing
291         }
292 
293         @Override
onClosed(CameraOfflineSession session)294         public void onClosed(CameraOfflineSession session) {
295             // do nothing
296         }
297     }
298 
updatePreviewSurface(Size sz)299     private void updatePreviewSurface(Size sz) {
300         final SurfaceHolder holder = getSurfaceView().getHolder();
301         mPreviewSurface = holder.getSurface();
302         holder.setFixedSize(sz.getWidth(), sz.getHeight());
303     }
304 
305     class IncomingHandler extends Handler {
306 
createImageReader(Size sz, int format)307         private void createImageReader(Size sz, int format) {
308             mImageListener = new SimpleImageReaderListener(/*asyncMode*/true, NUM_MAX_IMAGES);
309             mReader = makeImageReader(sz, format, NUM_MAX_IMAGES, mImageListener, mCameraHandler);
310             mReaderSurface = mReader.getSurface();
311         }
312 
closeImageReader()313         private void closeImageReader() {
314             CameraTestUtils.closeImageReader(mReader);
315             if (mImageListener != null) {
316                 mImageListener.drain();
317                 mImageListener = null;
318             }
319             mReader = null;
320             mReaderSurface = null;
321         }
322 
checkValidSurfaceIsPresent()323         private void checkValidSurfaceIsPresent() {
324             for (SharedOutputConfiguration sharedStreamInfo :
325                     mSharedSessionConfig.getOutputStreamsInformation()) {
326                 if (sharedStreamInfo.getSurfaceType() == TestConstants.SURFACE_TYPE_SURFACE_VIEW) {
327                     mIsSurfaceViewPresent = true;
328                     mSurfaceViewSize = sharedStreamInfo.getSize();
329                 }
330                 if (sharedStreamInfo.getSurfaceType() == TestConstants.SURFACE_TYPE_IMAGE_READER) {
331                     mIsImageReaderPresent = true;
332                     mImageReaderSize = sharedStreamInfo.getSize();
333                     mImageReaderFormat = sharedStreamInfo.getFormat();
334                 }
335             }
336         }
337 
338         @Override
handleMessage(Message msg)339         public void handleMessage(Message msg) {
340             final Executor executor = new HandlerExecutor(mCameraHandler);
341 
342             switch (msg.what) {
343                 case TestConstants.OP_OPEN_CAMERA:
344                     mCameraId = msg.getData().getString(TestConstants.EXTRA_CAMERA_ID);
345                     try {
346                         if (mStateCallback == null || mStateCallback.mChosenCameraId != mCameraId) {
347                             mStateCallback = new StateCallback(mCameraId);
348                             mCameraManager.openCamera(mCameraId, executor, mStateCallback);
349                         }
350                     } catch (CameraAccessException e) {
351                         mErrorServiceConnection.logAsync(
352                                 TestConstants.EVENT_CAMERA_ERROR,
353                                 TAG + " camera exception during connection: " + e);
354                         Log.e(TAG, "Access exception: " + e);
355                     }
356                     break;
357 
358                 case TestConstants.OP_OPEN_CAMERA_SHARED:
359                     mCameraId = msg.getData().getString(TestConstants.EXTRA_CAMERA_ID);
360                     try {
361                         boolean sharingEnabled =
362                                 mCameraManager.isCameraDeviceSharingSupported(mCameraId);
363                         if (!sharingEnabled) {
364                             mErrorServiceConnection.logAsync(
365                                     TestConstants.EVENT_CAMERA_ERROR,
366                                     TAG + " camera device does not support shared mode");
367                             Log.e(TAG, "camera device does not support shared mode");
368                             return;
369                         }
370                         if (mStateCallback == null || mStateCallback.mChosenCameraId != mCameraId) {
371                             mStateCallback = new StateCallback(mCameraId);
372                             mCameraManager.openSharedCamera(mCameraId, executor, mStateCallback);
373                             CameraCharacteristics props =
374                                     mCameraManager.getCameraCharacteristics(mCameraId);
375                             mSharedSessionConfig = props.get(
376                                     CameraCharacteristics.SHARED_SESSION_CONFIGURATION);
377                             if (mSharedSessionConfig == null) {
378                                 mErrorServiceConnection.logAsync(
379                                         TestConstants.EVENT_CAMERA_ERROR,
380                                         TAG + " shared session config is null");
381                                 Log.e(TAG, "shared session config is null");
382                                 return;
383                             }
384                             checkValidSurfaceIsPresent();
385                             if (mIsSurfaceViewPresent) {
386                                 updatePreviewSurface(mSurfaceViewSize);
387                             }
388                             if (mIsImageReaderPresent) {
389                                 createImageReader(mImageReaderSize, mImageReaderFormat);
390                             }
391                         }
392                     } catch (CameraAccessException e) {
393                         mErrorServiceConnection.logAsync(
394                                 TestConstants.EVENT_CAMERA_ERROR,
395                                 TAG + " camera exception during connection: " + e);
396                         Log.e(TAG, "Access exception: " + e);
397                     }
398                     break;
399 
400                 case TestConstants.OP_CLOSE_CAMERA:
401                     if (mSession != null) {
402                         mSession.close();
403                         mSession = null;
404                         mSessionMockListener = null;
405                         mCaptureListener = null;
406                         mSessionCallback = null;
407                     }
408                     closeImageReader();
409                     if (mCameraDevice != null) {
410                         mCameraDevice.close();
411                         mCameraDevice = null;
412                         mStateCallback = null;
413                     }
414                     break;
415 
416                 case TestConstants.OP_CREATE_SHARED_SESSION:
417                     if (mCameraDevice == null) {
418                         mErrorServiceConnection.logAsync(
419                                 TestConstants.EVENT_CAMERA_ERROR, TAG + "camera device is null");
420                         Log.e(TAG, "camera device is null");
421                         return;
422                     }
423                     List<Integer> sharedStreamArray =
424                             msg.getData()
425                                     .getIntegerArrayList(TestConstants.EXTRA_SHARED_STREAM_ARRAY);
426                     if (sharedStreamArray == null) {
427                         mErrorServiceConnection.logAsync(
428                                 TestConstants.EVENT_CAMERA_ERROR,
429                                 TAG + " shared stream index array is null");
430                         Log.e(TAG, "shared stream index array is null");
431                         return;
432                     }
433                     try {
434                         List<OutputConfiguration> outputs = new ArrayList<>();
435                         if (mIsPrimary) {
436                             mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(
437                                     CameraDevice.TEMPLATE_PREVIEW);
438                         }
439                         for (int i = 0; i < sharedStreamArray.size(); i++) {
440                             Integer surfaceType = sharedStreamArray.get(i);
441                             if (surfaceType == TestConstants.SURFACE_TYPE_SURFACE_VIEW) {
442                                 outputs.add(new OutputConfiguration(mPreviewSurface));
443                             }
444                             if (surfaceType == TestConstants.SURFACE_TYPE_IMAGE_READER) {
445                                 outputs.add(new OutputConfiguration(mReaderSurface));
446                             }
447                         }
448                         if (outputs.isEmpty()) {
449                             mErrorServiceConnection.logAsync(
450                                     TestConstants.EVENT_CAMERA_ERROR,
451                                     TAG + " shared output configuration is empty");
452                             Log.e(TAG, "shared output configuration is empty");
453                             return;
454                         }
455                         if (mSessionCallback == null
456                                 || mSessionCallback.mChosenCameraId != mCameraId) {
457                             mSessionCallback = new SessionCallback(mCameraId);
458                         }
459                         mSessionMockListener = spy(new BlockingSessionCallback(mSessionCallback));
460                         StateWaiter sessionWaiter = mSessionMockListener.getStateWaiter();
461                         SessionConfiguration sessionConfig =
462                                 new SessionConfiguration(
463                                         SessionConfiguration.SESSION_SHARED,
464                                         outputs,
465                                         executor,
466                                         mSessionMockListener);
467                         if (mIsPrimary) {
468                             sessionConfig.setSessionParameters(mCaptureRequestBuilder.build());
469                         }
470                         mCameraDevice.createCaptureSession(sessionConfig);
471                         sessionWaiter.waitForState(
472                                 BlockingSessionCallback.SESSION_CONFIGURED,
473                                 SESSION_CONFIGURE_TIMEOUT_MS);
474                     } catch (Exception e) {
475                         mErrorServiceConnection.logAsync(
476                                 TestConstants.EVENT_CAMERA_ERROR,
477                                 TAG + " exception during creating shared session: " + e);
478                         Log.e(TAG, "exception during creating shared session: " + e);
479                     }
480                     break;
481 
482                 case TestConstants.OP_CREATE_SHARED_SESSION_INVALID_CONFIGS:
483                     if (mCameraDevice == null) {
484                         mErrorServiceConnection.logAsync(
485                                 TestConstants.EVENT_CAMERA_ERROR, TAG + "camera device is null");
486                         Log.e(TAG, "camera device is null");
487                         return;
488                     }
489                     if (!mIsSurfaceViewPresent && !mIsImageReaderPresent) {
490                         mErrorServiceConnection.logAsync(
491                                 TestConstants.EVENT_CAMERA_ERROR,
492                                 TAG + " shared output configuration is empty");
493                         Log.e(TAG, "shared output configuration is empty");
494                         return;
495                     }
496                     if (mSessionCallback == null || mSessionCallback.mChosenCameraId != mCameraId) {
497                         mSessionCallback = new SessionCallback(mCameraId);
498                     }
499                     mSessionMockListener = spy(new BlockingSessionCallback(mSessionCallback));
500 
501                     // tests that using enableSurfaceSharing() returns an error
502                     try {
503                         StateWaiter sessionWaiter = mSessionMockListener.getStateWaiter();
504                         List<OutputConfiguration> outputs = new ArrayList<>();
505                         if (mIsImageReaderPresent) {
506                             OutputConfiguration imageReaderOutputConfig =
507                                     new OutputConfiguration(mReaderSurface);
508                             imageReaderOutputConfig.enableSurfaceSharing();
509                             outputs.add(imageReaderOutputConfig);
510                         } else if (mIsSurfaceViewPresent) {
511                             OutputConfiguration surfaceViewOutputConfig =
512                                     new OutputConfiguration(mPreviewSurface);
513                             surfaceViewOutputConfig.enableSurfaceSharing();
514                             outputs.add(surfaceViewOutputConfig);
515                         }
516 
517                         SessionConfiguration sessionConfig =
518                                 new SessionConfiguration(
519                                         SessionConfiguration.SESSION_SHARED,
520                                         outputs,
521                                         executor,
522                                         mSessionMockListener);
523                         mCameraDevice.createCaptureSession(sessionConfig);
524                         sessionWaiter.waitForState(
525                                 BlockingSessionCallback.SESSION_CONFIGURED,
526                                 SESSION_CONFIGURE_TIMEOUT_MS);
527                         return;
528                     } catch (Exception e) {
529                         mErrorServiceConnection.logAsync(
530                                 TestConstants.EVENT_CAMERA_SESSION_CONFIGURE_FAILED,
531                                 TAG
532                                         + " Expected exception when calling"
533                                         + " enableSurfaceSharing(): "
534                                         + e);
535                     }
536 
537                     // tests that using setInputConfiguration() returns an error
538                     try {
539                         StateWaiter sessionWaiter = mSessionMockListener.getStateWaiter();
540                         List<OutputConfiguration> outputs = new ArrayList<>();
541                         if (mIsImageReaderPresent) {
542                             outputs.add(new OutputConfiguration(mReaderSurface));
543                         } else if (mIsSurfaceViewPresent) {
544                             outputs.add(new OutputConfiguration(mPreviewSurface));
545                         }
546 
547                         SessionConfiguration sessionConfig =
548                                 new SessionConfiguration(
549                                         SessionConfiguration.SESSION_SHARED,
550                                         outputs,
551                                         executor,
552                                         mSessionMockListener);
553                         sessionConfig.setInputConfiguration(
554                                 new InputConfiguration(
555                                         /* width */ 7680,
556                                         /* height */ 4320,
557                                         /* format */ ImageFormat.PRIVATE));
558                         mCameraDevice.createCaptureSession(sessionConfig);
559                         sessionWaiter.waitForState(
560                                 BlockingSessionCallback.SESSION_CONFIGURED,
561                                 SESSION_CONFIGURE_TIMEOUT_MS);
562                         return;
563                     } catch (Exception e) {
564                         mErrorServiceConnection.logAsync(
565                                 TestConstants.EVENT_CAMERA_SESSION_CONFIGURE_FAILED,
566                                 TAG
567                                         + " Expected exception when calling"
568                                         + " setInputConfiguration(): "
569                                         + e);
570                     }
571 
572                     // tests that using an image reader surface with a different size than the one
573                     // provided in the shared session config returns an error
574                     if (mIsImageReaderPresent) {
575                         ImageReader newReader =  null;
576                         try {
577                             StateWaiter sessionWaiter = mSessionMockListener.getStateWaiter();
578                             newReader = ImageReader.newInstance(
579                                     mReader.getWidth() + 1,
580                                     mReader.getHeight() + 1, /* format */
581                                     ImageFormat.YUV_420_888,
582                                     /* maxImages */ 2);
583                             List<OutputConfiguration> outputs = new ArrayList<>();
584                             outputs.add(new OutputConfiguration(newReader.getSurface()));
585                             SessionConfiguration sessionConfig =
586                                     new SessionConfiguration(
587                                             SessionConfiguration.SESSION_SHARED,
588                                             outputs,
589                                             executor,
590                                             mSessionMockListener);
591                             mCameraDevice.createCaptureSession(sessionConfig);
592                             sessionWaiter.waitForState(
593                                     BlockingSessionCallback.SESSION_CONFIGURED,
594                                     SESSION_CONFIGURE_TIMEOUT_MS);
595 
596                             return;
597                         } catch (Exception e) {
598                             mErrorServiceConnection.logAsync(
599                                     TestConstants.EVENT_CAMERA_SESSION_CONFIGURE_FAILED,
600                                     TAG
601                                             + " Expected exception when using different size and"
602                                             + " format than shared session config: "
603                                             + e);
604                         } finally {
605                             CameraTestUtils.closeImageReader(newReader);
606                         }
607                     }
608                     break;
609 
610                 case TestConstants.OP_PERFORM_UNSUPPORTED_COMMANDS:
611                     if (mCameraDevice == null) {
612                         mErrorServiceConnection.logAsync(
613                                 TestConstants.EVENT_CAMERA_ERROR, TAG + "camera device is null");
614                         Log.e(TAG, "camera device is null");
615                         return;
616                     }
617                     if (!mIsSurfaceViewPresent && !mIsImageReaderPresent) {
618                         mErrorServiceConnection.logAsync(
619                                 TestConstants.EVENT_CAMERA_ERROR,
620                                 TAG + " shared output configuration is empty");
621                         Log.e(TAG, "shared output configuration is empty");
622                         return;
623                     }
624 
625                     if (mSessionCallback == null || mSessionCallback.mChosenCameraId != mCameraId) {
626                         mSessionCallback = new SessionCallback(mCameraId);
627                     }
628                     mSessionMockListener = spy(new BlockingSessionCallback(mSessionCallback));
629 
630                     StateWaiter sessionWaiterUnsupportedOps = mSessionMockListener.getStateWaiter();
631                     List<OutputConfiguration> outputsConfigs = new ArrayList<>();
632                     if (mIsImageReaderPresent) {
633                         outputsConfigs.add(new OutputConfiguration(mReaderSurface));
634                     } else if (mIsSurfaceViewPresent) {
635                         outputsConfigs.add(new OutputConfiguration(mPreviewSurface));
636                     }
637                     try {
638                         SessionConfiguration sessionConfig =
639                                 new SessionConfiguration(
640                                         SessionConfiguration.SESSION_HIGH_SPEED,
641                                         outputsConfigs,
642                                         executor,
643                                         mSessionMockListener);
644                         mCameraDevice.createCaptureSession(sessionConfig);
645                         sessionWaiterUnsupportedOps.waitForState(
646                                 BlockingSessionCallback.SESSION_CONFIGURED,
647                                 SESSION_CONFIGURE_TIMEOUT_MS);
648                         return;
649                     } catch (Exception e) {
650                         mErrorServiceConnection.logAsync(
651                                 TestConstants.EVENT_CAMERA_SESSION_CONFIGURE_FAILED,
652                                 TAG
653                                         + " Expected exception from creating SESSION_HIGH_SPEED"
654                                         + " session: "
655                                         + e);
656                     }
657 
658                     try {
659                         SessionConfiguration sessionConfig =
660                                 new SessionConfiguration(
661                                         SessionConfiguration.SESSION_REGULAR,
662                                         outputsConfigs,
663                                         executor,
664                                         mSessionMockListener);
665                         mCameraDevice.createCaptureSession(sessionConfig);
666                         sessionWaiterUnsupportedOps.waitForState(
667                                 BlockingSessionCallback.SESSION_CONFIGURED,
668                                 SESSION_CONFIGURE_TIMEOUT_MS);
669                         return;
670                     } catch (Exception e) {
671                         mErrorServiceConnection.logAsync(
672                                 TestConstants.EVENT_CAMERA_SESSION_CONFIGURE_FAILED,
673                                 TAG
674                                         + " Expected exception from creating SESSION_REGULAR"
675                                         + " session: "
676                                         + e);
677                     }
678 
679                     try {
680                         BlockingExtensionSessionCallback extensionSessionMockListener =
681                                 spy(
682                                         new BlockingExtensionSessionCallback(
683                                                 new ExtensionSessionCallback()));
684                         StateWaiter extensionSessionWaiter =
685                                 extensionSessionMockListener.getStateWaiter();
686                         ExtensionSessionConfiguration extensionSessionConfig =
687                                 new ExtensionSessionConfiguration(
688                                         CameraExtensionCharacteristics.EXTENSION_AUTOMATIC,
689                                         outputsConfigs,
690                                         executor,
691                                         extensionSessionMockListener);
692                         mCameraDevice.createExtensionSession(extensionSessionConfig);
693                         extensionSessionWaiter.waitForState(
694                                 BlockingExtensionSessionCallback.SESSION_CONFIGURED,
695                                 SESSION_CONFIGURE_TIMEOUT_MS);
696                         return;
697                     } catch (Exception e) {
698                         mErrorServiceConnection.logAsync(
699                                 TestConstants.EVENT_CAMERA_SESSION_CONFIGURE_FAILED,
700                                 TAG
701                                         + " Expected exception from running"
702                                         + " createExtensionSession"
703                                         + e);
704                     }
705 
706                     try {
707                         List<Surface> surfaces = new ArrayList<>();
708                         if (mIsImageReaderPresent) {
709                             surfaces.add(mReaderSurface);
710                         } else if (mIsSurfaceViewPresent) {
711                             surfaces.add(mPreviewSurface);
712                         }
713                         InputConfiguration inputConfig =
714                                 new InputConfiguration(
715                                         /* width */ 7680,
716                                         /* height */ 4320,
717                                         /* format */ ImageFormat.YUV_420_888);
718                         mCameraDevice.createReprocessableCaptureSession(
719                                 inputConfig, surfaces, mSessionMockListener, mCameraHandler);
720                         sessionWaiterUnsupportedOps.waitForState(
721                                 BlockingSessionCallback.SESSION_CONFIGURED,
722                                 SESSION_CONFIGURE_TIMEOUT_MS);
723                         return;
724                     } catch (Exception e) {
725                         mErrorServiceConnection.logAsync(
726                                 TestConstants.EVENT_CAMERA_SESSION_CONFIGURE_FAILED,
727                                 TAG
728                                         + " Expected exception from running"
729                                         + " createReprocessableCaptureSession"
730                                         + e);
731                     }
732 
733                     try {
734                         List<Surface> surfaces = new ArrayList<>();
735                         if (mIsImageReaderPresent) {
736                             surfaces.add(mReaderSurface);
737                         } else if (mIsSurfaceViewPresent) {
738                             surfaces.add(mPreviewSurface);
739                         }
740                         mCameraDevice.createConstrainedHighSpeedCaptureSession(
741                                 surfaces, mSessionMockListener, mCameraHandler);
742                         sessionWaiterUnsupportedOps.waitForState(
743                                 BlockingSessionCallback.SESSION_CONFIGURED,
744                                 SESSION_CONFIGURE_TIMEOUT_MS);
745                         return;
746                     } catch (Exception e) {
747                         mErrorServiceConnection.logAsync(
748                                 TestConstants.EVENT_CAMERA_SESSION_CONFIGURE_FAILED,
749                                 TAG
750                                         + " Expected exception from running"
751                                         + " createConstrainedHighSpeedCaptureSession"
752                                         + e);
753                     }
754                     break;
755 
756                 case TestConstants.OP_PERFORM_UNSUPPORTED_CAPTURE_SESSION_COMMANDS:
757                     if (mCameraDevice == null || mSession == null) {
758                         mErrorServiceConnection.logAsync(
759                                 TestConstants.EVENT_CAMERA_ERROR,
760                                 TAG + "No active camera device or session is present");
761                         Log.e(TAG, "No active camera device or session is present");
762                         return;
763                     }
764                     List<CaptureRequest> captureRequests = new ArrayList<>();
765                     captureRequests.add(mCaptureRequestBuilder.build());
766                     mCaptureListener = new SimpleCaptureCallback();
767                     try {
768                         mCaptureSequenceId =
769                                 mSession.captureBurst(
770                                         captureRequests, mCaptureListener, mCameraHandler);
771                         mErrorServiceConnection.logAsync(
772                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_STARTED,
773                                 TAG + " Activity started.");
774                         return;
775                     } catch (Exception e) {
776                         mErrorServiceConnection.logAsync(
777                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_FAILED,
778                                 TAG + " Expected exception from running captureBurst: " + e);
779                     }
780 
781                     try {
782                         mCaptureSequenceId =
783                                 mSession.captureBurstRequests(
784                                         captureRequests, executor, mCaptureListener);
785                         mErrorServiceConnection.logAsync(
786                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_STARTED,
787                                 TAG + " Activity started.");
788                         return;
789                     } catch (Exception e) {
790                         mErrorServiceConnection.logAsync(
791                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_FAILED,
792                                 TAG
793                                         + " Expected exception from running"
794                                         + " captureBurstRequest: "
795                                         + e);
796                     }
797 
798                     try {
799                         mCaptureSequenceId =
800                                 mSession.setRepeatingBurst(
801                                         captureRequests, mCaptureListener, mCameraHandler);
802                         mErrorServiceConnection.logAsync(
803                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_STARTED,
804                                 TAG + " Activity started.");
805                         return;
806                     } catch (Exception e) {
807                         mErrorServiceConnection.logAsync(
808                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_FAILED,
809                                 TAG + " Expected exception from running setRepeatingBurst: " + e);
810                     }
811 
812                     try {
813                         mCaptureSequenceId =
814                                 mSession.setRepeatingBurstRequests(
815                                         captureRequests, executor, mCaptureListener);
816                         mErrorServiceConnection.logAsync(
817                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_STARTED,
818                                 TAG + " Activity started.");
819                         return;
820                     } catch (Exception e) {
821                         mErrorServiceConnection.logAsync(
822                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_FAILED,
823                                 TAG
824                                         + " Expected exception from running"
825                                         + " setRepeatingBurstRequests: "
826                                         + e);
827                     }
828 
829                     if (mSession.supportsOfflineProcessing(mPreviewSurface)) {
830                         mErrorServiceConnection.logAsync(
831                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_STARTED,
832                                 TAG + " Activity started.");
833                         return;
834                     } else {
835                         mErrorServiceConnection.logAsync(
836                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_FAILED,
837                                 TAG + " Expected false from running supportsOfflineProcessing");
838                     }
839 
840                     try {
841                         List<Surface> surfaces = new ArrayList<>();
842                         surfaces.add(mPreviewSurface);
843                         mSession.switchToOffline(surfaces, executor, new OfflineSessionCallback());
844                         mErrorServiceConnection.logAsync(
845                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_STARTED,
846                                 TAG + " Activity started.");
847                         return;
848                     } catch (Exception e) {
849                         mErrorServiceConnection.logAsync(
850                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_FAILED,
851                                 TAG
852                                         + " Expected exception from running"
853                                         + " supportsOfflineProcessing: "
854                                         + e);
855                     }
856 
857                     try {
858                         OutputConfiguration outputConfig = new OutputConfiguration(mPreviewSurface);
859                         mSession.updateOutputConfiguration(outputConfig);
860                         mErrorServiceConnection.logAsync(
861                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_STARTED,
862                                 TAG + " Activity started.");
863                         return;
864                     } catch (Exception e) {
865                         mErrorServiceConnection.logAsync(
866                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_FAILED,
867                                 TAG
868                                         + " Expected exception from running"
869                                         + " updateOutputConfiguration: "
870                                         + e);
871                     }
872 
873                     try {
874                         List<OutputConfiguration> outputConfigs = new ArrayList<>();
875                         outputConfigs.add(new OutputConfiguration(mPreviewSurface));
876                         mSession.finalizeOutputConfigurations(outputConfigs);
877                         mErrorServiceConnection.logAsync(
878                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_STARTED,
879                                 TAG + " Activity started.");
880                         return;
881                     } catch (Exception e) {
882                         mErrorServiceConnection.logAsync(
883                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_FAILED,
884                                 TAG
885                                         + " Expected exception from running"
886                                         + " finalizeOutputConfigurations: "
887                                         + e);
888                     }
889 
890                     if (mSession.isReprocessable()) {
891                         mErrorServiceConnection.logAsync(
892                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_STARTED,
893                                 TAG + " Activity started.");
894                         return;
895                     } else {
896                         mErrorServiceConnection.logAsync(
897                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_FAILED,
898                                 TAG + " Expected false from running isReprocessable");
899                     }
900 
901                     if (mSession.getInputSurface() != null) {
902                         mErrorServiceConnection.logAsync(
903                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_STARTED,
904                                 TAG + " Activity started.");
905                         return;
906                     } else {
907                         mErrorServiceConnection.logAsync(
908                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_FAILED,
909                                 TAG + " Expected null from running getInputSurface");
910                     }
911 
912                     try {
913                         mSession.prepare(mPreviewSurface);
914                         mErrorServiceConnection.logAsync(
915                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_STARTED,
916                                 TAG + " Activity started.");
917                         return;
918                     } catch (Exception e) {
919                         mErrorServiceConnection.logAsync(
920                                 TestConstants.EVENT_CAMERA_UNSUPPORTED_ACTIVITY_FAILED,
921                                 TAG + " Expected exception from running" + " prepare: " + e);
922                     }
923                     break;
924 
925                 case TestConstants.OP_START_PREVIEW:
926                     if (mCameraDevice == null || mSession == null) {
927                         mErrorServiceConnection.logAsync(TestConstants.EVENT_CAMERA_ERROR,
928                                 TAG + " No active camera device or session is present");
929                         Log.e(TAG, "No active camera device or session is present");
930                         return;
931                     }
932                     try {
933                         mCaptureListener = new SimpleCaptureCallback();
934                         List<Integer> previewStreamArray = msg.getData().getIntegerArrayList(
935                                 TestConstants.EXTRA_SHARED_STREAM_ARRAY);
936                         if (previewStreamArray == null) {
937                             mErrorServiceConnection.logAsync(
938                                     TestConstants.EVENT_CAMERA_ERROR,
939                                     TAG + " preview stream index array is null");
940                             Log.e(TAG, "preview stream index array is null");
941                             return;
942                         }
943                         List<Surface> surfaces = new ArrayList<>();
944                         boolean imageReaderUsed = false;
945                         if (mIsPrimary && (mCaptureRequestBuilder == null)) {
946                             mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(
947                                     CameraDevice.TEMPLATE_PREVIEW);
948                         }
949                         for (int i = 0; i < previewStreamArray.size(); i++) {
950                             Integer surfaceType = previewStreamArray.get(i);
951                             if (surfaceType == TestConstants.SURFACE_TYPE_SURFACE_VIEW) {
952                                 if (mIsPrimary) {
953                                     mCaptureRequestBuilder.addTarget(mPreviewSurface);
954                                 } else {
955                                     surfaces.add(mPreviewSurface);
956                                 }
957                             }
958                             if (surfaceType == TestConstants.SURFACE_TYPE_IMAGE_READER) {
959                                 imageReaderUsed = true;
960                                 if (mIsPrimary) {
961                                     mCaptureRequestBuilder.addTarget(mReaderSurface);
962                                 } else {
963                                     surfaces.add(mReaderSurface);
964                                 }
965                             }
966                         }
967                         if (mIsPrimary) {
968                             mCaptureSequenceId =
969                                     mSession.setRepeatingRequest(
970                                             mCaptureRequestBuilder.build(),
971                                             mCaptureListener,
972                                             mCameraHandler);
973                         } else {
974                             mCaptureSequenceId =
975                                     mSession.startStreaming(surfaces, executor, mCaptureListener);
976                         }
977                         mCaptureListener.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS);
978                         if (imageReaderUsed) {
979                             mImageListener.getImage(CAPTURE_RESULT_TIMEOUT_MS).close();
980                         }
981 
982                         mErrorServiceConnection.logAsync(
983                                 TestConstants.EVENT_CAMERA_PREVIEW_STARTED,
984                                 Integer.toString(mCaptureSequenceId));
985                     } catch (Exception e) {
986                         mErrorServiceConnection.logAsync(TestConstants.EVENT_CAMERA_ERROR,
987                                 TAG + " exception during start preview: " + e);
988                         Log.e(TAG, "exception during start preview: " + e);
989                     }
990                     break;
991 
992                 case TestConstants.OP_STOP_PREVIEW:
993                     if (mCameraDevice == null || mSession == null) {
994                         mErrorServiceConnection.logAsync(TestConstants.EVENT_CAMERA_ERROR,
995                                 TAG + " No active camera device or session is present");
996                         Log.e(TAG, "No active camera device or session is present");
997                         return;
998                     }
999                     try {
1000                         if (mIsPrimary) {
1001                             mSession.stopRepeating();
1002                         } else {
1003                             mSession.stopStreaming();
1004                         }
1005                         mCaptureListener.getCaptureSequenceLastFrameNumber(
1006                                 mCaptureSequenceId, CAPTURE_RESULT_TIMEOUT_MS);
1007                         mCaptureListener.drain();
1008                         mImageListener.drain();
1009                         mErrorServiceConnection.logAsync(
1010                                 TestConstants.EVENT_CAMERA_PREVIEW_COMPLETED,
1011                                 Integer.toString(mCaptureSequenceId));
1012                         mCaptureSequenceId = -1;
1013                     } catch (Exception e) {
1014                         mErrorServiceConnection.logAsync(
1015                                 TestConstants.EVENT_CAMERA_ERROR,
1016                                 TAG + " exception during stop preview: " + e);
1017                         Log.e(TAG, "exception during stop preview: " + e);
1018                     }
1019                     break;
1020 
1021                 default:
1022                     super.handleMessage(msg);
1023             }
1024         }
1025     }
1026 }
1027