1 /*
2  * Copyright (C) 2019 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.core;
18 
19 import static androidx.camera.core.MirrorMode.MIRROR_MODE_OFF;
20 import static androidx.camera.core.MirrorMode.MIRROR_MODE_ON;
21 import static androidx.camera.core.MirrorMode.MIRROR_MODE_ON_FRONT_ONLY;
22 import static androidx.camera.core.MirrorMode.MIRROR_MODE_UNSPECIFIED;
23 import static androidx.camera.core.impl.ImageOutputConfig.OPTION_MAX_RESOLUTION;
24 import static androidx.camera.core.impl.ImageOutputConfig.OPTION_RESOLUTION_SELECTOR;
25 import static androidx.camera.core.impl.ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO;
26 import static androidx.camera.core.impl.ImageOutputConfig.OPTION_TARGET_RESOLUTION;
27 import static androidx.camera.core.impl.StreamSpec.FRAME_RATE_RANGE_UNSPECIFIED;
28 import static androidx.camera.core.impl.utils.TransformUtils.within360;
29 import static androidx.camera.core.processing.TargetUtils.isSuperset;
30 import static androidx.core.util.Preconditions.checkArgument;
31 import static androidx.core.util.Preconditions.checkArgumentInRange;
32 
33 import android.annotation.SuppressLint;
34 import android.graphics.Matrix;
35 import android.graphics.Rect;
36 import android.media.ImageReader;
37 import android.util.Range;
38 import android.util.Size;
39 import android.view.OrientationEventListener;
40 import android.view.Surface;
41 
42 import androidx.annotation.CallSuper;
43 import androidx.annotation.GuardedBy;
44 import androidx.annotation.IntRange;
45 import androidx.annotation.RestrictTo;
46 import androidx.annotation.RestrictTo.Scope;
47 import androidx.camera.core.impl.CameraControlInternal;
48 import androidx.camera.core.impl.CameraInfoInternal;
49 import androidx.camera.core.impl.CameraInternal;
50 import androidx.camera.core.impl.Config;
51 import androidx.camera.core.impl.Config.Option;
52 import androidx.camera.core.impl.DeferrableSurface;
53 import androidx.camera.core.impl.ImageOutputConfig;
54 import androidx.camera.core.impl.MutableOptionsBundle;
55 import androidx.camera.core.impl.SessionConfig;
56 import androidx.camera.core.impl.StreamSpec;
57 import androidx.camera.core.impl.UseCaseConfig;
58 import androidx.camera.core.impl.UseCaseConfigFactory;
59 import androidx.camera.core.internal.TargetConfig;
60 import androidx.camera.core.internal.compat.quirk.AeFpsRangeQuirk;
61 import androidx.camera.core.internal.utils.UseCaseConfigUtil;
62 import androidx.camera.core.resolutionselector.ResolutionSelector;
63 import androidx.camera.core.streamsharing.StreamSharing;
64 import androidx.core.util.Preconditions;
65 
66 import org.jspecify.annotations.NonNull;
67 import org.jspecify.annotations.Nullable;
68 
69 import java.util.Collections;
70 import java.util.HashSet;
71 import java.util.List;
72 import java.util.Objects;
73 import java.util.Set;
74 
75 /**
76  * The use case which all other use cases are built on top of.
77  *
78  * <p>A UseCase provides functionality to map the set of arguments in a use case to arguments
79  * that are usable by a camera. UseCase also will communicate of the active/inactive state to
80  * the Camera.
81  */
82 public abstract class UseCase {
83 
84     ////////////////////////////////////////////////////////////////////////////////////////////
85     // [UseCase lifetime constant] - Stays constant for the lifetime of the UseCase. Which means
86     // they could be created in the constructor.
87     ////////////////////////////////////////////////////////////////////////////////////////////
88 
89     /**
90      * The set of {@link StateChangeCallback} that are currently listening state transitions of this
91      * use case.
92      */
93     private final Set<StateChangeCallback> mStateChangeCallbacks = new HashSet<>();
94 
95     private final Object mCameraLock = new Object();
96 
97     ////////////////////////////////////////////////////////////////////////////////////////////
98     // [UseCase lifetime dynamic] - Dynamic variables which could change during anytime during
99     // the UseCase lifetime.
100     ////////////////////////////////////////////////////////////////////////////////////////////
101 
102     private State mState = State.INACTIVE;
103 
104     /** Extended config, applied on top of the app defined Config (mUseCaseConfig). */
105     private @Nullable UseCaseConfig<?> mExtendedConfig;
106 
107     /**
108      * Store the app defined {@link UseCaseConfig} used to create the use case.
109      */
110     private @NonNull UseCaseConfig<?> mUseCaseConfig;
111 
112     /**
113      * The currently used Config.
114      *
115      * <p> This is the combination of the extended Config, app provided Config, and camera
116      * implementation Config (with decreasing priority).
117      */
118     private @NonNull UseCaseConfig<?> mCurrentConfig;
119 
120     ////////////////////////////////////////////////////////////////////////////////////////////
121     // [UseCase attached constant] - Is only valid when the UseCase is attached to a camera.
122     ////////////////////////////////////////////////////////////////////////////////////////////
123 
124     /**
125      * The {@link StreamSpec} assigned to the {@link UseCase} based on the attached camera.
126      */
127     private StreamSpec mAttachedStreamSpec;
128 
129     /**
130      * The camera implementation provided Config. Its options has lowest priority and will be
131      * overwritten by any app defined or extended configs.
132      */
133     private @Nullable UseCaseConfig<?> mCameraConfig;
134 
135     /**
136      * The crop rect calculated at the time of binding based on {@link ViewPort}.
137      */
138     private @Nullable Rect mViewPortCropRect;
139 
140     /**
141      * The sensor to image buffer transform matrix.
142      */
143     private @NonNull Matrix mSensorToBufferTransformMatrix = new Matrix();
144 
145     @GuardedBy("mCameraLock")
146     private CameraInternal mCamera;
147 
148     @GuardedBy("mCameraLock")
149     private @Nullable CameraInternal mSecondaryCamera;
150 
151     private @Nullable CameraEffect mEffect;
152 
153     private @Nullable String mPhysicalCameraId;
154 
155     ////////////////////////////////////////////////////////////////////////////////////////////
156     // [UseCase attached dynamic] - Can change but is only available when the UseCase is attached.
157     ////////////////////////////////////////////////////////////////////////////////////////////
158 
159     // The currently attached session config
160     private @NonNull SessionConfig mAttachedSessionConfig =
161             SessionConfig.defaultEmptySessionConfig();
162 
163     // The currently attached session config for secondary camera in dual camera case
164     private @NonNull SessionConfig mAttachedSecondarySessionConfig =
165             SessionConfig.defaultEmptySessionConfig();
166 
167     /**
168      * Creates a named instance of the use case.
169      *
170      * @param currentConfig the configuration object used for this use case
171      */
172     @RestrictTo(Scope.LIBRARY_GROUP)
UseCase(@onNull UseCaseConfig<?> currentConfig)173     protected UseCase(@NonNull UseCaseConfig<?> currentConfig) {
174         mUseCaseConfig = currentConfig;
175         mCurrentConfig = currentConfig;
176     }
177 
178     /**
179      * Retrieve the default {@link UseCaseConfig} for the UseCase.
180      *
181      * @param applyDefaultConfig true if this is the base config applied to a UseCase.
182      * @param factory            the factory that contains the default UseCases.
183      * @return The UseCaseConfig or null if there is no default Config.
184      */
185     @RestrictTo(Scope.LIBRARY_GROUP)
getDefaultConfig(boolean applyDefaultConfig, @NonNull UseCaseConfigFactory factory)186     public abstract @Nullable UseCaseConfig<?> getDefaultConfig(boolean applyDefaultConfig,
187             @NonNull UseCaseConfigFactory factory);
188 
189     /**
190      * Create a {@link UseCaseConfig.Builder} for the UseCase.
191      *
192      * @param config the Config to initialize the builder
193      */
194     @RestrictTo(Scope.LIBRARY_GROUP)
getUseCaseConfigBuilder( @onNull Config config)195     public abstract UseCaseConfig.@NonNull Builder<?, ?, ?> getUseCaseConfigBuilder(
196             @NonNull Config config);
197 
198     /**
199      * Create a merged {@link UseCaseConfig} from the UseCase, camera, and an extended config.
200      *
201      * @param cameraInfo          info about the camera which may be used to resolve conflicts.
202      * @param extendedConfig      configs that take priority over the UseCase's default config
203      * @param cameraDefaultConfig configs that have lower priority than the UseCase's default.
204      *                            This Config comes from the camera implementation.
205      * @throws IllegalArgumentException if there exists conflicts in the merged config that can
206      *                                  not be resolved
207      */
208     @RestrictTo(Scope.LIBRARY_GROUP)
mergeConfigs( @onNull CameraInfoInternal cameraInfo, @Nullable UseCaseConfig<?> extendedConfig, @Nullable UseCaseConfig<?> cameraDefaultConfig)209     public @NonNull UseCaseConfig<?> mergeConfigs(
210             @NonNull CameraInfoInternal cameraInfo,
211             @Nullable UseCaseConfig<?> extendedConfig,
212             @Nullable UseCaseConfig<?> cameraDefaultConfig) {
213         MutableOptionsBundle mergedConfig;
214 
215         if (cameraDefaultConfig != null) {
216             mergedConfig = MutableOptionsBundle.from(cameraDefaultConfig);
217             mergedConfig.removeOption(TargetConfig.OPTION_TARGET_NAME);
218         } else {
219             mergedConfig = MutableOptionsBundle.create();
220         }
221 
222         // Removes the default resolution selector setting to go for the legacy resolution
223         // selection logic flow if applications call the legacy setTargetAspectRatio and
224         // setTargetResolution APIs to do the setting.
225         if (mUseCaseConfig.containsOption(OPTION_TARGET_ASPECT_RATIO)
226                 || mUseCaseConfig.containsOption(OPTION_TARGET_RESOLUTION)) {
227             if (mergedConfig.containsOption(OPTION_RESOLUTION_SELECTOR)) {
228                 mergedConfig.removeOption(OPTION_RESOLUTION_SELECTOR);
229             }
230         }
231 
232         // Removes the default max resolution setting if application sets any ResolutionStrategy
233         // to override it.
234         if (mUseCaseConfig.containsOption(OPTION_RESOLUTION_SELECTOR)
235                 && mergedConfig.containsOption(OPTION_MAX_RESOLUTION)) {
236             ResolutionSelector resolutionSelector =
237                     mUseCaseConfig.retrieveOption(OPTION_RESOLUTION_SELECTOR);
238             if (resolutionSelector.getResolutionStrategy() != null) {
239                 mergedConfig.removeOption(OPTION_MAX_RESOLUTION);
240             }
241         }
242 
243         // If any options need special handling, this is the place to do it. For now we'll just copy
244         // over all options.
245         for (Option<?> opt : mUseCaseConfig.listOptions()) {
246             Config.mergeOptionValue(mergedConfig, mergedConfig, mUseCaseConfig, opt);
247         }
248 
249         if (extendedConfig != null) {
250             // If any options need special handling, this is the place to do it. For now we'll
251             // just copy over all options.
252             for (Option<?> opt : extendedConfig.listOptions()) {
253                 @SuppressWarnings("unchecked") // Options/values are being copied directly
254                 Option<Object> objectOpt = (Option<Object>) opt;
255                 if (objectOpt.getId().equals(TargetConfig.OPTION_TARGET_NAME.getId())) {
256                     continue;
257                 }
258                 Config.mergeOptionValue(mergedConfig, mergedConfig, extendedConfig, opt);
259             }
260         }
261 
262         // If OPTION_TARGET_RESOLUTION has been set by the user, remove
263         // OPTION_TARGET_ASPECT_RATIO from defaultConfigBuilder because these two settings cannot be
264         // set at the same time.
265         if (mergedConfig.containsOption(ImageOutputConfig.OPTION_TARGET_RESOLUTION)
266                 && mergedConfig.containsOption(
267                 ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)) {
268             mergedConfig.removeOption(ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO);
269         }
270 
271         // Forces disable ZSL when high resolution is enabled.
272         if (mergedConfig.containsOption(ImageOutputConfig.OPTION_RESOLUTION_SELECTOR)
273                 && mergedConfig.retrieveOption(
274                 ImageOutputConfig.OPTION_RESOLUTION_SELECTOR).getAllowedResolutionMode()
275                 != ResolutionSelector.PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION) {
276             mergedConfig.insertOption(UseCaseConfig.OPTION_ZSL_DISABLED, true);
277         }
278 
279         return onMergeConfig(cameraInfo, getUseCaseConfigBuilder(mergedConfig));
280     }
281 
282     /**
283      * Called when a set of configs are merged so the UseCase can do additional handling.
284      *
285      * <p> This can be overridden by a UseCase which need to do additional verification of the
286      * configs to make sure there are no conflicting options.
287      *
288      * @param cameraInfo info about the camera which may be used to resolve conflicts.
289      * @param builder    the builder containing the merged configs requiring addition conflict
290      *                   resolution
291      * @return the conflict resolved config
292      * @throws IllegalArgumentException if there exists conflicts in the merged config that can
293      *                                  not be resolved
294      */
295     @RestrictTo(Scope.LIBRARY_GROUP)
onMergeConfig(@onNull CameraInfoInternal cameraInfo, UseCaseConfig.@NonNull Builder<?, ?, ?> builder)296     protected @NonNull UseCaseConfig<?> onMergeConfig(@NonNull CameraInfoInternal cameraInfo,
297             UseCaseConfig.@NonNull Builder<?, ?, ?> builder) {
298         return builder.getUseCaseConfig();
299     }
300 
301     /**
302      * A utility function that can convert the orientation degrees of
303      * {@link OrientationEventListener} to the nearest {@link Surface} rotation.
304      *
305      * <p>In general, it is best to use an {@link android.view.OrientationEventListener} to set
306      * the UseCase target rotation. This way, the rotation output will indicate which way is down
307      * for a given image or video. This is important since display orientation may be locked by
308      * device default, user setting, or app configuration, and some devices may not transition to a
309      * reverse-portrait display orientation. In these cases, set target rotation dynamically
310      * according to the {@link android.view.OrientationEventListener}, without re-creating the
311      * use case. The sample code is as below:
312      * <pre>{@code
313      * public class CameraXActivity extends AppCompatActivity {
314      *
315      *     private OrientationEventListener mOrientationEventListener;
316      *
317      *     @Override
318      *     protected void onStart() {
319      *         super.onStart();
320      *         if (mOrientationEventListener == null) {
321      *             mOrientationEventListener = new OrientationEventListener(this) {
322      *                 @Override
323      *                 public void onOrientationChanged(int orientation) {
324      *                     if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
325      *                         return;
326      *                     }
327      *                     int rotation = UseCase.snapToSurfaceRotation(orientation);
328      *                     mImageCapture.setTargetRotation(rotation);
329      *                     mImageAnalysis.setTargetRotation(rotation);
330      *                     mVideoCapture.setTargetRotation(rotation);
331      *                 }
332      *             };
333      *         }
334      *         mOrientationEventListener.enable();
335      *     }
336      *
337      *     @Override
338      *     protected void onStop() {
339      *         super.onStop();
340      *         mOrientationEventListener.disable();
341      *     }
342      * }
343      * }</pre>
344      *
345      * @param orientation the orientation degrees in range [0, 359].
346      * @return surface rotation. One of {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90},
347      * {@link Surface#ROTATION_180} and {@link Surface#ROTATION_270}.
348      * @throws IllegalArgumentException if the input orientation degrees is not in range [0, 359].
349      * @see ImageCapture#setTargetRotation(int)
350      * @see ImageAnalysis#setTargetRotation(int)
351      */
352     @ImageOutputConfig.RotationValue
snapToSurfaceRotation(@ntRangefrom = 0, to = 359) int orientation)353     public static int snapToSurfaceRotation(@IntRange(from = 0, to = 359) int orientation) {
354         checkArgumentInRange(orientation, 0, 359, "orientation");
355         if (orientation >= 315 || orientation < 45) {
356             return Surface.ROTATION_0;
357         } else if (orientation >= 225) {
358             return Surface.ROTATION_90;
359         } else if (orientation >= 135) {
360             return Surface.ROTATION_180;
361         } else {
362             return Surface.ROTATION_270;
363         }
364     }
365 
366     @RestrictTo(Scope.LIBRARY_GROUP)
setPhysicalCameraId(@onNull String physicalCameraId)367     public void setPhysicalCameraId(@NonNull String physicalCameraId) {
368         mPhysicalCameraId = physicalCameraId;
369     }
370 
371     @RestrictTo(Scope.LIBRARY_GROUP)
getPhysicalCameraId()372     public @Nullable String getPhysicalCameraId() {
373         return mPhysicalCameraId;
374     }
375 
376     /**
377      * Updates the target rotation of the use case config.
378      *
379      * @param targetRotation Target rotation of the output image, expressed as one of
380      *                       {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90},
381      *                       {@link Surface#ROTATION_180}, or {@link Surface#ROTATION_270}.
382      * @return true if the target rotation was changed.
383      */
384     @RestrictTo(Scope.LIBRARY_GROUP)
setTargetRotationInternal( @mageOutputConfig.RotationValue int targetRotation)385     protected boolean setTargetRotationInternal(
386             @ImageOutputConfig.RotationValue int targetRotation) {
387         ImageOutputConfig oldConfig = (ImageOutputConfig) getCurrentConfig();
388         int oldRotation = oldConfig.getTargetRotation(ImageOutputConfig.INVALID_ROTATION);
389         if (oldRotation == ImageOutputConfig.INVALID_ROTATION || oldRotation != targetRotation) {
390             UseCaseConfig.Builder<?, ?, ?> builder = getUseCaseConfigBuilder(mUseCaseConfig);
391             UseCaseConfigUtil.updateTargetRotationAndRelatedConfigs(builder, targetRotation);
392             mUseCaseConfig = builder.getUseCaseConfig();
393 
394             // Only merge configs if currently attached to a camera. Otherwise, set the current
395             // config to the use case config and mergeConfig() will be called once the use case
396             // is attached to a camera.
397             CameraInternal camera = getCamera();
398             if (camera == null) {
399                 mCurrentConfig = mUseCaseConfig;
400             } else {
401                 mCurrentConfig = mergeConfigs(camera.getCameraInfoInternal(), mExtendedConfig,
402                         mCameraConfig);
403             }
404 
405             return true;
406         }
407         return false;
408     }
409 
410     /**
411      * Returns the rotation that the intended target resolution is expressed in.
412      *
413      * @return The rotation of the intended target.
414      */
415     @SuppressLint("WrongConstant")
416     @RestrictTo(Scope.LIBRARY_GROUP)
417     @ImageOutputConfig.RotationValue
getTargetRotationInternal()418     protected int getTargetRotationInternal() {
419         return ((ImageOutputConfig) mCurrentConfig).getTargetRotation(Surface.ROTATION_0);
420     }
421 
422     /**
423      * Returns the target frame rate range for the associated VideoCapture use case.
424      *
425      * @return The target frame rate.
426      */
427     @RestrictTo(Scope.LIBRARY_GROUP)
getTargetFrameRateInternal()428     protected @NonNull Range<Integer> getTargetFrameRateInternal() {
429         return mCurrentConfig.getTargetFrameRate(FRAME_RATE_RANGE_UNSPECIFIED);
430     }
431 
432     /**
433      * Returns the mirror mode.
434      *
435      * <p>If mirror mode is not set, defaults to {@link MirrorMode#MIRROR_MODE_OFF}.
436      *
437      */
438     @RestrictTo(Scope.LIBRARY_GROUP)
439     @MirrorMode.Mirror
getMirrorModeInternal()440     protected int getMirrorModeInternal() {
441         return ((ImageOutputConfig) mCurrentConfig).getMirrorMode(MIRROR_MODE_UNSPECIFIED);
442     }
443 
444     /**
445      * Returns if the mirroring is required with the associated camera.
446      *
447      */
448     @RestrictTo(Scope.LIBRARY_GROUP)
isMirroringRequired(@onNull CameraInternal camera)449     public boolean isMirroringRequired(@NonNull CameraInternal camera) {
450         int mirrorMode = getMirrorModeInternal();
451         switch (mirrorMode) {
452             case MIRROR_MODE_UNSPECIFIED:
453             case MIRROR_MODE_OFF:
454                 return false;
455             case MIRROR_MODE_ON:
456                 return true;
457             case MIRROR_MODE_ON_FRONT_ONLY:
458                 return camera.isFrontFacing();
459             default:
460                 throw new AssertionError("Unknown mirrorMode: " + mirrorMode);
461         }
462     }
463 
464     /**
465      * Returns the target rotation set by apps explicitly.
466      *
467      * @return The rotation of the intended target.
468      */
469     @RestrictTo(Scope.LIBRARY_GROUP)
470     @ImageOutputConfig.OptionalRotationValue
getAppTargetRotation()471     protected int getAppTargetRotation() {
472         return ((ImageOutputConfig) mCurrentConfig)
473                 .getAppTargetRotation(ImageOutputConfig.ROTATION_NOT_SPECIFIED);
474     }
475 
476     /**
477      * Gets the relative rotation degrees without mirroring.
478      *
479      */
480     @RestrictTo(Scope.LIBRARY_GROUP)
481     @IntRange(from = 0, to = 359)
getRelativeRotation(@onNull CameraInternal cameraInternal)482     protected int getRelativeRotation(@NonNull CameraInternal cameraInternal) {
483         return getRelativeRotation(cameraInternal, /*requireMirroring=*/false);
484     }
485 
486     /**
487      * Gets the relative rotation degrees given whether the output should be mirrored.
488      *
489      */
490     @RestrictTo(Scope.LIBRARY_GROUP)
491     @IntRange(from = 0, to = 359)
getRelativeRotation(@onNull CameraInternal cameraInternal, boolean requireMirroring)492     protected int getRelativeRotation(@NonNull CameraInternal cameraInternal,
493             boolean requireMirroring) {
494         int rotation = cameraInternal.getCameraInfoInternal().getSensorRotationDegrees(
495                 getTargetRotationInternal());
496         // Parent UseCase always mirror the stream if the child requires it. No camera transform
497         // means that the stream is copied by a parent, and if the child also requires mirroring,
498         // we know that the stream has been mirrored.
499         boolean inputStreamMirrored = !cameraInternal.getHasTransform() && requireMirroring;
500         if (inputStreamMirrored) {
501             // Flip rotation if the stream has been mirrored.
502             rotation = within360(-rotation);
503         }
504         return rotation;
505     }
506 
507     /**
508      * Sets the {@link SessionConfig} that will be used by the attached {@link Camera}.
509      *
510      */
511     @RestrictTo(Scope.LIBRARY_GROUP)
updateSessionConfig(@onNull List<SessionConfig> sessionConfigs)512     protected void updateSessionConfig(@NonNull List<SessionConfig> sessionConfigs) {
513         if (sessionConfigs.isEmpty()) {
514             return;
515         }
516 
517         mAttachedSessionConfig = sessionConfigs.get(0);
518         if (sessionConfigs.size() > 1) {
519             mAttachedSecondarySessionConfig = sessionConfigs.get(1);
520         }
521 
522         for (SessionConfig sessionConfig : sessionConfigs) {
523             for (DeferrableSurface surface : sessionConfig.getSurfaces()) {
524                 if (surface.getContainerClass() == null) {
525                     surface.setContainerClass(this.getClass());
526                 }
527             }
528         }
529     }
530 
531     /**
532      * Add a {@link StateChangeCallback}, which listens to this UseCase's active and inactive
533      * transition events.
534      */
addStateChangeCallback(@onNull StateChangeCallback callback)535     private void addStateChangeCallback(@NonNull StateChangeCallback callback) {
536         mStateChangeCallbacks.add(callback);
537     }
538 
539     /**
540      * Remove a {@link StateChangeCallback} from listening to this UseCase's active and inactive
541      * transition events.
542      *
543      * <p>If the listener isn't currently listening to the UseCase then this call does nothing.
544      */
removeStateChangeCallback(@onNull StateChangeCallback callback)545     private void removeStateChangeCallback(@NonNull StateChangeCallback callback) {
546         mStateChangeCallbacks.remove(callback);
547     }
548 
549     /**
550      * Get the current {@link SessionConfig}.
551      *
552      */
553     @RestrictTo(Scope.LIBRARY_GROUP)
getSessionConfig()554     public @NonNull SessionConfig getSessionConfig() {
555         return mAttachedSessionConfig;
556     }
557 
558     /**
559      * Get the current {@link SessionConfig} of the secondary camera in dual camera case.
560      *
561      */
562     @RestrictTo(Scope.LIBRARY_GROUP)
getSecondarySessionConfig()563     public @NonNull SessionConfig getSecondarySessionConfig() {
564         return mAttachedSecondarySessionConfig;
565     }
566 
567     /**
568      * Notify all {@link StateChangeCallback} that are listening to this UseCase that it has
569      * transitioned to an active state.
570      *
571      */
572     @RestrictTo(Scope.LIBRARY_GROUP)
notifyActive()573     protected final void notifyActive() {
574         mState = State.ACTIVE;
575         notifyState();
576     }
577 
578     /**
579      * Notify all {@link StateChangeCallback} that are listening to this UseCase that it has
580      * transitioned to an inactive state.
581      *
582      */
583     @RestrictTo(Scope.LIBRARY_GROUP)
notifyInactive()584     protected final void notifyInactive() {
585         mState = State.INACTIVE;
586         notifyState();
587     }
588 
589     /**
590      * Notify all {@link StateChangeCallback} that are listening to this UseCase that the
591      * settings have been updated.
592      *
593      */
594     @RestrictTo(Scope.LIBRARY_GROUP)
notifyUpdated()595     protected final void notifyUpdated() {
596         for (StateChangeCallback stateChangeCallback : mStateChangeCallbacks) {
597             stateChangeCallback.onUseCaseUpdated(this);
598         }
599     }
600 
601     /**
602      * Notify all {@link StateChangeCallback} that are listening to this UseCase that the use
603      * case needs to be completely reset.
604      *
605      */
606     @RestrictTo(Scope.LIBRARY_GROUP)
notifyReset()607     protected final void notifyReset() {
608         for (StateChangeCallback stateChangeCallback : mStateChangeCallbacks) {
609             stateChangeCallback.onUseCaseReset(this);
610         }
611     }
612 
613     /**
614      * Notify all {@link StateChangeCallback} that are listening to this UseCase of its current
615      * state.
616      *
617      */
618     @RestrictTo(Scope.LIBRARY_GROUP)
notifyState()619     public final void notifyState() {
620         switch (mState) {
621             case INACTIVE:
622                 for (StateChangeCallback stateChangeCallback : mStateChangeCallbacks) {
623                     stateChangeCallback.onUseCaseInactive(this);
624                 }
625                 break;
626             case ACTIVE:
627                 for (StateChangeCallback stateChangeCallback : mStateChangeCallbacks) {
628                     stateChangeCallback.onUseCaseActive(this);
629                 }
630                 break;
631         }
632     }
633 
634     /**
635      * Returns the camera ID for the currently attached camera, or throws an exception if no
636      * camera is attached.
637      *
638      */
639     @RestrictTo(Scope.LIBRARY_GROUP)
getCameraId()640     protected @NonNull String getCameraId() {
641         return Preconditions.checkNotNull(getCamera(),
642                 "No camera attached to use case: " + this).getCameraInfoInternal().getCameraId();
643     }
644 
645     /**
646      * Returns the camera ID for the currently attached secondary camera, or throws an exception if
647      * no camera is attached.
648      *
649      */
650     @RestrictTo(Scope.LIBRARY_GROUP)
getSecondaryCameraId()651     protected @Nullable String getSecondaryCameraId() {
652         return getSecondaryCamera() == null ? null : getSecondaryCamera()
653                 .getCameraInfoInternal().getCameraId();
654     }
655 
656     /**
657      * Checks whether the provided camera ID is the currently attached camera ID.
658      *
659      */
660     @RestrictTo(Scope.LIBRARY_GROUP)
isCurrentCamera(@onNull String cameraId)661     protected boolean isCurrentCamera(@NonNull String cameraId) {
662         if (getCamera() == null) {
663             return false;
664         }
665         return Objects.equals(cameraId, getCameraId());
666     }
667 
668     @RestrictTo(Scope.LIBRARY_GROUP)
getName()669     public @NonNull String getName() {
670         return Objects.requireNonNull(
671                 mCurrentConfig.getTargetName("<UnknownUseCase-" + hashCode() + ">"));
672     }
673 
674     /**
675      * Retrieves the configuration set by applications.
676      */
677     @RestrictTo(Scope.LIBRARY_GROUP)
getAppConfig()678     protected @NonNull UseCaseConfig<?> getAppConfig() {
679         return mUseCaseConfig;
680     }
681 
682     /**
683      * Retrieves the configuration used by this use case.
684      *
685      * @return the configuration used by this use case.
686      */
687     @RestrictTo(Scope.LIBRARY_GROUP)
getCurrentConfig()688     public @NonNull UseCaseConfig<?> getCurrentConfig() {
689         return mCurrentConfig;
690     }
691 
692     /**
693      * Returns the currently attached {@link Camera} or {@code null} if none is attached.
694      *
695      */
696     @RestrictTo(Scope.LIBRARY_GROUP)
getCamera()697     public @Nullable CameraInternal getCamera() {
698         synchronized (mCameraLock) {
699             return mCamera;
700         }
701     }
702 
703     /**
704      * Returns the currently attached secondary {@link Camera} or {@code null} if none is attached.
705      *
706      */
707     @RestrictTo(Scope.LIBRARY_GROUP)
getSecondaryCamera()708     public @Nullable CameraInternal getSecondaryCamera() {
709         synchronized (mCameraLock) {
710             return mSecondaryCamera;
711         }
712     }
713 
714     /**
715      * Retrieves the currently attached surface resolution.
716      *
717      * @return the currently attached surface resolution for the given camera id.
718      */
719     @RestrictTo(Scope.LIBRARY_GROUP)
getAttachedSurfaceResolution()720     public @Nullable Size getAttachedSurfaceResolution() {
721         return mAttachedStreamSpec != null ? mAttachedStreamSpec.getResolution() : null;
722     }
723 
724     /**
725      * Retrieves the currently attached stream specification.
726      *
727      * @return the currently attached stream specification.
728      */
729     @RestrictTo(Scope.LIBRARY_GROUP)
getAttachedStreamSpec()730     public @Nullable StreamSpec getAttachedStreamSpec() {
731         return mAttachedStreamSpec;
732     }
733 
734     /**
735      * Offers suggested stream specification for the UseCase.
736      *
737      */
738     @RestrictTo(Scope.LIBRARY_GROUP)
updateSuggestedStreamSpec( @onNull StreamSpec primaryStreamSpec, @Nullable StreamSpec secondaryStreamSpec)739     public void updateSuggestedStreamSpec(
740             @NonNull StreamSpec primaryStreamSpec,
741             @Nullable StreamSpec secondaryStreamSpec) {
742         mAttachedStreamSpec = onSuggestedStreamSpecUpdated(
743                 primaryStreamSpec, secondaryStreamSpec);
744     }
745 
746     /**
747      * Called when binding new use cases via {@code CameraX#bindToLifecycle(LifecycleOwner,
748      * CameraSelector, UseCase...)} with additional information for dual cameras.
749      *
750      * <p>Override to create necessary objects like {@link ImageReader} depending
751      * on the stream specification.
752      *
753      * @param primaryStreamSpec The suggested stream specification that depends on camera device
754      *                            capability and what and how many use cases will be bound.
755      * @param secondaryStreamSpec The suggested stream specification for secondary camera in
756      *                            dual camera case.
757      * @return The stream specification that finally used to create the SessionConfig to
758      * attach to the camera device.
759      */
760     @RestrictTo(Scope.LIBRARY_GROUP)
onSuggestedStreamSpecUpdated( @onNull StreamSpec primaryStreamSpec, @Nullable StreamSpec secondaryStreamSpec)761     protected @NonNull StreamSpec onSuggestedStreamSpecUpdated(
762             @NonNull StreamSpec primaryStreamSpec,
763             @Nullable StreamSpec secondaryStreamSpec) {
764         return primaryStreamSpec;
765     }
766 
767     /**
768      * Update the implementation options of the stream specification for the UseCase.
769      *
770      */
771     @RestrictTo(Scope.LIBRARY_GROUP)
updateSuggestedStreamSpecImplementationOptions(@onNull Config config)772     public void updateSuggestedStreamSpecImplementationOptions(@NonNull Config config) {
773         // TODO(b/349823704): investigate whether we need mAttachedSecondaryStreamSpec for
774         //  StreamSharing
775         mAttachedStreamSpec = onSuggestedStreamSpecImplementationOptionsUpdated(config);
776     }
777 
778     /**
779      * Called when updating the stream specifications' implementation options of existing use cases
780      * via {@code CameraUseCaseAdapter#updateUseCases}.
781      *
782      * @param config The new implementationOptions for the stream specification.
783      */
784     @RestrictTo(Scope.LIBRARY_GROUP)
onSuggestedStreamSpecImplementationOptionsUpdated( @onNull Config config)785     protected @NonNull StreamSpec onSuggestedStreamSpecImplementationOptionsUpdated(
786             @NonNull Config config) {
787         if (mAttachedStreamSpec == null) {
788             throw new UnsupportedOperationException("Attempt to update the implementation options "
789                     + "for a use case without attached stream specifications.");
790         }
791         return mAttachedStreamSpec.toBuilder().setImplementationOptions(config).build();
792     }
793 
794 
795     /**
796      * Called when CameraControlInternal is attached into the UseCase. UseCase may need to
797      * override this method to configure the CameraControlInternal here. Ex. Setting correct flash
798      * mode by CameraControlInternal.setFlashMode to enable correct AE mode and flash state.
799      *
800      */
801     @RestrictTo(Scope.LIBRARY_GROUP)
onCameraControlReady()802     public void onCameraControlReady() {
803     }
804 
805     /**
806      * Binds use case to a camera.
807      *
808      * <p>Before a use case can receive frame data, it needs to establish association with the
809      * target camera first. An implementation of {@link CameraInternal} (e.g. a lifecycle camera
810      * or lifecycle-less camera) is provided when
811      * {@link #bindToCamera(CameraInternal, CameraInternal, UseCaseConfig, UseCaseConfig)} is
812      * invoked, so that the use case can retrieve the necessary information from the camera
813      * to calculate and set up the configs.
814      *
815      * <p>The default, extended and camera config settings are also applied to the use case config
816      * in this stage. Subclasses can override {@link #onMergeConfig} to update the use case
817      * config for use case specific purposes.
818      *
819      * <p>Calling {@link #getCameraControl()} can retrieve a real {@link CameraControlInternal}
820      * implementation of the associated camera after this function is invoked. Otherwise, a fake
821      * no-op {@link CameraControlInternal} implementation is returned by
822      * {@link #getCameraControl()} function.
823      */
824     @SuppressLint("WrongConstant")
825     @RestrictTo(Scope.LIBRARY_GROUP)
bindToCamera(@onNull CameraInternal camera, @Nullable CameraInternal secondaryCamera, @Nullable UseCaseConfig<?> extendedConfig, @Nullable UseCaseConfig<?> cameraConfig)826     public final void bindToCamera(@NonNull CameraInternal camera,
827             @Nullable CameraInternal secondaryCamera,
828             @Nullable UseCaseConfig<?> extendedConfig,
829             @Nullable UseCaseConfig<?> cameraConfig) {
830         synchronized (mCameraLock) {
831             mCamera = camera;
832             mSecondaryCamera = secondaryCamera;
833             addStateChangeCallback(camera);
834             if (secondaryCamera != null) {
835                 addStateChangeCallback(secondaryCamera);
836             }
837         }
838 
839         mExtendedConfig = extendedConfig;
840         mCameraConfig = cameraConfig;
841         mCurrentConfig = mergeConfigs(camera.getCameraInfoInternal(), mExtendedConfig,
842                 mCameraConfig);
843         onBind();
844     }
845 
846     /**
847      * Called when use case is binding to a camera.
848      *
849      * <p>Subclasses can override this callback function to create the necessary objects to
850      * make the use case work correctly.
851      *
852      * <p>After this function is invoked, CameraX will also provide the selected resolution
853      * information to subclasses via {@link #onSuggestedStreamSpecUpdated}. Subclasses should
854      * override it to set up the pipeline according to the selected resolution, so that UseCase
855      * becomes ready to receive data from the camera.
856      *
857      */
858     @RestrictTo(Scope.LIBRARY_GROUP)
onBind()859     public void onBind() {
860     }
861 
862     /**
863      * Unbinds use case from a camera.
864      *
865      * <p>The use case de-associates from the camera. Before this function is invoked, the use
866      * case must have been detached from the camera. So that the {@link CameraInternal}
867      * implementation can remove the related resource (e.g. surface) from the working capture
868      * session. Then, when this function is invoked, the use case can also clear all objects and
869      * settings to initial state like it is never bound to a camera.
870      *
871      * <p>After this function is invoked, calling {@link #getCameraControl()} returns a fake no-op
872      * {@link CameraControlInternal} implementation.
873      *
874      */
875     @RestrictTo(Scope.LIBRARY)
unbindFromCamera(@onNull CameraInternal camera)876     public final void unbindFromCamera(@NonNull CameraInternal camera) {
877         // Do any cleanup required by the UseCase implementation
878         onUnbind();
879 
880         synchronized (mCameraLock) {
881             if (camera == mCamera) {
882                 removeStateChangeCallback(mCamera);
883                 mCamera = null;
884             }
885 
886             if (camera == mSecondaryCamera) {
887                 removeStateChangeCallback(mSecondaryCamera);
888                 mSecondaryCamera = null;
889             }
890         }
891 
892         mAttachedStreamSpec = null;
893         mViewPortCropRect = null;
894 
895         // Resets the mUseCaseConfig to the initial status when the use case was created to make
896         // the use case reusable.
897         mCurrentConfig = mUseCaseConfig;
898         mExtendedConfig = null;
899         mCameraConfig = null;
900     }
901 
902     /**
903      * Called when use case is unbinding from a camera.
904      *
905      * <p>Subclasses can override this callback function to clear the objects created for
906      * their specific purposes.
907      *
908      */
909     @RestrictTo(Scope.LIBRARY_GROUP)
onUnbind()910     public void onUnbind() {
911     }
912 
913     /**
914      * Called when use case is attached to the camera. This method is called on main thread.
915      *
916      * <p>Once this function is invoked, the use case is attached to the {@link CameraInternal}
917      * implementation of the associated camera. CameraX starts to open the camera and capture
918      * session with the use case session config. The use case can receive the frame data from the
919      * camera after the capture session is configured.
920      *
921      */
922     @RestrictTo(Scope.LIBRARY_GROUP)
923     @CallSuper
onStateAttached()924     public void onStateAttached() {
925     }
926 
927     /**
928      * Called when use case is detached from the camera. This method is called on main thread.
929      *
930      * <p>Once this function is invoked, the use case is detached from the {@link CameraInternal}
931      * implementation of the associated camera. The use case no longer receives frame data from
932      * the camera.
933      *
934      */
935     @RestrictTo(Scope.LIBRARY_GROUP)
onStateDetached()936     public void onStateDetached() {
937     }
938 
939     /**
940      * Retrieves a previously attached {@link CameraControlInternal}.
941      *
942      */
943     @RestrictTo(Scope.LIBRARY_GROUP)
getCameraControl()944     protected @NonNull CameraControlInternal getCameraControl() {
945         synchronized (mCameraLock) {
946             if (mCamera == null) {
947                 return CameraControlInternal.DEFAULT_EMPTY_INSTANCE;
948             }
949             return mCamera.getCameraControlInternal();
950         }
951     }
952 
953     /**
954      * Sets the view port crop rect calculated at the time of binding.
955      *
956      */
957     @RestrictTo(Scope.LIBRARY_GROUP)
958     @CallSuper
setViewPortCropRect(@onNull Rect viewPortCropRect)959     public void setViewPortCropRect(@NonNull Rect viewPortCropRect) {
960         mViewPortCropRect = viewPortCropRect;
961     }
962 
963     /**
964      * Sets the {@link CameraEffect} associated with this use case.
965      *
966      * @throws IllegalArgumentException if the effect targets are not supported by this use case.
967      */
968     @RestrictTo(Scope.LIBRARY_GROUP)
setEffect(@ullable CameraEffect effect)969     public void setEffect(@Nullable CameraEffect effect) {
970         checkArgument(effect == null || isEffectTargetsSupported(effect.getTargets()));
971         mEffect = effect;
972     }
973 
974     /**
975      * Gets the {@link CameraEffect} associated with this use case.
976      *
977      */
978     @RestrictTo(Scope.LIBRARY_GROUP)
getEffect()979     public @Nullable CameraEffect getEffect() {
980         return mEffect;
981     }
982 
983     /**
984      * Gets the view port crop rect.
985      *
986      */
987     @RestrictTo(Scope.LIBRARY_GROUP)
getViewPortCropRect()988     public @Nullable Rect getViewPortCropRect() {
989         return mViewPortCropRect;
990     }
991 
992     /**
993      * Sets the sensor to image buffer transform matrix.
994      *
995      */
996     @RestrictTo(Scope.LIBRARY_GROUP)
997     @CallSuper
setSensorToBufferTransformMatrix(@onNull Matrix sensorToBufferTransformMatrix)998     public void setSensorToBufferTransformMatrix(@NonNull Matrix sensorToBufferTransformMatrix) {
999         mSensorToBufferTransformMatrix = new Matrix(sensorToBufferTransformMatrix);
1000     }
1001 
1002     /**
1003      * Gets the sensor to image buffer transform matrix.
1004      *
1005      */
1006     @RestrictTo(Scope.LIBRARY_GROUP)
getSensorToBufferTransformMatrix()1007     public @NonNull Matrix getSensorToBufferTransformMatrix() {
1008         return mSensorToBufferTransformMatrix;
1009     }
1010 
1011     /**
1012      * Get image format for the use case.
1013      *
1014      * @return image format for the use case
1015      */
1016     @RestrictTo(Scope.LIBRARY_GROUP)
getImageFormat()1017     public int getImageFormat() {
1018         return mCurrentConfig.getInputFormat();
1019     }
1020 
1021     /**
1022      * Returns a new {@link ResolutionInfo} according to the latest settings of the use case, or
1023      * null if the use case is not bound yet.
1024      *
1025      * <p>This allows the subclasses to return different {@link ResolutionInfo} according to its
1026      * different design.
1027      *
1028      */
1029     @RestrictTo(Scope.LIBRARY_GROUP)
getResolutionInfoInternal()1030     protected @Nullable ResolutionInfo getResolutionInfoInternal() {
1031         CameraInternal camera = getCamera();
1032         Size resolution = getAttachedSurfaceResolution();
1033 
1034         if (camera == null || resolution == null) {
1035             return null;
1036         }
1037 
1038         Rect cropRect = getViewPortCropRect();
1039 
1040         if (cropRect == null) {
1041             cropRect = new Rect(0, 0, resolution.getWidth(), resolution.getHeight());
1042         }
1043 
1044         int rotationDegrees = getRelativeRotation(camera);
1045 
1046         return new ResolutionInfo(resolution, cropRect, rotationDegrees);
1047     }
1048 
1049     /**
1050      * A set of {@link CameraEffect.Targets} bitmasks supported by the {@link UseCase}.
1051      *
1052      * <p>To apply the {@link CameraEffect} on the {@link UseCase} or one of its ancestors,
1053      * {@link CameraEffect#getTargets()} must be a superset of at least one of the bitmask. For
1054      * example:
1055      * <ul>
1056      * <li>For {@link Preview}, the set only contains [PREVIEW]. {@link Preview} and its ancestors
1057      * supports effects that are supersets of [PREVIEW]: PREVIEW, PREVIEW|VIDEO_CAPTURE, or
1058      * PREVIEW|VIDEO_CAPTURE|IMAGE_CAPTURE. A {@link CameraEffect} that does not target PREVIEW
1059      * cannot be applied to {@link Preview} or its ancestors.
1060      * <li>For {@link StreamSharing}, the set contains [PREVIEW|VIDEO_CAPTURE].
1061      * {@link StreamSharing} supports effects with targets PREVIEW|VIDEO_CAPTURE or
1062      * PREVIEW|VIDEO_CAPTURE|IMAGE_CAPTURE.
1063      * </ul>
1064      *
1065      * <p>The method returns an empty set if this {@link UseCase} does not support effects. By
1066      * default, this method returns an empty set.
1067      *
1068      */
1069     @RestrictTo(Scope.LIBRARY_GROUP)
getSupportedEffectTargets()1070     protected @NonNull Set<Integer> getSupportedEffectTargets() {
1071         return Collections.emptySet();
1072     }
1073 
1074     /**
1075      * Returns whether the targets can be applied to this {@link UseCase} or one of its ancestors.
1076      *
1077      * @see #getSupportedEffectTargets()
1078      */
1079     @RestrictTo(Scope.LIBRARY_GROUP)
isEffectTargetsSupported(@ameraEffect.Targets int effectTargets)1080     public boolean isEffectTargetsSupported(@CameraEffect.Targets int effectTargets) {
1081         for (Integer useCaseTargets : getSupportedEffectTargets()) {
1082             if (isSuperset(effectTargets, useCaseTargets)) {
1083                 return true;
1084             }
1085         }
1086         return false;
1087     }
1088 
1089     /**
1090      * Applies the AE fps range to the session config builder according to the stream spec and
1091      * quirk values.
1092      */
1093     @RestrictTo(Scope.LIBRARY_GROUP)
applyExpectedFrameRateRange(SessionConfig.@onNull Builder sessionConfigBuilder, @NonNull StreamSpec streamSpec)1094     protected void applyExpectedFrameRateRange(SessionConfig.@NonNull Builder sessionConfigBuilder,
1095             @NonNull StreamSpec streamSpec) {
1096         // Directly applies the apps' setting if the value is not FRAME_RATE_RANGE_UNSPECIFIED
1097         if (!FRAME_RATE_RANGE_UNSPECIFIED.equals(streamSpec.getExpectedFrameRateRange())) {
1098             sessionConfigBuilder.setExpectedFrameRateRange(streamSpec.getExpectedFrameRateRange());
1099             return;
1100         }
1101 
1102         synchronized (mCameraLock) {
1103             CameraInfoInternal cameraInfoInternal = Preconditions.checkNotNull(
1104                     mCamera).getCameraInfoInternal();
1105             List<AeFpsRangeQuirk> aeFpsRangeQuirks = cameraInfoInternal.getCameraQuirks().getAll(
1106                     AeFpsRangeQuirk.class);
1107             Preconditions.checkArgument(aeFpsRangeQuirks.size() <= 1,
1108                     "There should not have more than one AeFpsRangeQuirk.");
1109 
1110             if (!aeFpsRangeQuirks.isEmpty()) {
1111                 sessionConfigBuilder.setExpectedFrameRateRange(
1112                         aeFpsRangeQuirks.get(0).getTargetAeFpsRange());
1113             }
1114         }
1115     }
1116 
1117     enum State {
1118         /** Currently waiting for image data. */
1119         ACTIVE,
1120         /** Currently not waiting for image data. */
1121         INACTIVE
1122     }
1123 
1124     /**
1125      * Callback for when a {@link UseCase} transitions between active/inactive states.
1126      *
1127      */
1128     @RestrictTo(Scope.LIBRARY_GROUP)
1129     public interface StateChangeCallback {
1130         /**
1131          * Called when a {@link UseCase} becomes active.
1132          *
1133          * <p>When a UseCase is active it expects that all data producers attached to itself
1134          * should start producing data for it to consume. In addition the UseCase will start
1135          * producing data that other classes can be consumed.
1136          */
onUseCaseActive(@onNull UseCase useCase)1137         void onUseCaseActive(@NonNull UseCase useCase);
1138 
1139         /**
1140          * Called when a {@link UseCase} becomes inactive.
1141          *
1142          * <p>When a UseCase is inactive it no longer expects data to be produced for it. In
1143          * addition the UseCase will stop producing data for other classes to consume.
1144          */
onUseCaseInactive(@onNull UseCase useCase)1145         void onUseCaseInactive(@NonNull UseCase useCase);
1146 
1147         /**
1148          * Called when a {@link UseCase} has updated settings.
1149          *
1150          * <p>When a {@link UseCase} has updated settings, it is expected that the listener will
1151          * use these updated settings to reconfigure the listener's own state. A settings update is
1152          * orthogonal to the active/inactive state change.
1153          */
onUseCaseUpdated(@onNull UseCase useCase)1154         void onUseCaseUpdated(@NonNull UseCase useCase);
1155 
1156         /**
1157          * Called when a {@link UseCase} has updated settings that require complete reset of the
1158          * camera.
1159          *
1160          * <p>Updating certain parameters of the use case require a full reset of the camera. This
1161          * includes updating the {@link Surface} used by the use case.
1162          */
onUseCaseReset(@onNull UseCase useCase)1163         void onUseCaseReset(@NonNull UseCase useCase);
1164     }
1165 }
1166