• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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.impl;
18 
19 import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
20 
21 import android.annotation.NonNull;
22 import android.hardware.ICameraService;
23 import android.hardware.camera2.CameraAccessException;
24 import android.hardware.camera2.CameraCaptureSession;
25 import android.hardware.camera2.CameraCharacteristics;
26 import android.hardware.camera2.CameraDevice;
27 import android.hardware.camera2.CaptureFailure;
28 import android.hardware.camera2.CaptureRequest;
29 import android.hardware.camera2.CaptureResult;
30 import android.hardware.camera2.ICameraDeviceCallbacks;
31 import android.hardware.camera2.ICameraDeviceUser;
32 import android.hardware.camera2.TotalCaptureResult;
33 import android.hardware.camera2.params.InputConfiguration;
34 import android.hardware.camera2.params.OutputConfiguration;
35 import android.hardware.camera2.params.SessionConfiguration;
36 import android.hardware.camera2.params.StreamConfigurationMap;
37 import android.hardware.camera2.utils.SubmitInfo;
38 import android.hardware.camera2.utils.SurfaceUtils;
39 import android.os.Binder;
40 import android.os.Build;
41 import android.os.Handler;
42 import android.os.IBinder;
43 import android.os.Looper;
44 import android.os.RemoteException;
45 import android.os.ServiceSpecificException;
46 import android.util.Log;
47 import android.util.Range;
48 import android.util.Size;
49 import android.util.SparseArray;
50 import android.view.Surface;
51 
52 import com.android.internal.util.Preconditions;
53 
54 import java.util.AbstractMap.SimpleEntry;
55 import java.util.ArrayList;
56 import java.util.Collection;
57 import java.util.HashMap;
58 import java.util.HashSet;
59 import java.util.Iterator;
60 import java.util.LinkedList;
61 import java.util.List;
62 import java.util.Set;
63 import java.util.TreeMap;
64 import java.util.concurrent.atomic.AtomicBoolean;
65 import java.util.concurrent.Executor;
66 
67 
68 /**
69  * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
70  */
71 public class CameraDeviceImpl extends CameraDevice
72         implements IBinder.DeathRecipient {
73     private final String TAG;
74     private final boolean DEBUG = false;
75 
76     private static final int REQUEST_ID_NONE = -1;
77 
78     // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
79     private ICameraDeviceUserWrapper mRemoteDevice;
80 
81     // Lock to synchronize cross-thread access to device public interface
82     final Object mInterfaceLock = new Object(); // access from this class and Session only!
83     private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
84 
85     private final StateCallback mDeviceCallback;
86     private volatile StateCallbackKK mSessionStateCallback;
87     private final Executor mDeviceExecutor;
88 
89     private final AtomicBoolean mClosing = new AtomicBoolean();
90     private boolean mInError = false;
91     private boolean mIdle = true;
92 
93     /** map request IDs to callback/request data */
94     private final SparseArray<CaptureCallbackHolder> mCaptureCallbackMap =
95             new SparseArray<CaptureCallbackHolder>();
96 
97     private int mRepeatingRequestId = REQUEST_ID_NONE;
98     // Latest repeating request list's types
99     private int[] mRepeatingRequestTypes;
100     // Map stream IDs to input/output configurations
101     private SimpleEntry<Integer, InputConfiguration> mConfiguredInput =
102             new SimpleEntry<>(REQUEST_ID_NONE, null);
103     private final SparseArray<OutputConfiguration> mConfiguredOutputs =
104             new SparseArray<>();
105 
106     private final String mCameraId;
107     private final CameraCharacteristics mCharacteristics;
108     private final int mTotalPartialCount;
109 
110     private static final long NANO_PER_SECOND = 1000000000; //ns
111 
112     /**
113      * A list tracking request and its expected last regular/reprocess/zslStill frame
114      * number. Updated when calling ICameraDeviceUser methods.
115      */
116     private final List<RequestLastFrameNumbersHolder> mRequestLastFrameNumbersList =
117             new ArrayList<>();
118 
119     /**
120      * An object tracking received frame numbers.
121      * Updated when receiving callbacks from ICameraDeviceCallbacks.
122      */
123     private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
124 
125     private CameraCaptureSessionCore mCurrentSession;
126     private int mNextSessionId = 0;
127 
128     private final int mAppTargetSdkVersion;
129 
130     // Runnables for all state transitions, except error, which needs the
131     // error code argument
132 
133     private final Runnable mCallOnOpened = new Runnable() {
134         @Override
135         public void run() {
136             StateCallbackKK sessionCallback = null;
137             synchronized(mInterfaceLock) {
138                 if (mRemoteDevice == null) return; // Camera already closed
139 
140                 sessionCallback = mSessionStateCallback;
141             }
142             if (sessionCallback != null) {
143                 sessionCallback.onOpened(CameraDeviceImpl.this);
144             }
145             mDeviceCallback.onOpened(CameraDeviceImpl.this);
146         }
147     };
148 
149     private final Runnable mCallOnUnconfigured = new Runnable() {
150         @Override
151         public void run() {
152             StateCallbackKK sessionCallback = null;
153             synchronized(mInterfaceLock) {
154                 if (mRemoteDevice == null) return; // Camera already closed
155 
156                 sessionCallback = mSessionStateCallback;
157             }
158             if (sessionCallback != null) {
159                 sessionCallback.onUnconfigured(CameraDeviceImpl.this);
160             }
161         }
162     };
163 
164     private final Runnable mCallOnActive = new Runnable() {
165         @Override
166         public void run() {
167             StateCallbackKK sessionCallback = null;
168             synchronized(mInterfaceLock) {
169                 if (mRemoteDevice == null) return; // Camera already closed
170 
171                 sessionCallback = mSessionStateCallback;
172             }
173             if (sessionCallback != null) {
174                 sessionCallback.onActive(CameraDeviceImpl.this);
175             }
176         }
177     };
178 
179     private final Runnable mCallOnBusy = new Runnable() {
180         @Override
181         public void run() {
182             StateCallbackKK sessionCallback = null;
183             synchronized(mInterfaceLock) {
184                 if (mRemoteDevice == null) return; // Camera already closed
185 
186                 sessionCallback = mSessionStateCallback;
187             }
188             if (sessionCallback != null) {
189                 sessionCallback.onBusy(CameraDeviceImpl.this);
190             }
191         }
192     };
193 
194     private final Runnable mCallOnClosed = new Runnable() {
195         private boolean mClosedOnce = false;
196 
197         @Override
198         public void run() {
199             if (mClosedOnce) {
200                 throw new AssertionError("Don't post #onClosed more than once");
201             }
202             StateCallbackKK sessionCallback = null;
203             synchronized(mInterfaceLock) {
204                 sessionCallback = mSessionStateCallback;
205             }
206             if (sessionCallback != null) {
207                 sessionCallback.onClosed(CameraDeviceImpl.this);
208             }
209             mDeviceCallback.onClosed(CameraDeviceImpl.this);
210             mClosedOnce = true;
211         }
212     };
213 
214     private final Runnable mCallOnIdle = new Runnable() {
215         @Override
216         public void run() {
217             StateCallbackKK sessionCallback = null;
218             synchronized(mInterfaceLock) {
219                 if (mRemoteDevice == null) return; // Camera already closed
220 
221                 sessionCallback = mSessionStateCallback;
222             }
223             if (sessionCallback != null) {
224                 sessionCallback.onIdle(CameraDeviceImpl.this);
225             }
226         }
227     };
228 
229     private final Runnable mCallOnDisconnected = new Runnable() {
230         @Override
231         public void run() {
232             StateCallbackKK sessionCallback = null;
233             synchronized(mInterfaceLock) {
234                 if (mRemoteDevice == null) return; // Camera already closed
235 
236                 sessionCallback = mSessionStateCallback;
237             }
238             if (sessionCallback != null) {
239                 sessionCallback.onDisconnected(CameraDeviceImpl.this);
240             }
241             mDeviceCallback.onDisconnected(CameraDeviceImpl.this);
242         }
243     };
244 
CameraDeviceImpl(String cameraId, StateCallback callback, Executor executor, CameraCharacteristics characteristics, int appTargetSdkVersion)245     public CameraDeviceImpl(String cameraId, StateCallback callback, Executor executor,
246                         CameraCharacteristics characteristics, int appTargetSdkVersion) {
247         if (cameraId == null || callback == null || executor == null || characteristics == null) {
248             throw new IllegalArgumentException("Null argument given");
249         }
250         mCameraId = cameraId;
251         mDeviceCallback = callback;
252         mDeviceExecutor = executor;
253         mCharacteristics = characteristics;
254         mAppTargetSdkVersion = appTargetSdkVersion;
255 
256         final int MAX_TAG_LEN = 23;
257         String tag = String.format("CameraDevice-JV-%s", mCameraId);
258         if (tag.length() > MAX_TAG_LEN) {
259             tag = tag.substring(0, MAX_TAG_LEN);
260         }
261         TAG = tag;
262 
263         Integer partialCount =
264                 mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
265         if (partialCount == null) {
266             // 1 means partial result is not supported.
267             mTotalPartialCount = 1;
268         } else {
269             mTotalPartialCount = partialCount;
270         }
271     }
272 
getCallbacks()273     public CameraDeviceCallbacks getCallbacks() {
274         return mCallbacks;
275     }
276 
277     /**
278      * Set remote device, which triggers initial onOpened/onUnconfigured callbacks
279      *
280      * <p>This function may post onDisconnected and throw CAMERA_DISCONNECTED if remoteDevice dies
281      * during setup.</p>
282      *
283      */
setRemoteDevice(ICameraDeviceUser remoteDevice)284     public void setRemoteDevice(ICameraDeviceUser remoteDevice) throws CameraAccessException {
285         synchronized(mInterfaceLock) {
286             // TODO: Move from decorator to direct binder-mediated exceptions
287             // If setRemoteFailure already called, do nothing
288             if (mInError) return;
289 
290             mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);
291 
292             IBinder remoteDeviceBinder = remoteDevice.asBinder();
293             // For legacy camera device, remoteDevice is in the same process, and
294             // asBinder returns NULL.
295             if (remoteDeviceBinder != null) {
296                 try {
297                     remoteDeviceBinder.linkToDeath(this, /*flag*/ 0);
298                 } catch (RemoteException e) {
299                     CameraDeviceImpl.this.mDeviceExecutor.execute(mCallOnDisconnected);
300 
301                     throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
302                             "The camera device has encountered a serious error");
303                 }
304             }
305 
306             mDeviceExecutor.execute(mCallOnOpened);
307             mDeviceExecutor.execute(mCallOnUnconfigured);
308         }
309     }
310 
311     /**
312      * Call to indicate failed connection to a remote camera device.
313      *
314      * <p>This places the camera device in the error state and informs the callback.
315      * Use in place of setRemoteDevice() when startup fails.</p>
316      */
setRemoteFailure(final ServiceSpecificException failure)317     public void setRemoteFailure(final ServiceSpecificException failure) {
318         int failureCode = StateCallback.ERROR_CAMERA_DEVICE;
319         boolean failureIsError = true;
320 
321         switch (failure.errorCode) {
322             case ICameraService.ERROR_CAMERA_IN_USE:
323                 failureCode = StateCallback.ERROR_CAMERA_IN_USE;
324                 break;
325             case ICameraService.ERROR_MAX_CAMERAS_IN_USE:
326                 failureCode = StateCallback.ERROR_MAX_CAMERAS_IN_USE;
327                 break;
328             case ICameraService.ERROR_DISABLED:
329                 failureCode = StateCallback.ERROR_CAMERA_DISABLED;
330                 break;
331             case ICameraService.ERROR_DISCONNECTED:
332                 failureIsError = false;
333                 break;
334             case ICameraService.ERROR_INVALID_OPERATION:
335                 failureCode = StateCallback.ERROR_CAMERA_DEVICE;
336                 break;
337             default:
338                 Log.e(TAG, "Unexpected failure in opening camera device: " + failure.errorCode +
339                         failure.getMessage());
340                 break;
341         }
342         final int code = failureCode;
343         final boolean isError = failureIsError;
344         synchronized(mInterfaceLock) {
345             mInError = true;
346             mDeviceExecutor.execute(new Runnable() {
347                 @Override
348                 public void run() {
349                     if (isError) {
350                         mDeviceCallback.onError(CameraDeviceImpl.this, code);
351                     } else {
352                         mDeviceCallback.onDisconnected(CameraDeviceImpl.this);
353                     }
354                 }
355             });
356         }
357     }
358 
359     @Override
getId()360     public String getId() {
361         return mCameraId;
362     }
363 
configureOutputs(List<Surface> outputs)364     public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
365         // Leave this here for backwards compatibility with older code using this directly
366         ArrayList<OutputConfiguration> outputConfigs = new ArrayList<>(outputs.size());
367         for (Surface s : outputs) {
368             outputConfigs.add(new OutputConfiguration(s));
369         }
370         configureStreamsChecked(/*inputConfig*/null, outputConfigs,
371                 /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
372 
373     }
374 
375     /**
376      * Attempt to configure the input and outputs; the device goes to idle and then configures the
377      * new input and outputs if possible.
378      *
379      * <p>The configuration may gracefully fail, if input configuration is not supported,
380      * if there are too many outputs, if the formats are not supported, or if the sizes for that
381      * format is not supported. In this case this function will return {@code false} and the
382      * unconfigured callback will be fired.</p>
383      *
384      * <p>If the configuration succeeds (with 1 or more outputs with or without an input),
385      * then the idle callback is fired. Unconfiguring the device always fires the idle callback.</p>
386      *
387      * @param inputConfig input configuration or {@code null} for no input
388      * @param outputs a list of one or more surfaces, or {@code null} to unconfigure
389      * @param operatingMode If the stream configuration is for a normal session,
390      *     a constrained high speed session, or something else.
391      * @param sessionParams Session parameters.
392      * @return whether or not the configuration was successful
393      *
394      * @throws CameraAccessException if there were any unexpected problems during configuration
395      */
configureStreamsChecked(InputConfiguration inputConfig, List<OutputConfiguration> outputs, int operatingMode, CaptureRequest sessionParams)396     public boolean configureStreamsChecked(InputConfiguration inputConfig,
397             List<OutputConfiguration> outputs, int operatingMode, CaptureRequest sessionParams)
398                     throws CameraAccessException {
399         // Treat a null input the same an empty list
400         if (outputs == null) {
401             outputs = new ArrayList<OutputConfiguration>();
402         }
403         if (outputs.size() == 0 && inputConfig != null) {
404             throw new IllegalArgumentException("cannot configure an input stream without " +
405                     "any output streams");
406         }
407 
408         checkInputConfiguration(inputConfig);
409 
410         boolean success = false;
411 
412         synchronized(mInterfaceLock) {
413             checkIfCameraClosedOrInError();
414             // Streams to create
415             HashSet<OutputConfiguration> addSet = new HashSet<OutputConfiguration>(outputs);
416             // Streams to delete
417             List<Integer> deleteList = new ArrayList<Integer>();
418 
419             // Determine which streams need to be created, which to be deleted
420             for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
421                 int streamId = mConfiguredOutputs.keyAt(i);
422                 OutputConfiguration outConfig = mConfiguredOutputs.valueAt(i);
423 
424                 if (!outputs.contains(outConfig) || outConfig.isDeferredConfiguration()) {
425                     // Always delete the deferred output configuration when the session
426                     // is created, as the deferred output configuration doesn't have unique surface
427                     // related identifies.
428                     deleteList.add(streamId);
429                 } else {
430                     addSet.remove(outConfig);  // Don't create a stream previously created
431                 }
432             }
433 
434             mDeviceExecutor.execute(mCallOnBusy);
435             stopRepeating();
436 
437             try {
438                 waitUntilIdle();
439 
440                 mRemoteDevice.beginConfigure();
441 
442                 // reconfigure the input stream if the input configuration is different.
443                 InputConfiguration currentInputConfig = mConfiguredInput.getValue();
444                 if (inputConfig != currentInputConfig &&
445                         (inputConfig == null || !inputConfig.equals(currentInputConfig))) {
446                     if (currentInputConfig != null) {
447                         mRemoteDevice.deleteStream(mConfiguredInput.getKey());
448                         mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(
449                                 REQUEST_ID_NONE, null);
450                     }
451                     if (inputConfig != null) {
452                         int streamId = mRemoteDevice.createInputStream(inputConfig.getWidth(),
453                                 inputConfig.getHeight(), inputConfig.getFormat());
454                         mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(
455                                 streamId, inputConfig);
456                     }
457                 }
458 
459                 // Delete all streams first (to free up HW resources)
460                 for (Integer streamId : deleteList) {
461                     mRemoteDevice.deleteStream(streamId);
462                     mConfiguredOutputs.delete(streamId);
463                 }
464 
465                 // Add all new streams
466                 for (OutputConfiguration outConfig : outputs) {
467                     if (addSet.contains(outConfig)) {
468                         int streamId = mRemoteDevice.createStream(outConfig);
469                         mConfiguredOutputs.put(streamId, outConfig);
470                     }
471                 }
472 
473                 if (sessionParams != null) {
474                     mRemoteDevice.endConfigure(operatingMode, sessionParams.getNativeCopy());
475                 } else {
476                     mRemoteDevice.endConfigure(operatingMode, null);
477                 }
478 
479                 success = true;
480             } catch (IllegalArgumentException e) {
481                 // OK. camera service can reject stream config if it's not supported by HAL
482                 // This is only the result of a programmer misusing the camera2 api.
483                 Log.w(TAG, "Stream configuration failed due to: " + e.getMessage());
484                 return false;
485             } catch (CameraAccessException e) {
486                 if (e.getReason() == CameraAccessException.CAMERA_IN_USE) {
487                     throw new IllegalStateException("The camera is currently busy." +
488                             " You must wait until the previous operation completes.", e);
489                 }
490                 throw e;
491             } finally {
492                 if (success && outputs.size() > 0) {
493                     mDeviceExecutor.execute(mCallOnIdle);
494                 } else {
495                     // Always return to the 'unconfigured' state if we didn't hit a fatal error
496                     mDeviceExecutor.execute(mCallOnUnconfigured);
497                 }
498             }
499         }
500 
501         return success;
502     }
503 
504     @Override
createCaptureSession(List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler)505     public void createCaptureSession(List<Surface> outputs,
506             CameraCaptureSession.StateCallback callback, Handler handler)
507             throws CameraAccessException {
508         List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
509         for (Surface surface : outputs) {
510             outConfigurations.add(new OutputConfiguration(surface));
511         }
512         createCaptureSessionInternal(null, outConfigurations, callback,
513                 checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
514                 /*sessionParams*/ null);
515     }
516 
517     @Override
createCaptureSessionByOutputConfigurations( List<OutputConfiguration> outputConfigurations, CameraCaptureSession.StateCallback callback, Handler handler)518     public void createCaptureSessionByOutputConfigurations(
519             List<OutputConfiguration> outputConfigurations,
520             CameraCaptureSession.StateCallback callback, Handler handler)
521             throws CameraAccessException {
522         if (DEBUG) {
523             Log.d(TAG, "createCaptureSessionByOutputConfigurations");
524         }
525 
526         // OutputConfiguration objects are immutable, but need to have our own array
527         List<OutputConfiguration> currentOutputs = new ArrayList<>(outputConfigurations);
528 
529         createCaptureSessionInternal(null, currentOutputs, callback, checkAndWrapHandler(handler),
530                 /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/null);
531     }
532 
533     @Override
createReprocessableCaptureSession(InputConfiguration inputConfig, List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler)534     public void createReprocessableCaptureSession(InputConfiguration inputConfig,
535             List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler)
536             throws CameraAccessException {
537         if (DEBUG) {
538             Log.d(TAG, "createReprocessableCaptureSession");
539         }
540 
541         if (inputConfig == null) {
542             throw new IllegalArgumentException("inputConfig cannot be null when creating a " +
543                     "reprocessable capture session");
544         }
545         List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
546         for (Surface surface : outputs) {
547             outConfigurations.add(new OutputConfiguration(surface));
548         }
549         createCaptureSessionInternal(inputConfig, outConfigurations, callback,
550                 checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
551                 /*sessionParams*/ null);
552     }
553 
554     @Override
createReprocessableCaptureSessionByConfigurations(InputConfiguration inputConfig, List<OutputConfiguration> outputs, android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler)555     public void createReprocessableCaptureSessionByConfigurations(InputConfiguration inputConfig,
556             List<OutputConfiguration> outputs,
557             android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler)
558                     throws CameraAccessException {
559         if (DEBUG) {
560             Log.d(TAG, "createReprocessableCaptureSessionWithConfigurations");
561         }
562 
563         if (inputConfig == null) {
564             throw new IllegalArgumentException("inputConfig cannot be null when creating a " +
565                     "reprocessable capture session");
566         }
567 
568         if (outputs == null) {
569             throw new IllegalArgumentException("Output configurations cannot be null when " +
570                     "creating a reprocessable capture session");
571         }
572 
573         // OutputConfiguration objects aren't immutable, make a copy before using.
574         List<OutputConfiguration> currentOutputs = new ArrayList<OutputConfiguration>();
575         for (OutputConfiguration output : outputs) {
576             currentOutputs.add(new OutputConfiguration(output));
577         }
578         createCaptureSessionInternal(inputConfig, currentOutputs,
579                 callback, checkAndWrapHandler(handler),
580                 /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
581     }
582 
583     @Override
createConstrainedHighSpeedCaptureSession(List<Surface> outputs, android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler)584     public void createConstrainedHighSpeedCaptureSession(List<Surface> outputs,
585             android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler)
586             throws CameraAccessException {
587         if (outputs == null || outputs.size() == 0 || outputs.size() > 2) {
588             throw new IllegalArgumentException(
589                     "Output surface list must not be null and the size must be no more than 2");
590         }
591         List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
592         for (Surface surface : outputs) {
593             outConfigurations.add(new OutputConfiguration(surface));
594         }
595         createCaptureSessionInternal(null, outConfigurations, callback,
596                 checkAndWrapHandler(handler),
597                 /*operatingMode*/ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE,
598                 /*sessionParams*/ null);
599     }
600 
601     @Override
createCustomCaptureSession(InputConfiguration inputConfig, List<OutputConfiguration> outputs, int operatingMode, android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler)602     public void createCustomCaptureSession(InputConfiguration inputConfig,
603             List<OutputConfiguration> outputs,
604             int operatingMode,
605             android.hardware.camera2.CameraCaptureSession.StateCallback callback,
606             Handler handler) throws CameraAccessException {
607         List<OutputConfiguration> currentOutputs = new ArrayList<OutputConfiguration>();
608         for (OutputConfiguration output : outputs) {
609             currentOutputs.add(new OutputConfiguration(output));
610         }
611         createCaptureSessionInternal(inputConfig, currentOutputs, callback,
612                 checkAndWrapHandler(handler), operatingMode, /*sessionParams*/ null);
613     }
614 
615     @Override
createCaptureSession(SessionConfiguration config)616     public void createCaptureSession(SessionConfiguration config)
617             throws CameraAccessException {
618         if (config == null) {
619             throw new IllegalArgumentException("Invalid session configuration");
620         }
621 
622         List<OutputConfiguration> outputConfigs = config.getOutputConfigurations();
623         if (outputConfigs == null) {
624             throw new IllegalArgumentException("Invalid output configurations");
625         }
626         if (config.getExecutor() == null) {
627             throw new IllegalArgumentException("Invalid executor");
628         }
629         createCaptureSessionInternal(config.getInputConfiguration(), outputConfigs,
630                 config.getStateCallback(), config.getExecutor(), config.getSessionType(),
631                 config.getSessionParameters());
632     }
633 
createCaptureSessionInternal(InputConfiguration inputConfig, List<OutputConfiguration> outputConfigurations, CameraCaptureSession.StateCallback callback, Executor executor, int operatingMode, CaptureRequest sessionParams)634     private void createCaptureSessionInternal(InputConfiguration inputConfig,
635             List<OutputConfiguration> outputConfigurations,
636             CameraCaptureSession.StateCallback callback, Executor executor,
637             int operatingMode, CaptureRequest sessionParams) throws CameraAccessException {
638         synchronized(mInterfaceLock) {
639             if (DEBUG) {
640                 Log.d(TAG, "createCaptureSessionInternal");
641             }
642 
643             checkIfCameraClosedOrInError();
644 
645             boolean isConstrainedHighSpeed =
646                     (operatingMode == ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE);
647             if (isConstrainedHighSpeed && inputConfig != null) {
648                 throw new IllegalArgumentException("Constrained high speed session doesn't support"
649                         + " input configuration yet.");
650             }
651 
652             // Notify current session that it's going away, before starting camera operations
653             // After this call completes, the session is not allowed to call into CameraDeviceImpl
654             if (mCurrentSession != null) {
655                 mCurrentSession.replaceSessionClose();
656             }
657 
658             // TODO: dont block for this
659             boolean configureSuccess = true;
660             CameraAccessException pendingException = null;
661             Surface input = null;
662             try {
663                 // configure streams and then block until IDLE
664                 configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations,
665                         operatingMode, sessionParams);
666                 if (configureSuccess == true && inputConfig != null) {
667                     input = mRemoteDevice.getInputSurface();
668                 }
669             } catch (CameraAccessException e) {
670                 configureSuccess = false;
671                 pendingException = e;
672                 input = null;
673                 if (DEBUG) {
674                     Log.v(TAG, "createCaptureSession - failed with exception ", e);
675                 }
676             }
677 
678             // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
679             CameraCaptureSessionCore newSession = null;
680             if (isConstrainedHighSpeed) {
681                 ArrayList<Surface> surfaces = new ArrayList<>(outputConfigurations.size());
682                 for (OutputConfiguration outConfig : outputConfigurations) {
683                     surfaces.add(outConfig.getSurface());
684                 }
685                 StreamConfigurationMap config =
686                     getCharacteristics().get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
687                 SurfaceUtils.checkConstrainedHighSpeedSurfaces(surfaces, /*fpsRange*/null, config);
688 
689                 newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
690                         callback, executor, this, mDeviceExecutor, configureSuccess,
691                         mCharacteristics);
692             } else {
693                 newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
694                         callback, executor, this, mDeviceExecutor, configureSuccess);
695             }
696 
697             // TODO: wait until current session closes, then create the new session
698             mCurrentSession = newSession;
699 
700             if (pendingException != null) {
701                 throw pendingException;
702             }
703 
704             mSessionStateCallback = mCurrentSession.getDeviceStateCallback();
705         }
706     }
707 
708     @Override
isSessionConfigurationSupported( @onNull SessionConfiguration sessionConfig)709     public boolean isSessionConfigurationSupported(
710             @NonNull SessionConfiguration sessionConfig) throws CameraAccessException,
711             UnsupportedOperationException, IllegalArgumentException {
712         synchronized(mInterfaceLock) {
713             checkIfCameraClosedOrInError();
714 
715             return mRemoteDevice.isSessionConfigurationSupported(sessionConfig);
716         }
717     }
718 
719     /**
720      * For use by backwards-compatibility code only.
721      */
setSessionListener(StateCallbackKK sessionCallback)722     public void setSessionListener(StateCallbackKK sessionCallback) {
723         synchronized(mInterfaceLock) {
724             mSessionStateCallback = sessionCallback;
725         }
726     }
727 
overrideEnableZsl(CameraMetadataNative request, boolean newValue)728     private void overrideEnableZsl(CameraMetadataNative request, boolean newValue) {
729         Boolean enableZsl = request.get(CaptureRequest.CONTROL_ENABLE_ZSL);
730         if (enableZsl == null) {
731             // If enableZsl is not available, don't override.
732             return;
733         }
734 
735         request.set(CaptureRequest.CONTROL_ENABLE_ZSL, newValue);
736     }
737 
738     @Override
createCaptureRequest(int templateType, Set<String> physicalCameraIdSet)739     public CaptureRequest.Builder createCaptureRequest(int templateType,
740             Set<String> physicalCameraIdSet)
741             throws CameraAccessException {
742         synchronized(mInterfaceLock) {
743             checkIfCameraClosedOrInError();
744 
745             for (String physicalId : physicalCameraIdSet) {
746                 if (physicalId == getId()) {
747                     throw new IllegalStateException("Physical id matches the logical id!");
748                 }
749             }
750 
751             CameraMetadataNative templatedRequest = null;
752 
753             templatedRequest = mRemoteDevice.createDefaultRequest(templateType);
754 
755             // If app target SDK is older than O, or it's not a still capture template, enableZsl
756             // must be false in the default request.
757             if (mAppTargetSdkVersion < Build.VERSION_CODES.O ||
758                     templateType != TEMPLATE_STILL_CAPTURE) {
759                 overrideEnableZsl(templatedRequest, false);
760             }
761 
762             CaptureRequest.Builder builder = new CaptureRequest.Builder(
763                     templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE,
764                     getId(), physicalCameraIdSet);
765 
766             return builder;
767         }
768     }
769 
770     @Override
createCaptureRequest(int templateType)771     public CaptureRequest.Builder createCaptureRequest(int templateType)
772             throws CameraAccessException {
773         synchronized(mInterfaceLock) {
774             checkIfCameraClosedOrInError();
775 
776             CameraMetadataNative templatedRequest = null;
777 
778             templatedRequest = mRemoteDevice.createDefaultRequest(templateType);
779 
780             // If app target SDK is older than O, or it's not a still capture template, enableZsl
781             // must be false in the default request.
782             if (mAppTargetSdkVersion < Build.VERSION_CODES.O ||
783                     templateType != TEMPLATE_STILL_CAPTURE) {
784                 overrideEnableZsl(templatedRequest, false);
785             }
786 
787             CaptureRequest.Builder builder = new CaptureRequest.Builder(
788                     templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE,
789                     getId(), /*physicalCameraIdSet*/ null);
790 
791             return builder;
792         }
793     }
794 
795     @Override
createReprocessCaptureRequest(TotalCaptureResult inputResult)796     public CaptureRequest.Builder createReprocessCaptureRequest(TotalCaptureResult inputResult)
797             throws CameraAccessException {
798         synchronized(mInterfaceLock) {
799             checkIfCameraClosedOrInError();
800 
801             CameraMetadataNative resultMetadata = new
802                     CameraMetadataNative(inputResult.getNativeCopy());
803 
804             return new CaptureRequest.Builder(resultMetadata, /*reprocess*/true,
805                     inputResult.getSessionId(), getId(), /*physicalCameraIdSet*/ null);
806         }
807     }
808 
prepare(Surface surface)809     public void prepare(Surface surface) throws CameraAccessException {
810         if (surface == null) throw new IllegalArgumentException("Surface is null");
811 
812         synchronized(mInterfaceLock) {
813             int streamId = -1;
814             for (int i = 0; i < mConfiguredOutputs.size(); i++) {
815                 final List<Surface> surfaces = mConfiguredOutputs.valueAt(i).getSurfaces();
816                 if (surfaces.contains(surface)) {
817                     streamId = mConfiguredOutputs.keyAt(i);
818                     break;
819                 }
820             }
821             if (streamId == -1) {
822                 throw new IllegalArgumentException("Surface is not part of this session");
823             }
824 
825             mRemoteDevice.prepare(streamId);
826         }
827     }
828 
prepare(int maxCount, Surface surface)829     public void prepare(int maxCount, Surface surface) throws CameraAccessException {
830         if (surface == null) throw new IllegalArgumentException("Surface is null");
831         if (maxCount <= 0) throw new IllegalArgumentException("Invalid maxCount given: " +
832                 maxCount);
833 
834         synchronized(mInterfaceLock) {
835             int streamId = -1;
836             for (int i = 0; i < mConfiguredOutputs.size(); i++) {
837                 if (surface == mConfiguredOutputs.valueAt(i).getSurface()) {
838                     streamId = mConfiguredOutputs.keyAt(i);
839                     break;
840                 }
841             }
842             if (streamId == -1) {
843                 throw new IllegalArgumentException("Surface is not part of this session");
844             }
845 
846             mRemoteDevice.prepare2(maxCount, streamId);
847         }
848     }
849 
updateOutputConfiguration(OutputConfiguration config)850     public void updateOutputConfiguration(OutputConfiguration config)
851             throws CameraAccessException {
852         synchronized(mInterfaceLock) {
853             int streamId = -1;
854             for (int i = 0; i < mConfiguredOutputs.size(); i++) {
855                 if (config.getSurface() == mConfiguredOutputs.valueAt(i).getSurface()) {
856                     streamId = mConfiguredOutputs.keyAt(i);
857                     break;
858                 }
859             }
860             if (streamId == -1) {
861                 throw new IllegalArgumentException("Invalid output configuration");
862             }
863 
864             mRemoteDevice.updateOutputConfiguration(streamId, config);
865             mConfiguredOutputs.put(streamId, config);
866         }
867     }
868 
tearDown(Surface surface)869     public void tearDown(Surface surface) throws CameraAccessException {
870         if (surface == null) throw new IllegalArgumentException("Surface is null");
871 
872         synchronized(mInterfaceLock) {
873             int streamId = -1;
874             for (int i = 0; i < mConfiguredOutputs.size(); i++) {
875                 if (surface == mConfiguredOutputs.valueAt(i).getSurface()) {
876                     streamId = mConfiguredOutputs.keyAt(i);
877                     break;
878                 }
879             }
880             if (streamId == -1) {
881                 throw new IllegalArgumentException("Surface is not part of this session");
882             }
883 
884             mRemoteDevice.tearDown(streamId);
885         }
886     }
887 
finalizeOutputConfigs(List<OutputConfiguration> outputConfigs)888     public void finalizeOutputConfigs(List<OutputConfiguration> outputConfigs)
889             throws CameraAccessException {
890         if (outputConfigs == null || outputConfigs.size() == 0) {
891             throw new IllegalArgumentException("deferred config is null or empty");
892         }
893 
894         synchronized(mInterfaceLock) {
895             for (OutputConfiguration config : outputConfigs) {
896                 int streamId = -1;
897                 for (int i = 0; i < mConfiguredOutputs.size(); i++) {
898                     // Have to use equal here, as createCaptureSessionByOutputConfigurations() and
899                     // createReprocessableCaptureSessionByConfigurations() do a copy of the configs.
900                     if (config.equals(mConfiguredOutputs.valueAt(i))) {
901                         streamId = mConfiguredOutputs.keyAt(i);
902                         break;
903                     }
904                 }
905                 if (streamId == -1) {
906                     throw new IllegalArgumentException("Deferred config is not part of this "
907                             + "session");
908                 }
909 
910                 if (config.getSurfaces().size() == 0) {
911                     throw new IllegalArgumentException("The final config for stream " + streamId
912                             + " must have at least 1 surface");
913                 }
914                 mRemoteDevice.finalizeOutputConfigurations(streamId, config);
915                 mConfiguredOutputs.put(streamId, config);
916             }
917         }
918     }
919 
capture(CaptureRequest request, CaptureCallback callback, Executor executor)920     public int capture(CaptureRequest request, CaptureCallback callback, Executor executor)
921             throws CameraAccessException {
922         if (DEBUG) {
923             Log.d(TAG, "calling capture");
924         }
925         List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
926         requestList.add(request);
927         return submitCaptureRequest(requestList, callback, executor, /*streaming*/false);
928     }
929 
captureBurst(List<CaptureRequest> requests, CaptureCallback callback, Executor executor)930     public int captureBurst(List<CaptureRequest> requests, CaptureCallback callback,
931             Executor executor) throws CameraAccessException {
932         if (requests == null || requests.isEmpty()) {
933             throw new IllegalArgumentException("At least one request must be given");
934         }
935         return submitCaptureRequest(requests, callback, executor, /*streaming*/false);
936     }
937 
938     /**
939      * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
940      * starting and stopping repeating request and flushing.
941      *
942      * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
943      * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
944      * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber as the last
945      * regular frame number will be added to the list mRequestLastFrameNumbersList.</p>
946      *
947      * @param requestId the request ID of the current repeating request.
948      * @param lastFrameNumber last frame number returned from binder.
949      * @param repeatingRequestTypes the repeating requests' types.
950      */
checkEarlyTriggerSequenceComplete( final int requestId, final long lastFrameNumber, final int[] repeatingRequestTypes)951     private void checkEarlyTriggerSequenceComplete(
952             final int requestId, final long lastFrameNumber,
953             final int[] repeatingRequestTypes) {
954         // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
955         // was never sent to HAL. Should trigger onCaptureSequenceAborted immediately.
956         if (lastFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
957             final CaptureCallbackHolder holder;
958             int index = mCaptureCallbackMap.indexOfKey(requestId);
959             holder = (index >= 0) ? mCaptureCallbackMap.valueAt(index) : null;
960             if (holder != null) {
961                 mCaptureCallbackMap.removeAt(index);
962                 if (DEBUG) {
963                     Log.v(TAG, String.format(
964                             "remove holder for requestId %d, "
965                             + "because lastFrame is %d.",
966                             requestId, lastFrameNumber));
967                 }
968             }
969 
970             if (holder != null) {
971                 if (DEBUG) {
972                     Log.v(TAG, "immediately trigger onCaptureSequenceAborted because"
973                             + " request did not reach HAL");
974                 }
975 
976                 Runnable resultDispatch = new Runnable() {
977                     @Override
978                     public void run() {
979                         if (!CameraDeviceImpl.this.isClosed()) {
980                             if (DEBUG) {
981                                 Log.d(TAG, String.format(
982                                         "early trigger sequence complete for request %d",
983                                         requestId));
984                             }
985                             holder.getCallback().onCaptureSequenceAborted(
986                                     CameraDeviceImpl.this,
987                                     requestId);
988                         }
989                     }
990                 };
991                 final long ident = Binder.clearCallingIdentity();
992                 try {
993                     holder.getExecutor().execute(resultDispatch);
994                 } finally {
995                     Binder.restoreCallingIdentity(ident);
996                 }
997             } else {
998                 Log.w(TAG, String.format(
999                         "did not register callback to request %d",
1000                         requestId));
1001             }
1002         } else {
1003             // This function is only called for regular/ZslStill request so lastFrameNumber is the
1004             // last regular/ZslStill frame number.
1005             mRequestLastFrameNumbersList.add(new RequestLastFrameNumbersHolder(requestId,
1006                     lastFrameNumber, repeatingRequestTypes));
1007 
1008             // It is possible that the last frame has already arrived, so we need to check
1009             // for sequence completion right away
1010             checkAndFireSequenceComplete();
1011         }
1012     }
1013 
getRequestTypes(final CaptureRequest[] requestArray)1014     private int[] getRequestTypes(final CaptureRequest[] requestArray) {
1015         int[] requestTypes = new int[requestArray.length];
1016         for (int i = 0; i < requestArray.length; i++) {
1017             requestTypes[i] = requestArray[i].getRequestType();
1018         }
1019         return requestTypes;
1020     }
1021 
submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback, Executor executor, boolean repeating)1022     private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
1023             Executor executor, boolean repeating) throws CameraAccessException {
1024 
1025         // Need a valid executor, or current thread needs to have a looper, if
1026         // callback is valid
1027         executor = checkExecutor(executor, callback);
1028 
1029         // Make sure that there all requests have at least 1 surface; all surfaces are non-null;
1030         // the surface isn't a physical stream surface for reprocessing request
1031         for (CaptureRequest request : requestList) {
1032             if (request.getTargets().isEmpty()) {
1033                 throw new IllegalArgumentException(
1034                         "Each request must have at least one Surface target");
1035             }
1036 
1037             for (Surface surface : request.getTargets()) {
1038                 if (surface == null) {
1039                     throw new IllegalArgumentException("Null Surface targets are not allowed");
1040                 }
1041 
1042                 for (int i = 0; i < mConfiguredOutputs.size(); i++) {
1043                     OutputConfiguration configuration = mConfiguredOutputs.valueAt(i);
1044                     if (configuration.isForPhysicalCamera()
1045                             && configuration.getSurfaces().contains(surface)) {
1046                         if (request.isReprocess()) {
1047                             throw new IllegalArgumentException(
1048                                     "Reprocess request on physical stream is not allowed");
1049                         }
1050                     }
1051                 }
1052             }
1053         }
1054 
1055         synchronized(mInterfaceLock) {
1056             checkIfCameraClosedOrInError();
1057             if (repeating) {
1058                 stopRepeating();
1059             }
1060 
1061             SubmitInfo requestInfo;
1062 
1063             CaptureRequest[] requestArray = requestList.toArray(new CaptureRequest[requestList.size()]);
1064             // Convert Surface to streamIdx and surfaceIdx
1065             for (CaptureRequest request : requestArray) {
1066                 request.convertSurfaceToStreamId(mConfiguredOutputs);
1067             }
1068 
1069             requestInfo = mRemoteDevice.submitRequestList(requestArray, repeating);
1070             if (DEBUG) {
1071                 Log.v(TAG, "last frame number " + requestInfo.getLastFrameNumber());
1072             }
1073 
1074             for (CaptureRequest request : requestArray) {
1075                 request.recoverStreamIdToSurface();
1076             }
1077 
1078             if (callback != null) {
1079                 mCaptureCallbackMap.put(requestInfo.getRequestId(),
1080                         new CaptureCallbackHolder(
1081                             callback, requestList, executor, repeating, mNextSessionId - 1));
1082             } else {
1083                 if (DEBUG) {
1084                     Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null");
1085                 }
1086             }
1087 
1088             if (repeating) {
1089                 if (mRepeatingRequestId != REQUEST_ID_NONE) {
1090                     checkEarlyTriggerSequenceComplete(mRepeatingRequestId,
1091                             requestInfo.getLastFrameNumber(),
1092                             mRepeatingRequestTypes);
1093                 }
1094                 mRepeatingRequestId = requestInfo.getRequestId();
1095                 mRepeatingRequestTypes = getRequestTypes(requestArray);
1096             } else {
1097                 mRequestLastFrameNumbersList.add(
1098                     new RequestLastFrameNumbersHolder(requestList, requestInfo));
1099             }
1100 
1101             if (mIdle) {
1102                 mDeviceExecutor.execute(mCallOnActive);
1103             }
1104             mIdle = false;
1105 
1106             return requestInfo.getRequestId();
1107         }
1108     }
1109 
setRepeatingRequest(CaptureRequest request, CaptureCallback callback, Executor executor)1110     public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
1111             Executor executor) throws CameraAccessException {
1112         List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
1113         requestList.add(request);
1114         return submitCaptureRequest(requestList, callback, executor, /*streaming*/true);
1115     }
1116 
setRepeatingBurst(List<CaptureRequest> requests, CaptureCallback callback, Executor executor)1117     public int setRepeatingBurst(List<CaptureRequest> requests, CaptureCallback callback,
1118             Executor executor) throws CameraAccessException {
1119         if (requests == null || requests.isEmpty()) {
1120             throw new IllegalArgumentException("At least one request must be given");
1121         }
1122         return submitCaptureRequest(requests, callback, executor, /*streaming*/true);
1123     }
1124 
stopRepeating()1125     public void stopRepeating() throws CameraAccessException {
1126 
1127         synchronized(mInterfaceLock) {
1128             checkIfCameraClosedOrInError();
1129             if (mRepeatingRequestId != REQUEST_ID_NONE) {
1130 
1131                 int requestId = mRepeatingRequestId;
1132                 mRepeatingRequestId = REQUEST_ID_NONE;
1133                 int[] requestTypes = mRepeatingRequestTypes;
1134                 mRepeatingRequestTypes = null;
1135 
1136                 long lastFrameNumber;
1137                 try {
1138                     lastFrameNumber = mRemoteDevice.cancelRequest(requestId);
1139                 } catch (IllegalArgumentException e) {
1140                     if (DEBUG) {
1141                         Log.v(TAG, "Repeating request was already stopped for request " + requestId);
1142                     }
1143                     // Repeating request was already stopped. Nothing more to do.
1144                     return;
1145                 }
1146 
1147                 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber, requestTypes);
1148             }
1149         }
1150     }
1151 
waitUntilIdle()1152     private void waitUntilIdle() throws CameraAccessException {
1153 
1154         synchronized(mInterfaceLock) {
1155             checkIfCameraClosedOrInError();
1156 
1157             if (mRepeatingRequestId != REQUEST_ID_NONE) {
1158                 throw new IllegalStateException("Active repeating request ongoing");
1159             }
1160 
1161             mRemoteDevice.waitUntilIdle();
1162         }
1163     }
1164 
flush()1165     public void flush() throws CameraAccessException {
1166         synchronized(mInterfaceLock) {
1167             checkIfCameraClosedOrInError();
1168 
1169             mDeviceExecutor.execute(mCallOnBusy);
1170 
1171             // If already idle, just do a busy->idle transition immediately, don't actually
1172             // flush.
1173             if (mIdle) {
1174                 mDeviceExecutor.execute(mCallOnIdle);
1175                 return;
1176             }
1177 
1178             long lastFrameNumber = mRemoteDevice.flush();
1179             if (mRepeatingRequestId != REQUEST_ID_NONE) {
1180                 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber,
1181                         mRepeatingRequestTypes);
1182                 mRepeatingRequestId = REQUEST_ID_NONE;
1183                 mRepeatingRequestTypes = null;
1184             }
1185         }
1186     }
1187 
1188     @Override
close()1189     public void close() {
1190         synchronized (mInterfaceLock) {
1191             if (mClosing.getAndSet(true)) {
1192                 return;
1193             }
1194 
1195             if (mRemoteDevice != null) {
1196                 mRemoteDevice.disconnect();
1197                 mRemoteDevice.unlinkToDeath(this, /*flags*/0);
1198             }
1199 
1200             // Only want to fire the onClosed callback once;
1201             // either a normal close where the remote device is valid
1202             // or a close after a startup error (no remote device but in error state)
1203             if (mRemoteDevice != null || mInError) {
1204                 mDeviceExecutor.execute(mCallOnClosed);
1205             }
1206 
1207             mRemoteDevice = null;
1208         }
1209     }
1210 
1211     @Override
finalize()1212     protected void finalize() throws Throwable {
1213         try {
1214             close();
1215         }
1216         finally {
1217             super.finalize();
1218         }
1219     }
1220 
checkInputConfiguration(InputConfiguration inputConfig)1221     private void checkInputConfiguration(InputConfiguration inputConfig) {
1222         if (inputConfig != null) {
1223             StreamConfigurationMap configMap = mCharacteristics.get(
1224                     CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
1225 
1226             int[] inputFormats = configMap.getInputFormats();
1227             boolean validFormat = false;
1228             for (int format : inputFormats) {
1229                 if (format == inputConfig.getFormat()) {
1230                     validFormat = true;
1231                 }
1232             }
1233 
1234             if (validFormat == false) {
1235                 throw new IllegalArgumentException("input format " + inputConfig.getFormat() +
1236                         " is not valid");
1237             }
1238 
1239             boolean validSize = false;
1240             Size[] inputSizes = configMap.getInputSizes(inputConfig.getFormat());
1241             for (Size s : inputSizes) {
1242                 if (inputConfig.getWidth() == s.getWidth() &&
1243                         inputConfig.getHeight() == s.getHeight()) {
1244                     validSize = true;
1245                 }
1246             }
1247 
1248             if (validSize == false) {
1249                 throw new IllegalArgumentException("input size " + inputConfig.getWidth() + "x" +
1250                         inputConfig.getHeight() + " is not valid");
1251             }
1252         }
1253     }
1254 
1255     /**
1256      * <p>A callback for tracking the progress of a {@link CaptureRequest}
1257      * submitted to the camera device.</p>
1258      *
1259      * An interface instead of an abstract class because this is internal and
1260      * we want to make sure we always implement all its callbacks until we reach
1261      * the public layer.
1262      */
1263     public interface CaptureCallback {
1264 
1265         /**
1266          * This constant is used to indicate that no images were captured for
1267          * the request.
1268          *
1269          * @hide
1270          */
1271         public static final int NO_FRAMES_CAPTURED = -1;
1272 
1273         /**
1274          * This method is called when the camera device has started capturing
1275          * the output image for the request, at the beginning of image exposure.
1276          *
1277          * @see android.media.MediaActionSound
1278          */
onCaptureStarted(CameraDevice camera, CaptureRequest request, long timestamp, long frameNumber)1279         public void onCaptureStarted(CameraDevice camera,
1280                 CaptureRequest request, long timestamp, long frameNumber);
1281 
1282         /**
1283          * This method is called when some results from an image capture are
1284          * available.
1285          *
1286          * @hide
1287          */
onCapturePartial(CameraDevice camera, CaptureRequest request, CaptureResult result)1288         public void onCapturePartial(CameraDevice camera,
1289                 CaptureRequest request, CaptureResult result);
1290 
1291         /**
1292          * This method is called when an image capture makes partial forward progress; some
1293          * (but not all) results from an image capture are available.
1294          *
1295          */
onCaptureProgressed(CameraDevice camera, CaptureRequest request, CaptureResult partialResult)1296         public void onCaptureProgressed(CameraDevice camera,
1297                 CaptureRequest request, CaptureResult partialResult);
1298 
1299         /**
1300          * This method is called when an image capture has fully completed and all the
1301          * result metadata is available.
1302          */
onCaptureCompleted(CameraDevice camera, CaptureRequest request, TotalCaptureResult result)1303         public void onCaptureCompleted(CameraDevice camera,
1304                 CaptureRequest request, TotalCaptureResult result);
1305 
1306         /**
1307          * This method is called instead of {@link #onCaptureCompleted} when the
1308          * camera device failed to produce a {@link CaptureResult} for the
1309          * request.
1310          */
onCaptureFailed(CameraDevice camera, CaptureRequest request, CaptureFailure failure)1311         public void onCaptureFailed(CameraDevice camera,
1312                 CaptureRequest request, CaptureFailure failure);
1313 
1314         /**
1315          * This method is called independently of the others in CaptureCallback,
1316          * when a capture sequence finishes and all {@link CaptureResult}
1317          * or {@link CaptureFailure} for it have been returned via this callback.
1318          */
onCaptureSequenceCompleted(CameraDevice camera, int sequenceId, long frameNumber)1319         public void onCaptureSequenceCompleted(CameraDevice camera,
1320                 int sequenceId, long frameNumber);
1321 
1322         /**
1323          * This method is called independently of the others in CaptureCallback,
1324          * when a capture sequence aborts before any {@link CaptureResult}
1325          * or {@link CaptureFailure} for it have been returned via this callback.
1326          */
onCaptureSequenceAborted(CameraDevice camera, int sequenceId)1327         public void onCaptureSequenceAborted(CameraDevice camera,
1328                 int sequenceId);
1329 
1330         /**
1331          * This method is called independently of the others in CaptureCallback, if an output buffer
1332          * is dropped for a particular capture request.
1333          *
1334          * Loss of metadata is communicated via onCaptureFailed, independently of any buffer loss.
1335          */
onCaptureBufferLost(CameraDevice camera, CaptureRequest request, Surface target, long frameNumber)1336         public void onCaptureBufferLost(CameraDevice camera,
1337                 CaptureRequest request, Surface target, long frameNumber);
1338     }
1339 
1340     /**
1341      * A callback for notifications about the state of a camera device, adding in the callbacks that
1342      * were part of the earlier KK API design, but now only used internally.
1343      */
1344     public static abstract class StateCallbackKK extends StateCallback {
1345         /**
1346          * The method called when a camera device has no outputs configured.
1347          *
1348          */
onUnconfigured(CameraDevice camera)1349         public void onUnconfigured(CameraDevice camera) {
1350             // Default empty implementation
1351         }
1352 
1353         /**
1354          * The method called when a camera device begins processing
1355          * {@link CaptureRequest capture requests}.
1356          *
1357          */
onActive(CameraDevice camera)1358         public void onActive(CameraDevice camera) {
1359             // Default empty implementation
1360         }
1361 
1362         /**
1363          * The method called when a camera device is busy.
1364          *
1365          */
onBusy(CameraDevice camera)1366         public void onBusy(CameraDevice camera) {
1367             // Default empty implementation
1368         }
1369 
1370         /**
1371          * The method called when a camera device has finished processing all
1372          * submitted capture requests and has reached an idle state.
1373          *
1374          */
onIdle(CameraDevice camera)1375         public void onIdle(CameraDevice camera) {
1376             // Default empty implementation
1377         }
1378 
1379         /**
1380          * This method is called when camera device's non-repeating request queue is empty,
1381          * and is ready to start capturing next image.
1382          */
onRequestQueueEmpty()1383         public void onRequestQueueEmpty() {
1384             // Default empty implementation
1385         }
1386 
1387         /**
1388          * The method called when the camera device has finished preparing
1389          * an output Surface
1390          */
onSurfacePrepared(Surface surface)1391         public void onSurfacePrepared(Surface surface) {
1392             // Default empty implementation
1393         }
1394     }
1395 
1396     static class CaptureCallbackHolder {
1397 
1398         private final boolean mRepeating;
1399         private final CaptureCallback mCallback;
1400         private final List<CaptureRequest> mRequestList;
1401         private final Executor mExecutor;
1402         private final int mSessionId;
1403         /**
1404          * <p>Determine if the callback holder is for a constrained high speed request list that
1405          * expects batched capture results. Capture results will be batched if the request list
1406          * is interleaved with preview and video requests. Capture results won't be batched if the
1407          * request list only contains preview requests, or if the request doesn't belong to a
1408          * constrained high speed list.
1409          */
1410         private final boolean mHasBatchedOutputs;
1411 
CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList, Executor executor, boolean repeating, int sessionId)1412         CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList,
1413                 Executor executor, boolean repeating, int sessionId) {
1414             if (callback == null || executor == null) {
1415                 throw new UnsupportedOperationException(
1416                     "Must have a valid handler and a valid callback");
1417             }
1418             mRepeating = repeating;
1419             mExecutor = executor;
1420             mRequestList = new ArrayList<CaptureRequest>(requestList);
1421             mCallback = callback;
1422             mSessionId = sessionId;
1423 
1424             // Check whether this callback holder is for batched outputs.
1425             // The logic here should match createHighSpeedRequestList.
1426             boolean hasBatchedOutputs = true;
1427             for (int i = 0; i < requestList.size(); i++) {
1428                 CaptureRequest request = requestList.get(i);
1429                 if (!request.isPartOfCRequestList()) {
1430                     hasBatchedOutputs = false;
1431                     break;
1432                 }
1433                 if (i == 0) {
1434                     Collection<Surface> targets = request.getTargets();
1435                     if (targets.size() != 2) {
1436                         hasBatchedOutputs = false;
1437                         break;
1438                     }
1439                 }
1440             }
1441             mHasBatchedOutputs = hasBatchedOutputs;
1442         }
1443 
isRepeating()1444         public boolean isRepeating() {
1445             return mRepeating;
1446         }
1447 
getCallback()1448         public CaptureCallback getCallback() {
1449             return mCallback;
1450         }
1451 
getRequest(int subsequenceId)1452         public CaptureRequest getRequest(int subsequenceId) {
1453             if (subsequenceId >= mRequestList.size()) {
1454                 throw new IllegalArgumentException(
1455                         String.format(
1456                                 "Requested subsequenceId %d is larger than request list size %d.",
1457                                 subsequenceId, mRequestList.size()));
1458             } else {
1459                 if (subsequenceId < 0) {
1460                     throw new IllegalArgumentException(String.format(
1461                             "Requested subsequenceId %d is negative", subsequenceId));
1462                 } else {
1463                     return mRequestList.get(subsequenceId);
1464                 }
1465             }
1466         }
1467 
getRequest()1468         public CaptureRequest getRequest() {
1469             return getRequest(0);
1470         }
1471 
getExecutor()1472         public Executor getExecutor() {
1473             return mExecutor;
1474         }
1475 
getSessionId()1476         public int getSessionId() {
1477             return mSessionId;
1478         }
1479 
getRequestCount()1480         public int getRequestCount() {
1481             return mRequestList.size();
1482         }
1483 
hasBatchedOutputs()1484         public boolean hasBatchedOutputs() {
1485             return mHasBatchedOutputs;
1486         }
1487     }
1488 
1489     /**
1490      * This class holds a capture ID and its expected last regular, zslStill, and reprocess
1491      * frame number.
1492      */
1493     static class RequestLastFrameNumbersHolder {
1494         // request ID
1495         private final int mRequestId;
1496         // The last regular frame number for this request ID. It's
1497         // CaptureCallback.NO_FRAMES_CAPTURED if the request ID has no regular request.
1498         private final long mLastRegularFrameNumber;
1499         // The last reprocess frame number for this request ID. It's
1500         // CaptureCallback.NO_FRAMES_CAPTURED if the request ID has no reprocess request.
1501         private final long mLastReprocessFrameNumber;
1502         // The last ZSL still capture frame number for this request ID. It's
1503         // CaptureCallback.NO_FRAMES_CAPTURED if the request ID has no zsl request.
1504         private final long mLastZslStillFrameNumber;
1505 
1506         /**
1507          * Create a request-last-frame-numbers holder with a list of requests, request ID, and
1508          * the last frame number returned by camera service.
1509          */
RequestLastFrameNumbersHolder(List<CaptureRequest> requestList, SubmitInfo requestInfo)1510         public RequestLastFrameNumbersHolder(List<CaptureRequest> requestList, SubmitInfo requestInfo) {
1511             long lastRegularFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
1512             long lastReprocessFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
1513             long lastZslStillFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
1514             long frameNumber = requestInfo.getLastFrameNumber();
1515 
1516             if (requestInfo.getLastFrameNumber() < requestList.size() - 1) {
1517                 throw new IllegalArgumentException(
1518                         "lastFrameNumber: " + requestInfo.getLastFrameNumber() +
1519                         " should be at least " + (requestList.size() - 1) + " for the number of " +
1520                         " requests in the list: " + requestList.size());
1521             }
1522 
1523             // find the last regular, zslStill, and reprocess frame number
1524             for (int i = requestList.size() - 1; i >= 0; i--) {
1525                 CaptureRequest request = requestList.get(i);
1526                 int requestType = request.getRequestType();
1527                 if (requestType == CaptureRequest.REQUEST_TYPE_REPROCESS
1528                         && lastReprocessFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
1529                     lastReprocessFrameNumber = frameNumber;
1530                 } else if (requestType == CaptureRequest.REQUEST_TYPE_ZSL_STILL
1531                         && lastZslStillFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
1532                     lastZslStillFrameNumber = frameNumber;
1533                 } else if (requestType == CaptureRequest.REQUEST_TYPE_REGULAR
1534                         && lastRegularFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
1535                     lastRegularFrameNumber = frameNumber;
1536                 }
1537 
1538                 if (lastReprocessFrameNumber != CaptureCallback.NO_FRAMES_CAPTURED
1539                         && lastZslStillFrameNumber != CaptureCallback.NO_FRAMES_CAPTURED
1540                         && lastRegularFrameNumber != CaptureCallback.NO_FRAMES_CAPTURED) {
1541                     break;
1542                 }
1543 
1544                 frameNumber--;
1545             }
1546 
1547             mLastRegularFrameNumber = lastRegularFrameNumber;
1548             mLastReprocessFrameNumber = lastReprocessFrameNumber;
1549             mLastZslStillFrameNumber = lastZslStillFrameNumber;
1550             mRequestId = requestInfo.getRequestId();
1551         }
1552 
1553         /**
1554          * Create a request-last-frame-numbers holder with a request ID and last regular/ZslStill
1555          * frame number.
1556          */
RequestLastFrameNumbersHolder(int requestId, long lastFrameNumber, int[] repeatingRequestTypes)1557         RequestLastFrameNumbersHolder(int requestId, long lastFrameNumber,
1558                 int[] repeatingRequestTypes) {
1559             long lastRegularFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
1560             long lastZslStillFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
1561 
1562             if (repeatingRequestTypes == null) {
1563                 throw new IllegalArgumentException(
1564                         "repeatingRequest list must not be null");
1565             }
1566             if (lastFrameNumber < repeatingRequestTypes.length - 1) {
1567                 throw new IllegalArgumentException(
1568                         "lastFrameNumber: " + lastFrameNumber + " should be at least "
1569                         + (repeatingRequestTypes.length - 1)
1570                         + " for the number of requests in the list: "
1571                         + repeatingRequestTypes.length);
1572             }
1573 
1574             long frameNumber = lastFrameNumber;
1575             for (int i = repeatingRequestTypes.length - 1; i >= 0; i--) {
1576                 if (repeatingRequestTypes[i] == CaptureRequest.REQUEST_TYPE_ZSL_STILL
1577                         && lastZslStillFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
1578                     lastZslStillFrameNumber = frameNumber;
1579                 } else if (repeatingRequestTypes[i] == CaptureRequest.REQUEST_TYPE_REGULAR
1580                         && lastRegularFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
1581                     lastRegularFrameNumber = frameNumber;
1582                 }
1583 
1584                 if (lastZslStillFrameNumber != CaptureCallback.NO_FRAMES_CAPTURED
1585                         && lastRegularFrameNumber != CaptureCallback.NO_FRAMES_CAPTURED) {
1586                     break;
1587                 }
1588 
1589                 frameNumber--;
1590             }
1591 
1592             mLastRegularFrameNumber = lastRegularFrameNumber;
1593             mLastZslStillFrameNumber = lastZslStillFrameNumber;
1594             mLastReprocessFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
1595             mRequestId = requestId;
1596         }
1597 
1598         /**
1599          * Return the last regular frame number. Return CaptureCallback.NO_FRAMES_CAPTURED if
1600          * it contains no regular request.
1601          */
getLastRegularFrameNumber()1602         public long getLastRegularFrameNumber() {
1603             return mLastRegularFrameNumber;
1604         }
1605 
1606         /**
1607          * Return the last reprocess frame number. Return CaptureCallback.NO_FRAMES_CAPTURED if
1608          * it contains no reprocess request.
1609          */
getLastReprocessFrameNumber()1610         public long getLastReprocessFrameNumber() {
1611             return mLastReprocessFrameNumber;
1612         }
1613 
1614         /**
1615          * Return the last ZslStill frame number. Return CaptureCallback.NO_FRAMES_CAPTURED if
1616          * it contains no Zsl request.
1617          */
getLastZslStillFrameNumber()1618         public long getLastZslStillFrameNumber() {
1619             return mLastZslStillFrameNumber;
1620         }
1621 
1622         /**
1623          * Return the last frame number overall.
1624          */
getLastFrameNumber()1625         public long getLastFrameNumber() {
1626             return Math.max(mLastZslStillFrameNumber,
1627                     Math.max(mLastRegularFrameNumber, mLastReprocessFrameNumber));
1628         }
1629 
1630         /**
1631          * Return the request ID.
1632          */
getRequestId()1633         public int getRequestId() {
1634             return mRequestId;
1635         }
1636     }
1637 
1638     /**
1639      * This class tracks the last frame number for submitted requests.
1640      */
1641     public class FrameNumberTracker {
1642 
1643         /** the completed frame number for each type of capture results */
1644         private long[] mCompletedFrameNumber = new long[CaptureRequest.REQUEST_TYPE_COUNT];
1645 
1646         /** the skipped frame numbers that don't belong to each type of capture results */
1647         private final LinkedList<Long>[] mSkippedOtherFrameNumbers =
1648                 new LinkedList[CaptureRequest.REQUEST_TYPE_COUNT];
1649 
1650         /** the skipped frame numbers that belong to each type of capture results */
1651         private final LinkedList<Long>[] mSkippedFrameNumbers =
1652                 new LinkedList[CaptureRequest.REQUEST_TYPE_COUNT];
1653 
1654         /** frame number -> request type */
1655         private final TreeMap<Long, Integer> mFutureErrorMap = new TreeMap<Long, Integer>();
1656         /** Map frame numbers to list of partial results */
1657         private final HashMap<Long, List<CaptureResult>> mPartialResults = new HashMap<>();
1658 
FrameNumberTracker()1659         public FrameNumberTracker() {
1660             for (int i = 0; i < CaptureRequest.REQUEST_TYPE_COUNT; i++) {
1661                 mCompletedFrameNumber[i] = CaptureCallback.NO_FRAMES_CAPTURED;
1662                 mSkippedOtherFrameNumbers[i] = new LinkedList<Long>();
1663                 mSkippedFrameNumbers[i] = new LinkedList<Long>();
1664             }
1665         }
1666 
update()1667         private void update() {
1668             Iterator iter = mFutureErrorMap.entrySet().iterator();
1669             while (iter.hasNext()) {
1670                 TreeMap.Entry pair = (TreeMap.Entry)iter.next();
1671                 Long errorFrameNumber = (Long)pair.getKey();
1672                 int requestType = (int) pair.getValue();
1673                 Boolean removeError = false;
1674                 if (errorFrameNumber == mCompletedFrameNumber[requestType] + 1) {
1675                     mCompletedFrameNumber[requestType] = errorFrameNumber;
1676                     removeError = true;
1677                 } else {
1678                     if (!mSkippedFrameNumbers[requestType].isEmpty()) {
1679                         if (errorFrameNumber == mSkippedFrameNumbers[requestType].element()) {
1680                             mCompletedFrameNumber[requestType] = errorFrameNumber;
1681                             mSkippedFrameNumbers[requestType].remove();
1682                             removeError = true;
1683                         }
1684                     } else {
1685                         for (int i = 1; i < CaptureRequest.REQUEST_TYPE_COUNT; i++) {
1686                             int otherType = (requestType + i) % CaptureRequest.REQUEST_TYPE_COUNT;
1687                             if (!mSkippedOtherFrameNumbers[otherType].isEmpty() && errorFrameNumber
1688                                     == mSkippedOtherFrameNumbers[otherType].element()) {
1689                                 mCompletedFrameNumber[requestType] = errorFrameNumber;
1690                                 mSkippedOtherFrameNumbers[otherType].remove();
1691                                 removeError = true;
1692                                 break;
1693                             }
1694                         }
1695                     }
1696                 }
1697                 if (removeError) {
1698                     iter.remove();
1699                 }
1700             }
1701         }
1702 
1703         /**
1704          * This function is called every time when a result or an error is received.
1705          * @param frameNumber the frame number corresponding to the result or error
1706          * @param isError true if it is an error, false if it is not an error
1707          * @param requestType the type of capture request: Reprocess, ZslStill, or Regular.
1708          */
updateTracker(long frameNumber, boolean isError, int requestType)1709         public void updateTracker(long frameNumber, boolean isError, int requestType) {
1710             if (isError) {
1711                 mFutureErrorMap.put(frameNumber, requestType);
1712             } else {
1713                 try {
1714                     updateCompletedFrameNumber(frameNumber, requestType);
1715                 } catch (IllegalArgumentException e) {
1716                     Log.e(TAG, e.getMessage());
1717                 }
1718             }
1719             update();
1720         }
1721 
1722         /**
1723          * This function is called every time a result has been completed.
1724          *
1725          * <p>It keeps a track of all the partial results already created for a particular
1726          * frame number.</p>
1727          *
1728          * @param frameNumber the frame number corresponding to the result
1729          * @param result the total or partial result
1730          * @param partial {@true} if the result is partial, {@code false} if total
1731          * @param requestType the type of capture request: Reprocess, ZslStill, or Regular.
1732          */
updateTracker(long frameNumber, CaptureResult result, boolean partial, int requestType)1733         public void updateTracker(long frameNumber, CaptureResult result, boolean partial,
1734                 int requestType) {
1735             if (!partial) {
1736                 // Update the total result's frame status as being successful
1737                 updateTracker(frameNumber, /*isError*/false, requestType);
1738                 // Don't keep a list of total results, we don't need to track them
1739                 return;
1740             }
1741 
1742             if (result == null) {
1743                 // Do not record blank results; this also means there will be no total result
1744                 // so it doesn't matter that the partials were not recorded
1745                 return;
1746             }
1747 
1748             // Partial results must be aggregated in-order for that frame number
1749             List<CaptureResult> partials = mPartialResults.get(frameNumber);
1750             if (partials == null) {
1751                 partials = new ArrayList<>();
1752                 mPartialResults.put(frameNumber, partials);
1753             }
1754 
1755             partials.add(result);
1756         }
1757 
1758         /**
1759          * Attempt to pop off all of the partial results seen so far for the {@code frameNumber}.
1760          *
1761          * <p>Once popped-off, the partial results are forgotten (unless {@code updateTracker}
1762          * is called again with new partials for that frame number).</p>
1763          *
1764          * @param frameNumber the frame number corresponding to the result
1765          * @return a list of partial results for that frame with at least 1 element,
1766          *         or {@code null} if there were no partials recorded for that frame
1767          */
popPartialResults(long frameNumber)1768         public List<CaptureResult> popPartialResults(long frameNumber) {
1769             return mPartialResults.remove(frameNumber);
1770         }
1771 
getCompletedFrameNumber()1772         public long getCompletedFrameNumber() {
1773             return mCompletedFrameNumber[CaptureRequest.REQUEST_TYPE_REGULAR];
1774         }
1775 
getCompletedReprocessFrameNumber()1776         public long getCompletedReprocessFrameNumber() {
1777             return mCompletedFrameNumber[CaptureRequest.REQUEST_TYPE_REPROCESS];
1778         }
1779 
getCompletedZslStillFrameNumber()1780         public long getCompletedZslStillFrameNumber() {
1781             return mCompletedFrameNumber[CaptureRequest.REQUEST_TYPE_ZSL_STILL];
1782         }
1783 
1784         /**
1785          * Update the completed frame number for results of 3 categories
1786          * (Regular/Reprocess/ZslStill).
1787          *
1788          * It validates that all previous frames of the same category have arrived.
1789          *
1790          * If there is a gap since previous frame number of the same category, assume the frames in
1791          * the gap are other categories and store them in the skipped frame number queue to check
1792          * against when frames of those categories arrive.
1793          */
updateCompletedFrameNumber(long frameNumber, int requestType)1794         private void updateCompletedFrameNumber(long frameNumber,
1795                 int requestType) throws IllegalArgumentException {
1796             if (frameNumber <= mCompletedFrameNumber[requestType]) {
1797                 throw new IllegalArgumentException("frame number " + frameNumber + " is a repeat");
1798             }
1799 
1800             // Assume there are only 3 different types of capture requests.
1801             int otherType1 = (requestType + 1) % CaptureRequest.REQUEST_TYPE_COUNT;
1802             int otherType2 = (requestType + 2) % CaptureRequest.REQUEST_TYPE_COUNT;
1803             long maxOtherFrameNumberSeen =
1804                     Math.max(mCompletedFrameNumber[otherType1], mCompletedFrameNumber[otherType2]);
1805             if (frameNumber < maxOtherFrameNumberSeen) {
1806                 // if frame number is smaller than completed frame numbers of other categories,
1807                 // it must be:
1808                 // - the head of mSkippedFrameNumbers for this category, or
1809                 // - in one of other mSkippedOtherFrameNumbers
1810                 if (!mSkippedFrameNumbers[requestType].isEmpty()) {
1811                     // frame number must be head of current type of mSkippedFrameNumbers if
1812                     // mSkippedFrameNumbers isn't empty.
1813                     if (frameNumber < mSkippedFrameNumbers[requestType].element()) {
1814                         throw new IllegalArgumentException("frame number " + frameNumber
1815                                 + " is a repeat");
1816                     } else if (frameNumber > mSkippedFrameNumbers[requestType].element()) {
1817                         throw new IllegalArgumentException("frame number " + frameNumber
1818                                 + " comes out of order. Expecting "
1819                                 + mSkippedFrameNumbers[requestType].element());
1820                     }
1821                     // frame number matches the head of the skipped frame number queue.
1822                     mSkippedFrameNumbers[requestType].remove();
1823                 } else {
1824                     // frame number must be in one of the other mSkippedOtherFrameNumbers.
1825                     int index1 = mSkippedOtherFrameNumbers[otherType1].indexOf(frameNumber);
1826                     int index2 = mSkippedOtherFrameNumbers[otherType2].indexOf(frameNumber);
1827                     boolean inSkippedOther1 = index1 != -1;
1828                     boolean inSkippedOther2 = index2 != -1;
1829                     if (!(inSkippedOther1 ^ inSkippedOther2)) {
1830                         throw new IllegalArgumentException("frame number " + frameNumber
1831                                 + " is a repeat or invalid");
1832                     }
1833 
1834                     // We know the category of frame numbers in skippedOtherFrameNumbers leading up
1835                     // to the current frame number. Move them into the correct skippedFrameNumbers.
1836                     LinkedList<Long> srcList, dstList;
1837                     int index;
1838                     if (inSkippedOther1) {
1839                         srcList = mSkippedOtherFrameNumbers[otherType1];
1840                         dstList = mSkippedFrameNumbers[otherType2];
1841                         index = index1;
1842                     } else {
1843                         srcList = mSkippedOtherFrameNumbers[otherType2];
1844                         dstList = mSkippedFrameNumbers[otherType1];
1845                         index = index2;
1846                     }
1847                     for (int i = 0; i < index; i++) {
1848                         dstList.add(srcList.removeFirst());
1849                     }
1850 
1851                     // Remove current frame number from skippedOtherFrameNumbers
1852                     srcList.remove();
1853                 }
1854             } else {
1855                 // there is a gap of unseen frame numbers which should belong to the other
1856                 // 2 categories. Put all the skipped frame numbers in the queue.
1857                 for (long i =
1858                         Math.max(maxOtherFrameNumberSeen, mCompletedFrameNumber[requestType]) + 1;
1859                         i < frameNumber; i++) {
1860                     mSkippedOtherFrameNumbers[requestType].add(i);
1861                 }
1862             }
1863 
1864             mCompletedFrameNumber[requestType] = frameNumber;
1865         }
1866     }
1867 
checkAndFireSequenceComplete()1868     private void checkAndFireSequenceComplete() {
1869         long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
1870         long completedReprocessFrameNumber = mFrameNumberTracker.getCompletedReprocessFrameNumber();
1871         long completedZslStillFrameNumber = mFrameNumberTracker.getCompletedZslStillFrameNumber();
1872         boolean isReprocess = false;
1873         Iterator<RequestLastFrameNumbersHolder> iter = mRequestLastFrameNumbersList.iterator();
1874         while (iter.hasNext()) {
1875             final RequestLastFrameNumbersHolder requestLastFrameNumbers = iter.next();
1876             boolean sequenceCompleted = false;
1877             final int requestId = requestLastFrameNumbers.getRequestId();
1878             final CaptureCallbackHolder holder;
1879             synchronized(mInterfaceLock) {
1880                 if (mRemoteDevice == null) {
1881                     Log.w(TAG, "Camera closed while checking sequences");
1882                     return;
1883                 }
1884 
1885                 int index = mCaptureCallbackMap.indexOfKey(requestId);
1886                 holder = (index >= 0) ?
1887                         mCaptureCallbackMap.valueAt(index) : null;
1888                 if (holder != null) {
1889                     long lastRegularFrameNumber =
1890                             requestLastFrameNumbers.getLastRegularFrameNumber();
1891                     long lastReprocessFrameNumber =
1892                             requestLastFrameNumbers.getLastReprocessFrameNumber();
1893                     long lastZslStillFrameNumber =
1894                             requestLastFrameNumbers.getLastZslStillFrameNumber();
1895                     // check if it's okay to remove request from mCaptureCallbackMap
1896                     if (lastRegularFrameNumber <= completedFrameNumber
1897                             && lastReprocessFrameNumber <= completedReprocessFrameNumber
1898                             && lastZslStillFrameNumber <= completedZslStillFrameNumber) {
1899                         sequenceCompleted = true;
1900                         mCaptureCallbackMap.removeAt(index);
1901                         if (DEBUG) {
1902                             Log.v(TAG, String.format(
1903                                     "Remove holder for requestId %d, because lastRegularFrame %d "
1904                                     + "is <= %d, lastReprocessFrame %d is <= %d, "
1905                                     + "lastZslStillFrame %d is <= %d", requestId,
1906                                     lastRegularFrameNumber, completedFrameNumber,
1907                                     lastReprocessFrameNumber, completedReprocessFrameNumber,
1908                                     lastZslStillFrameNumber, completedZslStillFrameNumber));
1909                         }
1910                     }
1911                 }
1912             }
1913 
1914             // If no callback is registered for this requestId or sequence completed, remove it
1915             // from the frame number->request pair because it's not needed anymore.
1916             if (holder == null || sequenceCompleted) {
1917                 iter.remove();
1918             }
1919 
1920             // Call onCaptureSequenceCompleted
1921             if (sequenceCompleted) {
1922                 Runnable resultDispatch = new Runnable() {
1923                     @Override
1924                     public void run() {
1925                         if (!CameraDeviceImpl.this.isClosed()){
1926                             if (DEBUG) {
1927                                 Log.d(TAG, String.format(
1928                                         "fire sequence complete for request %d",
1929                                         requestId));
1930                             }
1931 
1932                             holder.getCallback().onCaptureSequenceCompleted(
1933                                 CameraDeviceImpl.this,
1934                                 requestId,
1935                                 requestLastFrameNumbers.getLastFrameNumber());
1936                         }
1937                     }
1938                 };
1939                 final long ident = Binder.clearCallingIdentity();
1940                 try {
1941                     holder.getExecutor().execute(resultDispatch);
1942                 } finally {
1943                     Binder.restoreCallingIdentity(ident);
1944                 }
1945             }
1946         }
1947     }
1948 
1949     public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
1950 
1951         @Override
asBinder()1952         public IBinder asBinder() {
1953             return this;
1954         }
1955 
1956         @Override
onDeviceError(final int errorCode, CaptureResultExtras resultExtras)1957         public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) {
1958             if (DEBUG) {
1959                 Log.d(TAG, String.format(
1960                         "Device error received, code %d, frame number %d, request ID %d, subseq ID %d",
1961                         errorCode, resultExtras.getFrameNumber(), resultExtras.getRequestId(),
1962                         resultExtras.getSubsequenceId()));
1963             }
1964 
1965             synchronized(mInterfaceLock) {
1966                 if (mRemoteDevice == null) {
1967                     return; // Camera already closed
1968                 }
1969 
1970                 switch (errorCode) {
1971                     case ERROR_CAMERA_DISCONNECTED:
1972                         final long ident = Binder.clearCallingIdentity();
1973                         try {
1974                             CameraDeviceImpl.this.mDeviceExecutor.execute(mCallOnDisconnected);
1975                         } finally {
1976                             Binder.restoreCallingIdentity(ident);
1977                         }
1978                         break;
1979                     case ERROR_CAMERA_REQUEST:
1980                     case ERROR_CAMERA_RESULT:
1981                     case ERROR_CAMERA_BUFFER:
1982                         onCaptureErrorLocked(errorCode, resultExtras);
1983                         break;
1984                     case ERROR_CAMERA_DEVICE:
1985                         scheduleNotifyError(StateCallback.ERROR_CAMERA_DEVICE);
1986                         break;
1987                     case ERROR_CAMERA_DISABLED:
1988                         scheduleNotifyError(StateCallback.ERROR_CAMERA_DISABLED);
1989                         break;
1990                     default:
1991                         Log.e(TAG, "Unknown error from camera device: " + errorCode);
1992                         scheduleNotifyError(StateCallback.ERROR_CAMERA_SERVICE);
1993                 }
1994             }
1995         }
1996 
scheduleNotifyError(int code)1997         private void scheduleNotifyError(int code) {
1998             mInError = true;
1999             final long ident = Binder.clearCallingIdentity();
2000             try {
2001                 CameraDeviceImpl.this.mDeviceExecutor.execute(obtainRunnable(
2002                             CameraDeviceCallbacks::notifyError, this, code).recycleOnUse());
2003             } finally {
2004                 Binder.restoreCallingIdentity(ident);
2005             }
2006         }
2007 
notifyError(int code)2008         private void notifyError(int code) {
2009             if (!CameraDeviceImpl.this.isClosed()) {
2010                 mDeviceCallback.onError(CameraDeviceImpl.this, code);
2011             }
2012         }
2013 
2014         @Override
onRepeatingRequestError(long lastFrameNumber, int repeatingRequestId)2015         public void onRepeatingRequestError(long lastFrameNumber, int repeatingRequestId) {
2016             if (DEBUG) {
2017                 Log.d(TAG, "Repeating request error received. Last frame number is " +
2018                         lastFrameNumber);
2019             }
2020 
2021             synchronized(mInterfaceLock) {
2022                 // Camera is already closed or no repeating request is present.
2023                 if (mRemoteDevice == null || mRepeatingRequestId == REQUEST_ID_NONE) {
2024                     return; // Camera already closed
2025                 }
2026 
2027                 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber,
2028                         mRepeatingRequestTypes);
2029                 // Check if there is already a new repeating request
2030                 if (mRepeatingRequestId == repeatingRequestId) {
2031                     mRepeatingRequestId = REQUEST_ID_NONE;
2032                     mRepeatingRequestTypes = null;
2033                 }
2034             }
2035         }
2036 
2037         @Override
onDeviceIdle()2038         public void onDeviceIdle() {
2039             if (DEBUG) {
2040                 Log.d(TAG, "Camera now idle");
2041             }
2042             synchronized(mInterfaceLock) {
2043                 if (mRemoteDevice == null) return; // Camera already closed
2044 
2045                 if (!CameraDeviceImpl.this.mIdle) {
2046                     final long ident = Binder.clearCallingIdentity();
2047                     try {
2048                         CameraDeviceImpl.this.mDeviceExecutor.execute(mCallOnIdle);
2049                     } finally {
2050                         Binder.restoreCallingIdentity(ident);
2051                     }
2052                 }
2053                 CameraDeviceImpl.this.mIdle = true;
2054             }
2055         }
2056 
2057         @Override
onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp)2058         public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
2059             int requestId = resultExtras.getRequestId();
2060             final long frameNumber = resultExtras.getFrameNumber();
2061 
2062             if (DEBUG) {
2063                 Log.d(TAG, "Capture started for id " + requestId + " frame number " + frameNumber);
2064             }
2065             final CaptureCallbackHolder holder;
2066 
2067             synchronized(mInterfaceLock) {
2068                 if (mRemoteDevice == null) return; // Camera already closed
2069 
2070                 // Get the callback for this frame ID, if there is one
2071                 holder = CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
2072 
2073                 if (holder == null) {
2074                     return;
2075                 }
2076 
2077                 if (isClosed()) return;
2078 
2079                 // Dispatch capture start notice
2080                 final long ident = Binder.clearCallingIdentity();
2081                 try {
2082                     holder.getExecutor().execute(
2083                         new Runnable() {
2084                             @Override
2085                             public void run() {
2086                                 if (!CameraDeviceImpl.this.isClosed()) {
2087                                     final int subsequenceId = resultExtras.getSubsequenceId();
2088                                     final CaptureRequest request = holder.getRequest(subsequenceId);
2089 
2090                                     if (holder.hasBatchedOutputs()) {
2091                                         // Send derived onCaptureStarted for requests within the
2092                                         // batch
2093                                         final Range<Integer> fpsRange =
2094                                             request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
2095                                         for (int i = 0; i < holder.getRequestCount(); i++) {
2096                                             holder.getCallback().onCaptureStarted(
2097                                                 CameraDeviceImpl.this,
2098                                                 holder.getRequest(i),
2099                                                 timestamp - (subsequenceId - i) *
2100                                                 NANO_PER_SECOND/fpsRange.getUpper(),
2101                                                 frameNumber - (subsequenceId - i));
2102                                         }
2103                                     } else {
2104                                         holder.getCallback().onCaptureStarted(
2105                                             CameraDeviceImpl.this,
2106                                             holder.getRequest(resultExtras.getSubsequenceId()),
2107                                             timestamp, frameNumber);
2108                                     }
2109                                 }
2110                             }
2111                         });
2112                 } finally {
2113                     Binder.restoreCallingIdentity(ident);
2114                 }
2115             }
2116         }
2117 
2118         @Override
onResultReceived(CameraMetadataNative result, CaptureResultExtras resultExtras, PhysicalCaptureResultInfo physicalResults[])2119         public void onResultReceived(CameraMetadataNative result,
2120                 CaptureResultExtras resultExtras, PhysicalCaptureResultInfo physicalResults[])
2121                 throws RemoteException {
2122 
2123             int requestId = resultExtras.getRequestId();
2124             long frameNumber = resultExtras.getFrameNumber();
2125 
2126             if (DEBUG) {
2127                 Log.v(TAG, "Received result frame " + frameNumber + " for id "
2128                         + requestId);
2129             }
2130 
2131             synchronized(mInterfaceLock) {
2132                 if (mRemoteDevice == null) return; // Camera already closed
2133 
2134                 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
2135                 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
2136                         getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
2137 
2138                 final CaptureCallbackHolder holder =
2139                         CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
2140                 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
2141 
2142                 boolean isPartialResult =
2143                         (resultExtras.getPartialResultCount() < mTotalPartialCount);
2144                 int requestType = request.getRequestType();
2145 
2146                 // Check if we have a callback for this
2147                 if (holder == null) {
2148                     if (DEBUG) {
2149                         Log.d(TAG,
2150                                 "holder is null, early return at frame "
2151                                         + frameNumber);
2152                     }
2153 
2154                     mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult,
2155                             requestType);
2156 
2157                     return;
2158                 }
2159 
2160                 if (isClosed()) {
2161                     if (DEBUG) {
2162                         Log.d(TAG,
2163                                 "camera is closed, early return at frame "
2164                                         + frameNumber);
2165                     }
2166 
2167                     mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult,
2168                             requestType);
2169                     return;
2170                 }
2171 
2172 
2173                 Runnable resultDispatch = null;
2174 
2175                 CaptureResult finalResult;
2176                 // Make a copy of the native metadata before it gets moved to a CaptureResult
2177                 // object.
2178                 final CameraMetadataNative resultCopy;
2179                 if (holder.hasBatchedOutputs()) {
2180                     resultCopy = new CameraMetadataNative(result);
2181                 } else {
2182                     resultCopy = null;
2183                 }
2184 
2185                 // Either send a partial result or the final capture completed result
2186                 if (isPartialResult) {
2187                     final CaptureResult resultAsCapture =
2188                             new CaptureResult(result, request, resultExtras);
2189                     // Partial result
2190                     resultDispatch = new Runnable() {
2191                         @Override
2192                         public void run() {
2193                             if (!CameraDeviceImpl.this.isClosed()) {
2194                                 if (holder.hasBatchedOutputs()) {
2195                                     // Send derived onCaptureProgressed for requests within
2196                                     // the batch.
2197                                     for (int i = 0; i < holder.getRequestCount(); i++) {
2198                                         CameraMetadataNative resultLocal =
2199                                                 new CameraMetadataNative(resultCopy);
2200                                         CaptureResult resultInBatch = new CaptureResult(
2201                                                 resultLocal, holder.getRequest(i), resultExtras);
2202 
2203                                         holder.getCallback().onCaptureProgressed(
2204                                             CameraDeviceImpl.this,
2205                                             holder.getRequest(i),
2206                                             resultInBatch);
2207                                     }
2208                                 } else {
2209                                     holder.getCallback().onCaptureProgressed(
2210                                         CameraDeviceImpl.this,
2211                                         request,
2212                                         resultAsCapture);
2213                                 }
2214                             }
2215                         }
2216                     };
2217                     finalResult = resultAsCapture;
2218                 } else {
2219                     List<CaptureResult> partialResults =
2220                             mFrameNumberTracker.popPartialResults(frameNumber);
2221 
2222                     final long sensorTimestamp =
2223                             result.get(CaptureResult.SENSOR_TIMESTAMP);
2224                     final Range<Integer> fpsRange =
2225                             request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
2226                     final int subsequenceId = resultExtras.getSubsequenceId();
2227                     final TotalCaptureResult resultAsCapture = new TotalCaptureResult(result,
2228                             request, resultExtras, partialResults, holder.getSessionId(),
2229                             physicalResults);
2230                     // Final capture result
2231                     resultDispatch = new Runnable() {
2232                         @Override
2233                         public void run() {
2234                             if (!CameraDeviceImpl.this.isClosed()){
2235                                 if (holder.hasBatchedOutputs()) {
2236                                     // Send derived onCaptureCompleted for requests within
2237                                     // the batch.
2238                                     for (int i = 0; i < holder.getRequestCount(); i++) {
2239                                         resultCopy.set(CaptureResult.SENSOR_TIMESTAMP,
2240                                                 sensorTimestamp - (subsequenceId - i) *
2241                                                 NANO_PER_SECOND/fpsRange.getUpper());
2242                                         CameraMetadataNative resultLocal =
2243                                                 new CameraMetadataNative(resultCopy);
2244                                         // No logical multi-camera support for batched output mode.
2245                                         TotalCaptureResult resultInBatch = new TotalCaptureResult(
2246                                             resultLocal, holder.getRequest(i), resultExtras,
2247                                             partialResults, holder.getSessionId(),
2248                                             new PhysicalCaptureResultInfo[0]);
2249 
2250                                         holder.getCallback().onCaptureCompleted(
2251                                             CameraDeviceImpl.this,
2252                                             holder.getRequest(i),
2253                                             resultInBatch);
2254                                     }
2255                                 } else {
2256                                     holder.getCallback().onCaptureCompleted(
2257                                         CameraDeviceImpl.this,
2258                                         request,
2259                                         resultAsCapture);
2260                                 }
2261                             }
2262                         }
2263                     };
2264                     finalResult = resultAsCapture;
2265                 }
2266 
2267                 final long ident = Binder.clearCallingIdentity();
2268                 try {
2269                     holder.getExecutor().execute(resultDispatch);
2270                 } finally {
2271                     Binder.restoreCallingIdentity(ident);
2272                 }
2273 
2274                 // Collect the partials for a total result; or mark the frame as totally completed
2275                 mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult,
2276                         requestType);
2277 
2278                 // Fire onCaptureSequenceCompleted
2279                 if (!isPartialResult) {
2280                     checkAndFireSequenceComplete();
2281                 }
2282             }
2283         }
2284 
2285         @Override
onPrepared(int streamId)2286         public void onPrepared(int streamId) {
2287             final OutputConfiguration output;
2288             final StateCallbackKK sessionCallback;
2289 
2290             if (DEBUG) {
2291                 Log.v(TAG, "Stream " + streamId + " is prepared");
2292             }
2293 
2294             synchronized(mInterfaceLock) {
2295                 output = mConfiguredOutputs.get(streamId);
2296                 sessionCallback = mSessionStateCallback;
2297             }
2298 
2299             if (sessionCallback == null) return;
2300 
2301             if (output == null) {
2302                 Log.w(TAG, "onPrepared invoked for unknown output Surface");
2303                 return;
2304             }
2305             final List<Surface> surfaces = output.getSurfaces();
2306             for (Surface surface : surfaces) {
2307                 sessionCallback.onSurfacePrepared(surface);
2308             }
2309         }
2310 
2311         @Override
onRequestQueueEmpty()2312         public void onRequestQueueEmpty() {
2313             final StateCallbackKK sessionCallback;
2314 
2315             if (DEBUG) {
2316                 Log.v(TAG, "Request queue becomes empty");
2317             }
2318 
2319             synchronized(mInterfaceLock) {
2320                 sessionCallback = mSessionStateCallback;
2321             }
2322 
2323             if (sessionCallback == null) return;
2324 
2325             sessionCallback.onRequestQueueEmpty();
2326         }
2327 
2328         /**
2329          * Called by onDeviceError for handling single-capture failures.
2330          */
onCaptureErrorLocked(int errorCode, CaptureResultExtras resultExtras)2331         private void onCaptureErrorLocked(int errorCode, CaptureResultExtras resultExtras) {
2332 
2333             final int requestId = resultExtras.getRequestId();
2334             final int subsequenceId = resultExtras.getSubsequenceId();
2335             final long frameNumber = resultExtras.getFrameNumber();
2336             final String errorPhysicalCameraId = resultExtras.getErrorPhysicalCameraId();
2337             final CaptureCallbackHolder holder =
2338                     CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
2339 
2340             final CaptureRequest request = holder.getRequest(subsequenceId);
2341 
2342             Runnable failureDispatch = null;
2343             if (errorCode == ERROR_CAMERA_BUFFER) {
2344                 // Because 1 stream id could map to multiple surfaces, we need to specify both
2345                 // streamId and surfaceId.
2346                 List<Surface> surfaces =
2347                         mConfiguredOutputs.get(resultExtras.getErrorStreamId()).getSurfaces();
2348                 for (Surface surface : surfaces) {
2349                     if (!request.containsTarget(surface)) {
2350                         continue;
2351                     }
2352                     if (DEBUG) {
2353                         Log.v(TAG, String.format("Lost output buffer reported for frame %d, target %s",
2354                                 frameNumber, surface));
2355                     }
2356                     failureDispatch = new Runnable() {
2357                         @Override
2358                         public void run() {
2359                             if (!CameraDeviceImpl.this.isClosed()){
2360                                 holder.getCallback().onCaptureBufferLost(
2361                                     CameraDeviceImpl.this,
2362                                     request,
2363                                     surface,
2364                                     frameNumber);
2365                             }
2366                         }
2367                     };
2368                     // Dispatch the failure callback
2369                     final long ident = Binder.clearCallingIdentity();
2370                     try {
2371                         holder.getExecutor().execute(failureDispatch);
2372                     } finally {
2373                         Binder.restoreCallingIdentity(ident);
2374                     }
2375                 }
2376             } else {
2377                 boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
2378 
2379                 // This is only approximate - exact handling needs the camera service and HAL to
2380                 // disambiguate between request failures to due abort and due to real errors.  For
2381                 // now, assume that if the session believes we're mid-abort, then the error is due
2382                 // to abort.
2383                 int reason = (mCurrentSession != null && mCurrentSession.isAborting()) ?
2384                         CaptureFailure.REASON_FLUSHED :
2385                         CaptureFailure.REASON_ERROR;
2386 
2387                 final CaptureFailure failure = new CaptureFailure(
2388                     request,
2389                     reason,
2390                     /*dropped*/ mayHaveBuffers,
2391                     requestId,
2392                     frameNumber,
2393                     errorPhysicalCameraId);
2394 
2395                 failureDispatch = new Runnable() {
2396                     @Override
2397                     public void run() {
2398                         if (!CameraDeviceImpl.this.isClosed()){
2399                             holder.getCallback().onCaptureFailed(
2400                                 CameraDeviceImpl.this,
2401                                 request,
2402                                 failure);
2403                         }
2404                     }
2405                 };
2406 
2407                 // Fire onCaptureSequenceCompleted if appropriate
2408                 if (DEBUG) {
2409                     Log.v(TAG, String.format("got error frame %d", frameNumber));
2410                 }
2411                 mFrameNumberTracker.updateTracker(frameNumber,
2412                         /*error*/true, request.getRequestType());
2413                 checkAndFireSequenceComplete();
2414 
2415                 // Dispatch the failure callback
2416                 final long ident = Binder.clearCallingIdentity();
2417                 try {
2418                     holder.getExecutor().execute(failureDispatch);
2419                 } finally {
2420                     Binder.restoreCallingIdentity(ident);
2421                 }
2422             }
2423 
2424         }
2425 
2426     } // public class CameraDeviceCallbacks
2427 
2428     /**
2429      * A camera specific adapter {@link Executor} that posts all executed tasks onto the given
2430      * {@link Handler}.
2431      *
2432      * @hide
2433      */
2434     private static class CameraHandlerExecutor implements Executor {
2435         private final Handler mHandler;
2436 
CameraHandlerExecutor(@onNull Handler handler)2437         public CameraHandlerExecutor(@NonNull Handler handler) {
2438             mHandler = Preconditions.checkNotNull(handler);
2439         }
2440 
2441         @Override
execute(Runnable command)2442         public void execute(Runnable command) {
2443             // Return value of 'post()' will be ignored in order to keep the
2444             // same camera behavior. For further details see b/74605221 .
2445             mHandler.post(command);
2446         }
2447     }
2448 
2449     /**
2450      * Default executor management.
2451      *
2452      * <p>
2453      * If executor is null, get the current thread's
2454      * Looper to create a Executor with. If no looper exists, throw
2455      * {@code IllegalArgumentException}.
2456      * </p>
2457      */
checkExecutor(Executor executor)2458     static Executor checkExecutor(Executor executor) {
2459         return (executor == null) ? checkAndWrapHandler(null) : executor;
2460     }
2461 
2462     /**
2463      * Default executor management.
2464      *
2465      * <p>If the callback isn't null, check the executor, otherwise pass it through.</p>
2466      */
checkExecutor(Executor executor, T callback)2467     public static <T> Executor checkExecutor(Executor executor, T callback) {
2468         return (callback != null) ? checkExecutor(executor) : executor;
2469     }
2470 
2471     /**
2472      * Wrap Handler in Executor.
2473      *
2474      * <p>
2475      * If handler is null, get the current thread's
2476      * Looper to create a Executor with. If no looper exists, throw
2477      * {@code IllegalArgumentException}.
2478      * </p>
2479      */
checkAndWrapHandler(Handler handler)2480     public static Executor checkAndWrapHandler(Handler handler) {
2481         return new CameraHandlerExecutor(checkHandler(handler));
2482     }
2483 
2484     /**
2485      * Default handler management.
2486      *
2487      * <p>
2488      * If handler is null, get the current thread's
2489      * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
2490      * </p>
2491      */
checkHandler(Handler handler)2492     static Handler checkHandler(Handler handler) {
2493         if (handler == null) {
2494             Looper looper = Looper.myLooper();
2495             if (looper == null) {
2496                 throw new IllegalArgumentException(
2497                     "No handler given, and current thread has no looper!");
2498             }
2499             handler = new Handler(looper);
2500         }
2501         return handler;
2502     }
2503 
2504     /**
2505      * Default handler management, conditional on there being a callback.
2506      *
2507      * <p>If the callback isn't null, check the handler, otherwise pass it through.</p>
2508      */
checkHandler(Handler handler, T callback)2509     static <T> Handler checkHandler(Handler handler, T callback) {
2510         if (callback != null) {
2511             return checkHandler(handler);
2512         }
2513         return handler;
2514     }
2515 
checkIfCameraClosedOrInError()2516     private void checkIfCameraClosedOrInError() throws CameraAccessException {
2517         if (mRemoteDevice == null) {
2518             throw new IllegalStateException("CameraDevice was already closed");
2519         }
2520         if (mInError) {
2521             throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
2522                     "The camera device has encountered a serious error");
2523         }
2524     }
2525 
2526     /** Whether the camera device has started to close (may not yet have finished) */
isClosed()2527     private boolean isClosed() {
2528         return mClosing.get();
2529     }
2530 
getCharacteristics()2531     private CameraCharacteristics getCharacteristics() {
2532         return mCharacteristics;
2533     }
2534 
2535     /**
2536      * Listener for binder death.
2537      *
2538      * <p> Handle binder death for ICameraDeviceUser. Trigger onError.</p>
2539      */
2540     @Override
binderDied()2541     public void binderDied() {
2542         Log.w(TAG, "CameraDevice " + mCameraId + " died unexpectedly");
2543 
2544         if (mRemoteDevice == null) {
2545             return; // Camera already closed
2546         }
2547 
2548         mInError = true;
2549         Runnable r = new Runnable() {
2550             @Override
2551             public void run() {
2552                 if (!isClosed()) {
2553                     mDeviceCallback.onError(CameraDeviceImpl.this,
2554                             StateCallback.ERROR_CAMERA_SERVICE);
2555                 }
2556             }
2557         };
2558         final long ident = Binder.clearCallingIdentity();
2559         try {
2560             CameraDeviceImpl.this.mDeviceExecutor.execute(r);
2561         } finally {
2562             Binder.restoreCallingIdentity(ident);
2563         }
2564     }
2565 }
2566