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