1 /* 2 * Copyright 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.camera.camera2.internal; 18 19 import static java.util.Collections.emptyList; 20 21 import android.hardware.camera2.CameraAccessException; 22 import android.hardware.camera2.CameraCaptureSession; 23 import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession; 24 import android.hardware.camera2.CameraDevice; 25 import android.hardware.camera2.CaptureRequest; 26 import android.os.Build; 27 import android.os.Handler; 28 import android.view.Surface; 29 30 import androidx.annotation.GuardedBy; 31 import androidx.annotation.RequiresApi; 32 import androidx.camera.camera2.internal.annotation.CameraExecutor; 33 import androidx.camera.camera2.internal.compat.CameraCaptureSessionCompat; 34 import androidx.camera.camera2.internal.compat.CameraDeviceCompat; 35 import androidx.camera.camera2.internal.compat.params.OutputConfigurationCompat; 36 import androidx.camera.camera2.internal.compat.params.SessionConfigurationCompat; 37 import androidx.camera.core.Logger; 38 import androidx.camera.core.impl.DeferrableSurface; 39 import androidx.camera.core.impl.DeferrableSurfaces; 40 import androidx.camera.core.impl.utils.executor.CameraXExecutors; 41 import androidx.camera.core.impl.utils.futures.FutureCallback; 42 import androidx.camera.core.impl.utils.futures.FutureChain; 43 import androidx.camera.core.impl.utils.futures.Futures; 44 import androidx.concurrent.futures.CallbackToFutureAdapter; 45 import androidx.concurrent.futures.CallbackToFutureAdapter.Completer; 46 import androidx.core.util.Preconditions; 47 48 import com.google.common.util.concurrent.ListenableFuture; 49 50 import org.jspecify.annotations.NonNull; 51 import org.jspecify.annotations.Nullable; 52 53 import java.util.List; 54 import java.util.Objects; 55 import java.util.concurrent.CancellationException; 56 import java.util.concurrent.Executor; 57 import java.util.concurrent.ScheduledExecutorService; 58 59 /** 60 * The implementation of {@link SynchronizedCaptureSession} to forward the feature calls 61 * into the {@link CameraCaptureSession}. 62 * 63 * The implementation of {@link SynchronizedCaptureSession.StateCallback} and 64 * {@link SynchronizedCaptureSession.Opener} will be able to track the creation and close of the 65 * SynchronizedCaptureSession in {@link CaptureSessionRepository}. 66 * Some Quirks may be required to take some action before opening/closing other sessions, with the 67 * SynchronizedCaptureSessionBaseImpl, it would be useful when implementing the workaround of 68 * Quirks. 69 */ 70 class SynchronizedCaptureSessionBaseImpl extends SynchronizedCaptureSession.StateCallback implements 71 SynchronizedCaptureSession, SynchronizedCaptureSession.Opener { 72 73 private static final String TAG = "SyncCaptureSessionBase"; 74 75 @SuppressWarnings("WeakerAccess") /* synthetic accessor */ 76 final Object mLock = new Object(); 77 78 final @NonNull CaptureSessionRepository mCaptureSessionRepository; 79 final @NonNull Handler mCompatHandler; 80 @CameraExecutor 81 final @NonNull Executor mExecutor; 82 private final @NonNull ScheduledExecutorService mScheduledExecutorService; 83 84 @Nullable StateCallback mCaptureSessionStateCallback; 85 @Nullable CameraCaptureSessionCompat mCameraCaptureSessionCompat; 86 87 @GuardedBy("mLock") 88 @Nullable ListenableFuture<Void> mOpenCaptureSessionFuture; 89 @SuppressWarnings("WeakerAccess") /* synthetic accessor */ 90 @GuardedBy("mLock") 91 @Nullable Completer<Void> mOpenCaptureSessionCompleter; 92 93 @GuardedBy("mLock") 94 private @Nullable ListenableFuture<List<Surface>> mStartingSurface; 95 96 @GuardedBy("mLock") 97 private @Nullable List<DeferrableSurface> mHeldDeferrableSurfaces = null; 98 99 @GuardedBy("mLock") 100 private boolean mClosed = false; 101 @GuardedBy("mLock") 102 private boolean mOpenerDisabled = false; 103 @GuardedBy("mLock") 104 private boolean mSessionFinished = false; 105 SynchronizedCaptureSessionBaseImpl(@onNull CaptureSessionRepository repository, @CameraExecutor @NonNull Executor executor, @NonNull ScheduledExecutorService scheduledExecutorService, @NonNull Handler compatHandler)106 SynchronizedCaptureSessionBaseImpl(@NonNull CaptureSessionRepository repository, 107 @CameraExecutor @NonNull Executor executor, 108 @NonNull ScheduledExecutorService scheduledExecutorService, 109 @NonNull Handler compatHandler) { 110 mCaptureSessionRepository = repository; 111 mCompatHandler = compatHandler; 112 mExecutor = executor; 113 mScheduledExecutorService = scheduledExecutorService; 114 } 115 116 @Override getStateCallback()117 public @NonNull StateCallback getStateCallback() { 118 return this; 119 } 120 121 @Override getOpeningBlocker()122 public @NonNull ListenableFuture<Void> getOpeningBlocker() { 123 return Futures.immediateFuture(null); 124 } 125 126 @Override openCaptureSession(@onNull CameraDevice cameraDevice, @NonNull SessionConfigurationCompat sessionConfigurationCompat, @NonNull List<DeferrableSurface> deferrableSurfaces)127 public @NonNull ListenableFuture<Void> openCaptureSession(@NonNull CameraDevice cameraDevice, 128 @NonNull SessionConfigurationCompat sessionConfigurationCompat, 129 @NonNull List<DeferrableSurface> deferrableSurfaces) { 130 synchronized (mLock) { 131 if (mOpenerDisabled) { 132 return Futures.immediateFailedFuture( 133 new CancellationException("Opener is disabled")); 134 } 135 mCaptureSessionRepository.onCreateCaptureSession(this); 136 CameraDeviceCompat cameraDeviceCompat = 137 CameraDeviceCompat.toCameraDeviceCompat(cameraDevice, mCompatHandler); 138 mOpenCaptureSessionFuture = CallbackToFutureAdapter.getFuture(completer -> { 139 synchronized (mLock) { 140 // Attempt to set all the configured deferrable surfaces is in used 141 // before adding them to the session. 142 holdDeferrableSurfaces(deferrableSurfaces); 143 144 Preconditions.checkState(mOpenCaptureSessionCompleter == null, 145 "The openCaptureSessionCompleter can only set once!"); 146 147 mOpenCaptureSessionCompleter = completer; 148 cameraDeviceCompat.createCaptureSession(sessionConfigurationCompat); 149 return "openCaptureSession[session=" 150 + SynchronizedCaptureSessionBaseImpl.this + "]"; 151 } 152 }); 153 154 Futures.addCallback(mOpenCaptureSessionFuture, new FutureCallback<Void>() { 155 @Override 156 public void onSuccess(@Nullable Void result) { 157 // Nothing to do. 158 } 159 160 @Override 161 public void onFailure(@NonNull Throwable t) { 162 finishClose(); 163 mCaptureSessionRepository.onCaptureSessionConfigureFail( 164 SynchronizedCaptureSessionBaseImpl.this); 165 } 166 }, CameraXExecutors.directExecutor()); 167 168 return Futures.nonCancellationPropagating(mOpenCaptureSessionFuture); 169 } 170 } 171 isCameraCaptureSessionOpen()172 boolean isCameraCaptureSessionOpen() { 173 synchronized (mLock) { 174 return mOpenCaptureSessionFuture != null; 175 } 176 } 177 178 @Override createSessionConfigurationCompat( int sessionType, @NonNull List<OutputConfigurationCompat> outputsCompat, @NonNull StateCallback stateCallback)179 public @NonNull SessionConfigurationCompat createSessionConfigurationCompat( 180 int sessionType, 181 @NonNull List<OutputConfigurationCompat> outputsCompat, 182 @NonNull StateCallback stateCallback) { 183 mCaptureSessionStateCallback = stateCallback; 184 return new SessionConfigurationCompat(sessionType, outputsCompat, getExecutor(), 185 new CameraCaptureSession.StateCallback() { 186 187 @Override 188 public void onReady(@NonNull CameraCaptureSession session) { 189 createCaptureSessionCompat(session); 190 SynchronizedCaptureSessionBaseImpl.this.onReady( 191 SynchronizedCaptureSessionBaseImpl.this); 192 } 193 194 @Override 195 public void onActive(@NonNull CameraCaptureSession session) { 196 createCaptureSessionCompat(session); 197 SynchronizedCaptureSessionBaseImpl.this.onActive( 198 SynchronizedCaptureSessionBaseImpl.this); 199 } 200 201 @RequiresApi(api = Build.VERSION_CODES.O) 202 @Override 203 public void onCaptureQueueEmpty(@NonNull CameraCaptureSession session) { 204 createCaptureSessionCompat(session); 205 SynchronizedCaptureSessionBaseImpl.this.onCaptureQueueEmpty( 206 SynchronizedCaptureSessionBaseImpl.this); 207 } 208 209 @RequiresApi(api = Build.VERSION_CODES.M) 210 @Override 211 public void onSurfacePrepared( 212 @NonNull CameraCaptureSession session, 213 @NonNull Surface surface) { 214 createCaptureSessionCompat(session); 215 SynchronizedCaptureSessionBaseImpl.this.onSurfacePrepared( 216 SynchronizedCaptureSessionBaseImpl.this, surface); 217 } 218 219 @Override 220 public void onConfigured(@NonNull CameraCaptureSession session) { 221 try { 222 createCaptureSessionCompat(session); 223 SynchronizedCaptureSessionBaseImpl.this.onConfigured( 224 SynchronizedCaptureSessionBaseImpl.this); 225 } finally { 226 // Finish the mOpenCaptureSessionCompleter after callback. 227 Completer<Void> completer; 228 synchronized (mLock) { 229 Preconditions.checkNotNull(mOpenCaptureSessionCompleter, 230 "OpenCaptureSession completer should not null"); 231 completer = mOpenCaptureSessionCompleter; 232 mOpenCaptureSessionCompleter = null; 233 } 234 completer.set(null); 235 } 236 } 237 238 @Override 239 public void onConfigureFailed(@NonNull CameraCaptureSession session) { 240 try { 241 createCaptureSessionCompat(session); 242 SynchronizedCaptureSessionBaseImpl.this.onConfigureFailed( 243 SynchronizedCaptureSessionBaseImpl.this); 244 } finally { 245 // Finish the mOpenCaptureSessionCompleter after callback. 246 Completer<Void> completer; 247 synchronized (mLock) { 248 Preconditions.checkNotNull(mOpenCaptureSessionCompleter, 249 "OpenCaptureSession completer should not null"); 250 completer = mOpenCaptureSessionCompleter; 251 mOpenCaptureSessionCompleter = null; 252 } 253 completer.setException(new IllegalStateException("onConfigureFailed")); 254 } 255 } 256 257 @Override 258 public void onClosed(@NonNull CameraCaptureSession session) { 259 createCaptureSessionCompat(session); 260 SynchronizedCaptureSessionBaseImpl.this.onClosed( 261 SynchronizedCaptureSessionBaseImpl.this); 262 } 263 }); 264 } 265 266 @Override 267 @CameraExecutor 268 public @NonNull Executor getExecutor() { 269 return mExecutor; 270 } 271 272 void createCaptureSessionCompat(@NonNull CameraCaptureSession session) { 273 if (mCameraCaptureSessionCompat == null) { 274 mCameraCaptureSessionCompat = CameraCaptureSessionCompat.toCameraCaptureSessionCompat( 275 session, mCompatHandler); 276 } 277 } 278 279 @SuppressWarnings("ConstantConditions") // Implied non-null type use for surfaces. 280 @Override 281 public @NonNull ListenableFuture<List<Surface>> startWithDeferrableSurface( 282 @NonNull List<DeferrableSurface> deferrableSurfaces, long timeout) { 283 synchronized (mLock) { 284 if (mOpenerDisabled) { 285 return Futures.immediateFailedFuture( 286 new CancellationException("Opener is disabled")); 287 } 288 289 ListenableFuture<List<Surface>> future = DeferrableSurfaces.surfaceListWithTimeout( 290 deferrableSurfaces, false, timeout, getExecutor(), mScheduledExecutorService); 291 292 mStartingSurface = FutureChain.from(future).transformAsync(surfaces -> { 293 Logger.d(TAG, "[" + SynchronizedCaptureSessionBaseImpl.this + "] getSurface done " 294 + "with results: " + surfaces); 295 // If a Surface in configuredSurfaces is null it means the 296 // Surface was not retrieved from the ListenableFuture. Only 297 // handle the first failed Surface since subsequent calls to 298 // CaptureSession.open() will handle the other failed Surfaces if 299 // there are any. 300 if (surfaces.isEmpty()) { 301 return Futures.immediateFailedFuture(new IllegalArgumentException( 302 "Unable to open capture session without surfaces") 303 ); 304 } 305 if (surfaces.contains(null)) { 306 return Futures.immediateFailedFuture( 307 new DeferrableSurface.SurfaceClosedException( 308 "Surface closed", deferrableSurfaces.get(surfaces.indexOf(null)) 309 ) 310 ); 311 } 312 return Futures.immediateFuture(surfaces); 313 }, getExecutor()); 314 315 return Futures.nonCancellationPropagating(mStartingSurface); 316 } 317 } 318 319 @Override 320 public boolean stop() { 321 ListenableFuture<List<Surface>> startingSurface = null; 322 try { 323 synchronized (mLock) { 324 if (!mOpenerDisabled) { 325 if (mStartingSurface != null) { 326 startingSurface = mStartingSurface; 327 } 328 mOpenerDisabled = true; 329 } 330 331 // Return true if the CameraCaptureSession creation has not been started yet. 332 return !isCameraCaptureSessionOpen(); 333 } 334 } finally { 335 if (startingSurface != null) { 336 startingSurface.cancel(true); 337 } 338 } 339 } 340 341 @Override 342 public @NonNull CameraCaptureSessionCompat toCameraCaptureSessionCompat() { 343 Preconditions.checkNotNull(mCameraCaptureSessionCompat); 344 return mCameraCaptureSessionCompat; 345 } 346 347 @Override 348 public @NonNull CameraDevice getDevice() { 349 Preconditions.checkNotNull(mCameraCaptureSessionCompat); 350 return mCameraCaptureSessionCompat.toCameraCaptureSession().getDevice(); 351 } 352 353 @Override 354 public @Nullable Surface getInputSurface() { 355 Preconditions.checkNotNull(mCameraCaptureSessionCompat); 356 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 357 return Api23Impl.getInputSurface(mCameraCaptureSessionCompat.toCameraCaptureSession()); 358 } else { 359 return null; 360 } 361 } 362 363 @Override 364 public int captureSingleRequest(@NonNull CaptureRequest request, 365 CameraCaptureSession.@NonNull CaptureCallback listener) throws CameraAccessException { 366 Preconditions.checkNotNull(mCameraCaptureSessionCompat, "Need to call openCaptureSession " 367 + "before using this API."); 368 return mCameraCaptureSessionCompat.captureSingleRequest(request, getExecutor(), listener); 369 } 370 371 @Override 372 public int captureBurstRequests( 373 @NonNull List<CaptureRequest> requests, 374 CameraCaptureSession.@NonNull CaptureCallback listener) 375 throws CameraAccessException { 376 Preconditions.checkNotNull(mCameraCaptureSessionCompat, "Need to call openCaptureSession " 377 + "before using this API."); 378 return mCameraCaptureSessionCompat.captureBurstRequests(requests, getExecutor(), listener); 379 } 380 381 @Override 382 public int setSingleRepeatingRequest( 383 @NonNull CaptureRequest request, 384 CameraCaptureSession.@NonNull CaptureCallback listener) 385 throws CameraAccessException { 386 Preconditions.checkNotNull(mCameraCaptureSessionCompat, "Need to call openCaptureSession " 387 + "before using this API."); 388 return mCameraCaptureSessionCompat.setSingleRepeatingRequest(request, getExecutor(), 389 listener); 390 } 391 392 @Override 393 public int setRepeatingBurstRequests( 394 @NonNull List<CaptureRequest> requests, 395 CameraCaptureSession.@NonNull CaptureCallback listener) 396 throws CameraAccessException { 397 Preconditions.checkNotNull(mCameraCaptureSessionCompat, "Need to call openCaptureSession " 398 + "before using this API."); 399 return mCameraCaptureSessionCompat.setRepeatingBurstRequests(requests, getExecutor(), 400 listener); 401 } 402 403 @Override 404 @NonNull 405 public List<CaptureRequest> createHighSpeedRequestList(@NonNull CaptureRequest request) 406 throws CameraAccessException { 407 CameraCaptureSession cameraCaptureSession = 408 Preconditions.checkNotNull(mCameraCaptureSessionCompat).toCameraCaptureSession(); 409 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M 410 && cameraCaptureSession instanceof CameraConstrainedHighSpeedCaptureSession) { 411 return Api23Impl.createHighSpeedRequestList( 412 (CameraConstrainedHighSpeedCaptureSession) cameraCaptureSession, request); 413 } else { 414 return emptyList(); 415 } 416 } 417 418 @Override 419 public int captureSingleRequest(@NonNull CaptureRequest request, @NonNull Executor executor, 420 CameraCaptureSession.@NonNull CaptureCallback listener) throws CameraAccessException { 421 Preconditions.checkNotNull(mCameraCaptureSessionCompat, 422 "Need to call openCaptureSession before using this API."); 423 return mCameraCaptureSessionCompat.captureSingleRequest(request, executor, listener); 424 } 425 426 @Override 427 public int captureBurstRequests(@NonNull List<CaptureRequest> requests, 428 @NonNull Executor executor, CameraCaptureSession.@NonNull CaptureCallback listener) 429 throws CameraAccessException { 430 Preconditions.checkNotNull(mCameraCaptureSessionCompat, 431 "Need to call openCaptureSession before using this API."); 432 return mCameraCaptureSessionCompat.captureBurstRequests(requests, executor, listener); 433 } 434 435 @Override 436 public int setSingleRepeatingRequest(@NonNull CaptureRequest request, 437 @NonNull Executor executor, CameraCaptureSession.@NonNull CaptureCallback listener) 438 throws CameraAccessException { 439 Preconditions.checkNotNull(mCameraCaptureSessionCompat, 440 "Need to call openCaptureSession before using this API."); 441 return mCameraCaptureSessionCompat.setSingleRepeatingRequest(request, executor, listener); 442 } 443 444 @Override 445 public int setRepeatingBurstRequests(@NonNull List<CaptureRequest> requests, 446 @NonNull Executor executor, CameraCaptureSession.@NonNull CaptureCallback listener) 447 throws CameraAccessException { 448 Preconditions.checkNotNull(mCameraCaptureSessionCompat, 449 "Need to call openCaptureSession before using this API."); 450 return mCameraCaptureSessionCompat.setRepeatingBurstRequests(requests, executor, listener); 451 } 452 453 @Override 454 public void stopRepeating() throws CameraAccessException { 455 Preconditions.checkNotNull(mCameraCaptureSessionCompat, "Need to call openCaptureSession " 456 + "before using this API."); 457 mCameraCaptureSessionCompat.toCameraCaptureSession().stopRepeating(); 458 } 459 460 @Override 461 public void abortCaptures() throws CameraAccessException { 462 Preconditions.checkNotNull(mCameraCaptureSessionCompat, "Need to call openCaptureSession " 463 + "before using this API."); 464 mCameraCaptureSessionCompat.toCameraCaptureSession().abortCaptures(); 465 } 466 467 @Override 468 public void close() { 469 Preconditions.checkNotNull(mCameraCaptureSessionCompat, "Need to call openCaptureSession " 470 + "before using this API."); 471 mCaptureSessionRepository.onCaptureSessionClosing(this); 472 mCameraCaptureSessionCompat.toCameraCaptureSession().close(); 473 // Invoke the onSessionFinished callback directly to inform the closing 474 // step can be finished. 475 getExecutor().execute(() -> onSessionFinished(this)); 476 } 477 478 @Override 479 public void onReady(@NonNull SynchronizedCaptureSession session) { 480 Objects.requireNonNull(mCaptureSessionStateCallback); 481 mCaptureSessionStateCallback.onReady(session); 482 } 483 484 @Override 485 public void onActive(@NonNull SynchronizedCaptureSession session) { 486 Objects.requireNonNull(mCaptureSessionStateCallback); 487 mCaptureSessionStateCallback.onActive(session); 488 } 489 490 @RequiresApi(api = Build.VERSION_CODES.O) 491 @Override 492 public void onCaptureQueueEmpty(@NonNull SynchronizedCaptureSession session) { 493 Objects.requireNonNull(mCaptureSessionStateCallback); 494 mCaptureSessionStateCallback.onCaptureQueueEmpty(session); 495 } 496 497 @RequiresApi(api = Build.VERSION_CODES.M) 498 @Override 499 public void onSurfacePrepared(@NonNull SynchronizedCaptureSession session, 500 @NonNull Surface surface) { 501 Objects.requireNonNull(mCaptureSessionStateCallback); 502 mCaptureSessionStateCallback.onSurfacePrepared(session, surface); 503 } 504 505 @Override 506 public void onConfigured(@NonNull SynchronizedCaptureSession session) { 507 Objects.requireNonNull(mCaptureSessionStateCallback); 508 mCaptureSessionRepository.onCaptureSessionCreated(this); 509 mCaptureSessionStateCallback.onConfigured(session); 510 } 511 512 @Override 513 public void onConfigureFailed(@NonNull SynchronizedCaptureSession session) { 514 Objects.requireNonNull(mCaptureSessionStateCallback); 515 finishClose(); 516 mCaptureSessionRepository.onCaptureSessionConfigureFail(this); 517 mCaptureSessionStateCallback.onConfigureFailed(session); 518 } 519 520 /** 521 * The onClosed will be invoked when the CameraCaptureSession is closed or when we apply the 522 * workaround the issues like b/140955560, b/144817309 to force close the session. 523 * 524 * <p>This callback will be invoked after the SynchronizedCaptureSession#openCaptureSession 525 * is completed, and at most be called once. 526 * 527 * @param session the SynchronizedCaptureSession that is created by 528 * {@link SynchronizedCaptureSessionImpl#openCaptureSession} 529 */ 530 @Override 531 public void onClosed(@NonNull SynchronizedCaptureSession session) { 532 ListenableFuture<Void> openFuture = null; 533 synchronized (mLock) { 534 if (!mClosed) { 535 mClosed = true; 536 Preconditions.checkNotNull(mOpenCaptureSessionFuture, 537 "Need to call openCaptureSession before using this API."); 538 // Only callback onClosed after the capture session is configured. 539 openFuture = mOpenCaptureSessionFuture; 540 } 541 } 542 finishClose(); 543 if (openFuture != null) { 544 openFuture.addListener(() -> { 545 // Set the CaptureSession closed before invoke the state callback. 546 mCaptureSessionRepository.onCaptureSessionClosed( 547 SynchronizedCaptureSessionBaseImpl.this); 548 549 // Invoke the onSessionFinished since the SynchronizedCaptureSession receives 550 // the onClosed callback, we can treat this session is already in closed state. 551 onSessionFinished(session); 552 553 if (mCameraCaptureSessionCompat != null) { 554 // Only call onClosed() if we have the instance of CameraCaptureSession. 555 Objects.requireNonNull(mCaptureSessionStateCallback); 556 mCaptureSessionStateCallback.onClosed(session); 557 } else { 558 Logger.w(TAG, "[" + SynchronizedCaptureSessionBaseImpl.this + "] Cannot call " 559 + "onClosed() when the CameraCaptureSession is not correctly " 560 + "configured."); 561 } 562 }, CameraXExecutors.directExecutor()); 563 } 564 } 565 566 @Override 567 void onSessionFinished(@NonNull SynchronizedCaptureSession session) { 568 ListenableFuture<Void> openFuture = null; 569 synchronized (mLock) { 570 if (!mSessionFinished) { 571 mSessionFinished = true; 572 Preconditions.checkNotNull(mOpenCaptureSessionFuture, 573 "Need to call openCaptureSession before using this API."); 574 // Only callback onClosed after the capture session is configured. 575 openFuture = mOpenCaptureSessionFuture; 576 } 577 } 578 if (openFuture != null) { 579 openFuture.addListener(() -> { 580 Objects.requireNonNull(mCaptureSessionStateCallback); 581 mCaptureSessionStateCallback.onSessionFinished(session); 582 }, CameraXExecutors.directExecutor()); 583 } 584 } 585 586 /** 587 * Hold the DeferrableSurfaces to be used for this session to prevent the DeferrableSurfaces 588 * from being released. 589 * 590 * <p>Only one set of DeferrableSurfaces will be set to in used at the same time, it will unset 591 * the previous deferrableSurfaces if it has been set before. 592 * 593 * @param deferrableSurfaces will be set to in used. 594 * @throws DeferrableSurface.SurfaceClosedException if the deferrableSurfaces contains any 595 * closed surface. 596 */ 597 void holdDeferrableSurfaces(@NonNull List<DeferrableSurface> deferrableSurfaces) 598 throws DeferrableSurface.SurfaceClosedException { 599 synchronized (mLock) { 600 releaseDeferrableSurfaces(); 601 DeferrableSurfaces.incrementAll(deferrableSurfaces); 602 mHeldDeferrableSurfaces = deferrableSurfaces; 603 } 604 } 605 606 /** 607 * Release the DeferrableSurfaces that is held by the holdDeferrableSurfaces() 608 */ 609 void releaseDeferrableSurfaces() { 610 synchronized (mLock) { 611 if (mHeldDeferrableSurfaces != null) { 612 DeferrableSurfaces.decrementAll(mHeldDeferrableSurfaces); 613 614 // Clears the mRegisteredDeferrableSurfaces to prevent from duplicate 615 // decrement calls. 616 mHeldDeferrableSurfaces = null; 617 } 618 } 619 } 620 621 @Override 622 public void finishClose() { 623 releaseDeferrableSurfaces(); 624 } 625 626 @Override 627 public void onCameraDeviceError(int error) { 628 // Nothing to do for the default implementation. 629 } 630 631 /** 632 * Nested class to avoid verification errors for methods introduced in Android 6.0 (API 23). 633 */ 634 @RequiresApi(23) 635 private static class Api23Impl { 636 637 private Api23Impl() { 638 } 639 640 static Surface getInputSurface(CameraCaptureSession cameraCaptureSession) { 641 return cameraCaptureSession.getInputSurface(); 642 } 643 644 @NonNull 645 static List<CaptureRequest> createHighSpeedRequestList( 646 @NonNull CameraConstrainedHighSpeedCaptureSession constrainedHighSpeedSession, 647 @NonNull CaptureRequest captureRequest) 648 throws CameraAccessException { 649 return constrainedHighSpeedSession.createHighSpeedRequestList(captureRequest); 650 } 651 } 652 } 653