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