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 android.hardware.camera2.CameraAccessException; 20 import android.hardware.camera2.CameraCaptureSession; 21 import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession; 22 import android.hardware.camera2.CameraDevice; 23 import android.hardware.camera2.CaptureRequest; 24 import android.hardware.camera2.params.SessionConfiguration; 25 import android.os.Build; 26 import android.os.Handler; 27 import android.view.Surface; 28 29 import androidx.annotation.RequiresApi; 30 import androidx.camera.camera2.internal.annotation.CameraExecutor; 31 import androidx.camera.camera2.internal.compat.CameraCaptureSessionCompat; 32 import androidx.camera.camera2.internal.compat.params.OutputConfigurationCompat; 33 import androidx.camera.camera2.internal.compat.params.SessionConfigurationCompat; 34 import androidx.camera.core.impl.DeferrableSurface; 35 import androidx.camera.core.impl.Quirks; 36 37 import com.google.common.util.concurrent.ListenableFuture; 38 39 import org.jspecify.annotations.NonNull; 40 import org.jspecify.annotations.Nullable; 41 42 import java.util.List; 43 import java.util.concurrent.Executor; 44 import java.util.concurrent.ScheduledExecutorService; 45 46 /** 47 * The interface for accessing features in {@link CameraCaptureSession}. 48 * 49 * <p>The SynchronizedCaptureSession is similar to the {@link CameraCaptureSession}. Some device 50 * compatibility issues are already fixed in the SynchronizedCaptureSession. 51 * CameraX can access almost all the APIs in the CameraCaptureSession via the 52 * SynchronizedCaptureSession interface. 53 * 54 * <p>{@link SynchronizedCaptureSession} provide some extra overloaded methods that similar to the 55 * {@link CameraCaptureSession} APIs but doesn't need the Executor parameter input. These methods 56 * will automatically adopt the {@link androidx.camera.camera2.internal.annotation.CameraExecutor} 57 * if it need to use a Executor. Most use cases should attempt to call the overloaded method 58 * instead. 59 * 60 * <p>The {@link SynchronizedCaptureSession.Opener} can help to create the 61 * {@link SynchronizedCaptureSession} object. 62 * 63 * @see SynchronizedCaptureSession.Opener 64 */ 65 public interface SynchronizedCaptureSession { 66 getDevice()67 @NonNull CameraDevice getDevice(); 68 getStateCallback()69 @NonNull StateCallback getStateCallback(); 70 71 /** 72 * Get the input Surface associated with a reprocessable capture session. 73 * 74 * <p> It is only supported from API 23. Each reprocessable capture session has an input 75 * {@link Surface} where the reprocess capture requests get the input images from, rather 76 * than the camera device. The application can create a {@link android.media.ImageWriter 77 * ImageWriter} with this input {@link Surface} and use it to provide input images for 78 * reprocess capture requests. When the reprocessable capture session is closed, the input 79 * {@link Surface} is abandoned and becomes invalid.</p> 80 * 81 * @return The {@link Surface} where reprocessing capture requests get the input images from. If 82 * this is not a reprocess capture session, {@code null} will be returned. 83 * 84 * @see CameraCaptureSession#getInputSurface() 85 */ getInputSurface()86 @Nullable Surface getInputSurface(); 87 88 /** 89 * Get a {@link ListenableFuture} which indicates the task should be finished before another 90 * {@link SynchronizedCaptureSession} to be opened. 91 */ getOpeningBlocker()92 @NonNull ListenableFuture<Void> getOpeningBlocker(); 93 94 /** 95 * Return the {@link CameraCaptureSessionCompat} object which is used in this 96 * SynchronizedCaptureSession. 97 */ toCameraCaptureSessionCompat()98 @NonNull CameraCaptureSessionCompat toCameraCaptureSessionCompat(); 99 100 /** 101 * Submit a request for an image to be captured by the camera device. 102 * 103 * <p>The behavior of this method similar to the 104 * captureSingleRequest(CaptureRequest, Executor, CameraCaptureSession.CaptureCallback), 105 * except that it uses the {@link Executor} that has been set in the constructor of the 106 * SynchronizedCaptureSession. 107 * 108 * @param request the settings for this capture 109 * @param listener The callback object to notify once this request has been 110 * processed. 111 * @return int A unique capture sequence ID used by 112 * {@link CameraCaptureSession.CaptureCallback#onCaptureSequenceCompleted}. 113 * @throws CameraAccessException if the camera device is no longer connected or has 114 * encountered a fatal error 115 */ captureSingleRequest(@onNull CaptureRequest request, CameraCaptureSession.@NonNull CaptureCallback listener)116 int captureSingleRequest(@NonNull CaptureRequest request, 117 CameraCaptureSession.@NonNull CaptureCallback listener) throws CameraAccessException; 118 119 /** 120 * Submit a list of requests to be captured in sequence as a burst. The 121 * burst will be captured in the minimum amount of time possible, and will 122 * not be interleaved with requests submitted by other capture or repeat 123 * calls. 124 * 125 * <p>The behavior of this method similar to the 126 * captureBurstRequests(List, Executor, CameraCaptureSession.CaptureCallback), 127 * except that it uses the {@link Executor} that has been set in the constructor of the 128 * SynchronizedCaptureSession. 129 * 130 * @param requests the settings for this capture 131 * @param listener The callback object to notify once this request has been 132 * processed. 133 * @return int A unique capture sequence ID used by 134 * {@link CameraCaptureSession.CaptureCallback#onCaptureSequenceCompleted}. 135 * @throws CameraAccessException if the camera device is no longer connected or has 136 * encountered a fatal error 137 */ captureBurstRequests( @onNull List<CaptureRequest> requests, CameraCaptureSession.@NonNull CaptureCallback listener)138 int captureBurstRequests( 139 @NonNull List<CaptureRequest> requests, 140 CameraCaptureSession.@NonNull CaptureCallback listener) 141 throws CameraAccessException; 142 143 /** 144 * <p>Request endlessly repeating capture of a sequence of images by this capture session.</p> 145 * 146 * <p>The behavior of this method similar to the 147 * setSingleRepeatingRequest(CaptureRequest, Executor, CameraCaptureSession.CaptureCallback), 148 * except that it uses the {@link Executor} that has been set in the constructor of the 149 * SynchronizedCaptureSession. 150 * 151 * @param request the settings for this capture 152 * @param listener The callback object to notify once this request has been 153 * processed. 154 * @return int A unique capture sequence ID used by 155 * {@link CameraCaptureSession.CaptureCallback#onCaptureSequenceCompleted}. 156 * @throws CameraAccessException if the camera device is no longer connected or has 157 * encountered a fatal error 158 */ setSingleRepeatingRequest( @onNull CaptureRequest request, CameraCaptureSession.@NonNull CaptureCallback listener)159 int setSingleRepeatingRequest( 160 @NonNull CaptureRequest request, 161 CameraCaptureSession.@NonNull CaptureCallback listener) 162 throws CameraAccessException; 163 164 /** 165 * <p>Request endlessly repeating capture of a sequence of images by this capture session.</p> 166 * 167 * <p>The behavior of this method similar to the 168 * setRepeatingBurstRequests(List, Executor, CameraCaptureSession.CaptureCallback), 169 * except that it uses the {@link Executor} that has been set in the constructor of the 170 * SynchronizedCaptureSession. 171 * 172 * @param requests the settings for this capture 173 * @param listener The callback object to notify once this request has been 174 * processed. 175 * @return int A unique capture sequence ID used by 176 * {@link CameraCaptureSession.CaptureCallback#onCaptureSequenceCompleted}. 177 * @throws CameraAccessException if the camera device is no longer connected or has 178 * encountered a fatal error 179 */ setRepeatingBurstRequests( @onNull List<CaptureRequest> requests, CameraCaptureSession.@NonNull CaptureCallback listener)180 int setRepeatingBurstRequests( 181 @NonNull List<CaptureRequest> requests, 182 CameraCaptureSession.@NonNull CaptureCallback listener) 183 throws CameraAccessException; 184 185 /** 186 * Create a unmodifiable list of requests that is suitable for constrained high speed capture 187 * session streaming. 188 * 189 * @see CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList(CaptureRequest) 190 */ 191 @NonNull createHighSpeedRequestList(@onNull CaptureRequest request)192 List<CaptureRequest> createHighSpeedRequestList(@NonNull CaptureRequest request) 193 throws CameraAccessException; 194 195 /** 196 * Submit a request for an image to be captured by the camera device. 197 * 198 * <p>The behavior of this method matches that of 199 * CameraCaptureSessionCompat#captureSingleRequest(CaptureRequest, Executor, 200 * CameraCaptureSession.CaptureCallback) 201 * 202 * @param request the settings for this capture 203 * @param executor the executor which will be used for invoking the listener. 204 * @param listener The callback object to notify once this request has been processed. 205 * @return int A unique capture sequence ID used by 206 * {@link CameraCaptureSession.CaptureCallback#onCaptureSequenceCompleted}. 207 * @throws CameraAccessException if the camera device is no longer connected or has 208 * encountered a fatal error 209 */ captureSingleRequest(@onNull CaptureRequest request, @NonNull Executor executor, CameraCaptureSession.@NonNull CaptureCallback listener)210 int captureSingleRequest(@NonNull CaptureRequest request, 211 /* @CallbackExecutor */ @NonNull Executor executor, 212 CameraCaptureSession.@NonNull CaptureCallback listener) throws CameraAccessException; 213 214 /** 215 * Submit a list of requests to be captured in sequence as a burst. The burst will be 216 * captured in the minimum amount of time possible, and will not be interleaved with requests 217 * submitted by other capture or repeat calls. 218 * 219 * <p>The behavior of this method matches that of 220 * CameraCaptureSessionCompat#captureBurstRequests(List, Executor, 221 * CameraCaptureSession.CaptureCallback) 222 * 223 * @param requests the settings for this capture 224 * @param executor the executor which will be used for invoking the listener. 225 * @param listener The callback object to notify once this request has been 226 * processed. 227 * @return int A unique capture sequence ID used by 228 * {@link CameraCaptureSession.CaptureCallback#onCaptureSequenceCompleted}. 229 * @throws CameraAccessException if the camera device is no longer connected or has 230 * encountered a fatal error 231 */ captureBurstRequests( @onNull List<CaptureRequest> requests, @NonNull Executor executor, CameraCaptureSession.@NonNull CaptureCallback listener)232 int captureBurstRequests( 233 @NonNull List<CaptureRequest> requests, 234 /* @CallbackExecutor */ @NonNull Executor executor, 235 CameraCaptureSession.@NonNull CaptureCallback listener) 236 throws CameraAccessException; 237 238 /** 239 * <p>Request endlessly repeating capture of a sequence of images by this capture session.</p> 240 * 241 * <p>The behavior of this method matches that of 242 * CameraCaptureSessionCompat#setSingleRepeatingRequest(CaptureRequest, Executor, 243 * CameraCaptureSession.CaptureCallback) 244 * 245 * @param request the settings for this capture 246 * @param executor the executor which will be used for invoking the listener. 247 * @param listener The callback object to notify once this request has been 248 * processed. 249 * @return int A unique capture sequence ID used by 250 * {@link CameraCaptureSession.CaptureCallback#onCaptureSequenceCompleted}. 251 * @throws CameraAccessException if the camera device is no longer connected or has 252 * encountered a fatal error 253 */ setSingleRepeatingRequest( @onNull CaptureRequest request, @NonNull Executor executor, CameraCaptureSession.@NonNull CaptureCallback listener)254 int setSingleRepeatingRequest( 255 @NonNull CaptureRequest request, 256 /* @CallbackExecutor */ @NonNull Executor executor, 257 CameraCaptureSession.@NonNull CaptureCallback listener) 258 throws CameraAccessException; 259 260 /** 261 * <p>Request endlessly repeating capture of a sequence of images by this capture session.</p> 262 * 263 * <p>The behavior of this method matches that of 264 * CameraCaptureSessionCompat#setRepeatingBurstRequests(List, Executor, 265 * CameraCaptureSession.CaptureCallback) 266 * 267 * @param requests the settings for this capture 268 * @param executor the executor which will be used for invoking the listener. 269 * @param listener The callback object to notify once this request has been 270 * processed. 271 * @return int A unique capture sequence ID used by 272 * {@link CameraCaptureSession.CaptureCallback#onCaptureSequenceCompleted}. 273 * @throws CameraAccessException if the camera device is no longer connected or has 274 * encountered a fatal error 275 */ setRepeatingBurstRequests( @onNull List<CaptureRequest> requests, @NonNull Executor executor, CameraCaptureSession.@NonNull CaptureCallback listener)276 int setRepeatingBurstRequests( 277 @NonNull List<CaptureRequest> requests, 278 /* @CallbackExecutor */ @NonNull Executor executor, 279 CameraCaptureSession.@NonNull CaptureCallback listener) 280 throws CameraAccessException; 281 stopRepeating()282 void stopRepeating() throws CameraAccessException; 283 abortCaptures()284 void abortCaptures() throws CameraAccessException; 285 286 /** 287 * To speed up the camera switching, the close method will close the configured session and post 288 * run the {@link StateCallback#onSessionFinished(SynchronizedCaptureSession)} to 289 * inform the SynchronizedCaptureSession is already in the closed state. 290 * The {@link StateCallback#onSessionFinished(SynchronizedCaptureSession)} means the session 291 * is changed to a closed state, any further operations on this object is not acceptable. 292 */ close()293 void close(); 294 295 /** 296 * Set the session has already been completely closed. 297 * 298 * <p>This is an internal state control method for SynchronizedSession and 299 * CaptureSessionRepository, so you may not need to call this method outside. 300 */ finishClose()301 void finishClose(); 302 303 /** 304 * This method should be called when CameraDevice.StateCallback#onError happens. 305 * 306 * <p>It is used to inform the error of the CameraDevice, and should not be called for 307 * other reasons. 308 */ onCameraDeviceError(int error)309 void onCameraDeviceError(int error); 310 311 /** 312 * A callback object interface to adapting the updates from 313 * {@link CameraCaptureSession.StateCallback}. 314 * 315 * <p>This method is similar to the {@link CameraCaptureSession.StateCallback}. The main 316 * difference is users can receive the SynchronizedCaptureSession object from the callback. 317 */ 318 abstract class StateCallback { 319 onReady(@onNull SynchronizedCaptureSession session)320 void onReady(@NonNull SynchronizedCaptureSession session) { 321 322 } 323 onActive(@onNull SynchronizedCaptureSession session)324 void onActive(@NonNull SynchronizedCaptureSession session) { 325 326 } 327 328 @RequiresApi(api = Build.VERSION_CODES.O) onCaptureQueueEmpty(@onNull SynchronizedCaptureSession session)329 void onCaptureQueueEmpty(@NonNull SynchronizedCaptureSession session) { 330 331 } 332 333 @RequiresApi(api = Build.VERSION_CODES.M) onSurfacePrepared(@onNull SynchronizedCaptureSession session, @NonNull Surface surface)334 void onSurfacePrepared(@NonNull SynchronizedCaptureSession session, 335 @NonNull Surface surface) { 336 337 } 338 onConfigured(@onNull SynchronizedCaptureSession session)339 void onConfigured(@NonNull SynchronizedCaptureSession session) { 340 341 } 342 onConfigureFailed(@onNull SynchronizedCaptureSession session)343 public void onConfigureFailed(@NonNull SynchronizedCaptureSession session) { 344 345 } 346 347 /** 348 * This onClosed callback is a wrap of the CameraCaptureSession.StateCallback.onClosed, it 349 * will be invoked when: 350 * (1) CameraCaptureSession.StateCallback.onClosed is called. 351 * (2) The CameraDevice is disconnected. When the CameraDevice.StateCallback#onDisconnect 352 * is called, we will invoke this onClosed callback. Please see b/140955560. 353 * (3) When a new CameraCaptureSession is created, all the previous opened 354 * CameraCaptureSession can be treated as closed. Please see more detail in b/144817309. 355 * 356 * <p>Please note: The onClosed callback might not been called when the CameraDevice is 357 * closed before the CameraCaptureSession is closed. 358 * 359 * @param session the SynchronizedCaptureSession that is created by 360 * {@link SynchronizedCaptureSessionImpl#openCaptureSession} 361 */ onClosed(@onNull SynchronizedCaptureSession session)362 public void onClosed(@NonNull SynchronizedCaptureSession session) { 363 364 } 365 366 /** 367 * This callback will be invoked in the following condition: 368 * (1) After the {@link SynchronizedCaptureSession#close()} is called. It means the 369 * SynchronizedCaptureSession is changed to a closed state. Any further operations are not 370 * expected for this SynchronizedCaptureSession. 371 * (2) When the {@link SynchronizedCaptureSession.StateCallback#onClosed} is called. 372 * This means the session is already detached from the camera device. For 373 * example, close the camera device or open a second session, which should cause the first 374 * one to be closed. 375 * 376 * <p>This callback only would be invoked at most one time for a configured 377 * SynchronizedCaptureSession. Once the callback is called, we can treat this 378 * SynchronizedCaptureSession is no longer active and further operations on this object 379 * will fail. 380 * 381 * @param session the SynchronizedCaptureSession that is created by 382 * {@link SynchronizedCaptureSessionImpl#openCaptureSession} 383 */ onSessionFinished(@onNull SynchronizedCaptureSession session)384 void onSessionFinished(@NonNull SynchronizedCaptureSession session) { 385 386 } 387 } 388 389 /** 390 * Opener interface to open the {@link SynchronizedCaptureSession}. 391 * 392 * <p>The {@link #openCaptureSession} method can be used to open a new 393 * {@link SynchronizedCaptureSession}, and the {@link SessionConfigurationCompat} object is 394 * needed by the {@link #openCaptureSession} should be created via the 395 * {@link #createSessionConfigurationCompat}. It will send the ready-to-use 396 * {@link SynchronizedCaptureSession} to the provided listener's 397 * {@link SynchronizedCaptureSession.StateCallback#onConfigured} callback. 398 * 399 * <p>An Opener should only be used to open one SynchronizedCaptureSession. The Opener cannot be 400 * reused to open the second SynchronizedCaptureSession. The {@link #openCaptureSession} can't 401 * be called more than once in the same Opener. 402 * 403 * @see #openCaptureSession(CameraDevice, SessionConfigurationCompat, List) 404 * @see #createSessionConfigurationCompat(int, List, SynchronizedCaptureSession.StateCallback) 405 * @see SynchronizedCaptureSession.StateCallback 406 * 407 * <p>The {@link #stop} method should be invoked when the SynchronizedCaptureSession opening 408 * flow is interrupted. 409 * @see #startWithDeferrableSurface 410 * @see #stop() 411 */ 412 interface Opener { 413 414 /** 415 * Opens the SynchronizedCaptureSession. 416 * 417 * <p>The behavior of this method similar to the 418 * {@link CameraDevice#createCaptureSession(SessionConfiguration)}. It will use the 419 * input cameraDevice to create the SynchronizedCaptureSession. 420 * 421 * <p>The {@link SessionConfigurationCompat} object that is needed in this method should be 422 * created via the {@link #createSessionConfigurationCompat}. 423 * 424 * <p>The use count of the input DeferrableSurfaces will be increased. It will be 425 * automatically decreased when the surface is not used by the camera. For instance, when 426 * the opened SynchronizedCaptureSession is closed completely or when the configuration of 427 * the session is failed. 428 * 429 * <p>Cancellation of the returned future is a no-op. The opening task can only be 430 * cancelled by the {@link #stop()}. The {@link #stop()} only effective when the 431 * CameraDevice#createCaptureSession() hasn't been invoked. If the {@link #stop()} is called 432 * before the CameraDevice#createCaptureSession(), it will stop the 433 * SynchronizedCaptureSession creation. 434 * Otherwise, the SynchronizedCaptureSession will be created and the 435 * {@link SynchronizedCaptureSession.StateCallback#onConfigured} or 436 * {@link SynchronizedCaptureSession.StateCallback#onConfigureFailed} callback will be 437 * invoked. 438 * 439 * @param cameraDevice the camera with which to generate the 440 * SynchronizedCaptureSession 441 * @param sessionConfigurationCompat A {@link SessionConfigurationCompat} that is created 442 * via the {@link #createSessionConfigurationCompat}. 443 * @param deferrableSurfaces the list of the DeferrableSurface that be used to 444 * configure the session. 445 * @return a ListenableFuture object which completes when the SynchronizedCaptureSession is 446 * configured. 447 * @see #createSessionConfigurationCompat 448 * @see #stop() 449 */ openCaptureSession(@onNull CameraDevice cameraDevice, @NonNull SessionConfigurationCompat sessionConfigurationCompat, @NonNull List<DeferrableSurface> deferrableSurfaces)450 @NonNull ListenableFuture<Void> openCaptureSession(@NonNull CameraDevice cameraDevice, 451 @NonNull SessionConfigurationCompat sessionConfigurationCompat, 452 @NonNull List<DeferrableSurface> deferrableSurfaces); 453 454 /** 455 * Create the SessionConfigurationCompat for {@link #openCaptureSession} used. 456 * 457 * This method will add necessary information into the created SessionConfigurationCompat 458 * instance for SynchronizedCaptureSession. 459 * 460 * @param sessionType The session type. 461 * @param outputsCompat A list of output configurations for the SynchronizedCaptureSession. 462 * @param stateCallback A state callback interface implementation. 463 */ createSessionConfigurationCompat(int sessionType, @NonNull List<OutputConfigurationCompat> outputsCompat, SynchronizedCaptureSession.@NonNull StateCallback stateCallback)464 @NonNull SessionConfigurationCompat createSessionConfigurationCompat(int sessionType, 465 @NonNull List<OutputConfigurationCompat> outputsCompat, 466 SynchronizedCaptureSession.@NonNull StateCallback stateCallback); 467 468 /** 469 * Get the surface from the DeferrableSurfaces. 470 * 471 * <p>The {@link #startWithDeferrableSurface} method will return a Surface list that 472 * is held in the List<DeferrableSurface>. The Opener helps in maintaining the timing to 473 * close the returned DeferrableSurface list. Most use case should attempt to use the 474 * {@link #startWithDeferrableSurface} method to get the Surface for creating the 475 * SynchronizedCaptureSession. 476 * 477 * @param deferrableSurfaces The deferrable surfaces to open. 478 * @param timeout the timeout to get surfaces from the deferrable surface list. 479 * @return the Future which will contain the surface list, Cancellation of this 480 * future is a no-op. The returned Surface list can be used to create the 481 * SynchronizedCaptureSession. 482 * @see #openCaptureSession 483 * @see #stop 484 */ startWithDeferrableSurface( @onNull List<DeferrableSurface> deferrableSurfaces, long timeout)485 @NonNull ListenableFuture<List<Surface>> startWithDeferrableSurface( 486 @NonNull List<DeferrableSurface> deferrableSurfaces, long timeout); 487 488 @CameraExecutor getExecutor()489 @NonNull Executor getExecutor(); 490 491 /** 492 * Disable the startWithDeferrableSurface() and openCaptureSession() ability, and stop the 493 * startWithDeferrableSurface() and openCaptureSession() if 494 * CameraDevice#createCaptureSession() hasn't been invoked. Once the 495 * CameraDevice#createCaptureSession() already been invoked, the task of 496 * openCaptureSession() will keep going. 497 * 498 * @return true if the CameraCaptureSession creation has not been started yet. Otherwise 499 * return false. 500 */ stop()501 boolean stop(); 502 } 503 504 /** 505 * A builder to create new {@link SynchronizedCaptureSession.Opener} 506 */ 507 class OpenerBuilder { 508 509 private final Executor mExecutor; 510 private final ScheduledExecutorService mScheduledExecutorService; 511 private final Handler mCompatHandler; 512 private final CaptureSessionRepository mCaptureSessionRepository; 513 private final Quirks mCameraQuirks; 514 private final Quirks mDeviceQuirks; 515 OpenerBuilder(@ameraExecutor @onNull Executor executor, @NonNull ScheduledExecutorService scheduledExecutorService, @NonNull Handler compatHandler, @NonNull CaptureSessionRepository captureSessionRepository, @NonNull Quirks cameraQuirks, @NonNull Quirks deviceQuirks)516 OpenerBuilder(@CameraExecutor @NonNull Executor executor, 517 @NonNull ScheduledExecutorService scheduledExecutorService, 518 @NonNull Handler compatHandler, 519 @NonNull CaptureSessionRepository captureSessionRepository, 520 @NonNull Quirks cameraQuirks, 521 @NonNull Quirks deviceQuirks) { 522 mExecutor = executor; 523 mScheduledExecutorService = scheduledExecutorService; 524 mCompatHandler = compatHandler; 525 mCaptureSessionRepository = captureSessionRepository; 526 mCameraQuirks = cameraQuirks; 527 mDeviceQuirks = deviceQuirks; 528 } 529 build()530 @NonNull Opener build() { 531 return new SynchronizedCaptureSessionImpl(mCameraQuirks, mDeviceQuirks, 532 mCaptureSessionRepository, mExecutor, mScheduledExecutorService, 533 mCompatHandler); 534 } 535 } 536 } 537