java.lang.Object
↳androidx.camera.core.UseCase
Subclasses:
VideoCapture, Preview, ImageAnalysis, ImageCapture, StreamSharing, VideoCapture<T>
Gradle dependencies
compile group: 'androidx.camera', name: 'camera-core', version: '1.5.0-alpha01'
- groupId: androidx.camera
- artifactId: camera-core
- version: 1.5.0-alpha01
Artifact androidx.camera:camera-core:1.5.0-alpha01 it located at Google repository (https://maven.google.com/)
Overview
The use case which all other use cases are built on top of.
A UseCase provides functionality to map the set of arguments in a use case to arguments
that are usable by a camera. UseCase also will communicate of the active/inactive state to
the Camera.
Summary
Constructors |
---|
protected | UseCase(UseCaseConfig<UseCase> currentConfig)
Creates a named instance of the use case. |
Methods |
---|
public final void | bindToCamera(CameraInternal camera, CameraInternal secondaryCamera, UseCaseConfig<UseCase> extendedConfig, UseCaseConfig<UseCase> cameraConfig)
Binds use case to a camera. |
protected UseCaseConfig<UseCase> | getAppConfig()
Retrieves the configuration set by applications. |
protected int | getAppTargetRotation()
Returns the target rotation set by apps explicitly. |
public StreamSpec | getAttachedStreamSpec()
Retrieves the currently attached stream specification. |
public Size | getAttachedSurfaceResolution()
Retrieves the currently attached surface resolution. |
public CameraInternal | getCamera()
Returns the currently attached Camera or null if none is attached. |
protected CameraControlInternal | getCameraControl()
Retrieves a previously attached CameraControlInternal. |
protected java.lang.String | getCameraId()
Returns the camera ID for the currently attached camera, or throws an exception if no
camera is attached. |
public UseCaseConfig<UseCase> | getCurrentConfig()
Retrieves the configuration used by this use case. |
public abstract UseCaseConfig<UseCase> | getDefaultConfig(boolean applyDefaultConfig, UseCaseConfigFactory factory)
Retrieve the default UseCaseConfig for the UseCase. |
public CameraEffect | getEffect()
Gets the CameraEffect associated with this use case. |
public int | getImageFormat()
Get image format for the use case. |
protected int | getMirrorModeInternal()
Returns the mirror mode. |
public java.lang.String | getName()
|
public java.lang.String | getPhysicalCameraId()
|
protected int | getRelativeRotation(CameraInternal cameraInternal)
Gets the relative rotation degrees without mirroring. |
protected int | getRelativeRotation(CameraInternal cameraInternal, boolean requireMirroring)
Gets the relative rotation degrees given whether the output should be mirrored. |
protected ResolutionInfo | getResolutionInfoInternal()
Returns a new ResolutionInfo according to the latest settings of the use case, or
null if the use case is not bound yet. |
public CameraInternal | getSecondaryCamera()
Returns the currently attached secondary Camera or null if none is attached. |
protected java.lang.String | getSecondaryCameraId()
Returns the camera ID for the currently attached secondary camera, or throws an exception if
no camera is attached. |
public SessionConfig | getSecondarySessionConfig()
Get the current SessionConfig of the secondary camera in dual camera case. |
public Matrix | getSensorToBufferTransformMatrix()
Gets the sensor to image buffer transform matrix. |
public SessionConfig | getSessionConfig()
Get the current SessionConfig. |
protected java.util.Set<java.lang.Integer> | getSupportedEffectTargets()
A set of CameraEffect.Targets bitmasks supported by the UseCase. |
protected <any> | getTargetFrameRateInternal()
Returns the target frame rate range for the associated VideoCapture use case. |
protected int | getTargetRotationInternal()
Returns the rotation that the intended target resolution is expressed in. |
public abstract UseCaseConfig.Builder<UseCase, UseCaseConfig, java.lang.Object> | getUseCaseConfigBuilder(Config config)
Create a UseCaseConfig.Builder for the UseCase. |
public Rect | getViewPortCropRect()
Gets the view port crop rect. |
protected boolean | isCurrentCamera(java.lang.String cameraId)
Checks whether the provided camera ID is the currently attached camera ID. |
public boolean | isEffectTargetsSupported(int effectTargets)
Returns whether the targets can be applied to this UseCase or one of its ancestors. |
public boolean | isMirroringRequired(CameraInternal camera)
Returns if the mirroring is required with the associated camera. |
public UseCaseConfig<UseCase> | mergeConfigs(CameraInfoInternal cameraInfo, UseCaseConfig<UseCase> extendedConfig, UseCaseConfig<UseCase> cameraDefaultConfig)
Create a merged UseCaseConfig from the UseCase, camera, and an extended config. |
protected final void | notifyActive()
Notify all UseCase.StateChangeCallback that are listening to this UseCase that it has
transitioned to an active state. |
protected final void | notifyInactive()
Notify all UseCase.StateChangeCallback that are listening to this UseCase that it has
transitioned to an inactive state. |
protected final void | notifyReset()
Notify all UseCase.StateChangeCallback that are listening to this UseCase that the use
case needs to be completely reset. |
public final void | notifyState()
Notify all UseCase.StateChangeCallback that are listening to this UseCase of its current
state. |
protected final void | notifyUpdated()
Notify all UseCase.StateChangeCallback that are listening to this UseCase that the
settings have been updated. |
public void | onBind()
Called when use case is binding to a camera. |
public void | onCameraControlReady()
Called when CameraControlInternal is attached into the UseCase. |
protected UseCaseConfig<UseCase> | onMergeConfig(CameraInfoInternal cameraInfo, UseCaseConfig.Builder<UseCase, UseCaseConfig, java.lang.Object> builder)
Called when a set of configs are merged so the UseCase can do additional handling. |
public void | onStateAttached()
Called when use case is attached to the camera. |
public void | onStateDetached()
Called when use case is detached from the camera. |
protected StreamSpec | onSuggestedStreamSpecImplementationOptionsUpdated(Config config)
Called when updating the stream specifications' implementation options of existing use cases
via CameraUseCaseAdapter#updateUseCases. |
protected StreamSpec | onSuggestedStreamSpecUpdated(StreamSpec primaryStreamSpec, StreamSpec secondaryStreamSpec)
Called when binding new use cases via CameraX#bindToLifecycle(LifecycleOwner,
CameraSelector, UseCase...) with additional information for dual cameras. |
public void | onUnbind()
Called when use case is unbinding from a camera. |
public void | setEffect(CameraEffect effect)
Sets the CameraEffect associated with this use case. |
public void | setPhysicalCameraId(java.lang.String physicalCameraId)
|
public void | setSensorToBufferTransformMatrix(Matrix sensorToBufferTransformMatrix)
Sets the sensor to image buffer transform matrix. |
protected boolean | setTargetRotationInternal(int targetRotation)
Updates the target rotation of the use case config. |
public void | setViewPortCropRect(Rect viewPortCropRect)
Sets the view port crop rect calculated at the time of binding. |
public static int | snapToSurfaceRotation(int orientation)
A utility function that can convert the orientation degrees of
to the nearest rotation. |
public final void | unbindFromCamera(CameraInternal camera)
Unbinds use case from a camera. |
protected void | updateSessionConfig(java.util.List<SessionConfig> sessionConfigs)
Sets the SessionConfig that will be used by the attached Camera. |
public void | updateSuggestedStreamSpec(StreamSpec primaryStreamSpec, StreamSpec secondaryStreamSpec)
Offers suggested stream specification for the UseCase. |
public void | updateSuggestedStreamSpecImplementationOptions(Config config)
Update the implementation options of the stream specification for the UseCase. |
from java.lang.Object | clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Constructors
Creates a named instance of the use case.
Parameters:
currentConfig: the configuration object used for this use case
Methods
Retrieve the default UseCaseConfig for the UseCase.
Parameters:
applyDefaultConfig: true if this is the base config applied to a UseCase.
factory: the factory that contains the default UseCases.
Returns:
The UseCaseConfig or null if there is no default Config.
Create a UseCaseConfig.Builder for the UseCase.
Parameters:
config: the Config to initialize the builder
Create a merged UseCaseConfig from the UseCase, camera, and an extended config.
Parameters:
cameraInfo: info about the camera which may be used to resolve conflicts.
extendedConfig: configs that take priority over the UseCase's default config
cameraDefaultConfig: configs that have lower priority than the UseCase's default.
This Config comes from the camera implementation.
Called when a set of configs are merged so the UseCase can do additional handling.
This can be overridden by a UseCase which need to do additional verification of the
configs to make sure there are no conflicting options.
Parameters:
cameraInfo: info about the camera which may be used to resolve conflicts.
builder: the builder containing the merged configs requiring addition conflict
resolution
Returns:
the conflict resolved config
public static int
snapToSurfaceRotation(int orientation)
A utility function that can convert the orientation degrees of
to the nearest rotation.
In general, it is best to use an to set
the UseCase target rotation. This way, the rotation output will indicate which way is down
for a given image or video. This is important since display orientation may be locked by
device default, user setting, or app configuration, and some devices may not transition to a
reverse-portrait display orientation. In these cases, set target rotation dynamically
according to the , without re-creating the
use case. The sample code is as below:
{@code
public class CameraXActivity extends AppCompatActivity {
private OrientationEventListener mOrientationEventListener;Parameters:
orientation: the orientation degrees in range [0, 359].
Returns:
surface rotation. One of , ,
and .
See also: ImageCapture.setTargetRotation(int), ImageAnalysis.setTargetRotation(int)
public void
setPhysicalCameraId(java.lang.String physicalCameraId)
public java.lang.String
getPhysicalCameraId()
protected boolean
setTargetRotationInternal(int targetRotation)
Updates the target rotation of the use case config.
Parameters:
targetRotation: Target rotation of the output image, expressed as one of
, ,
, or .
Returns:
true if the target rotation was changed.
protected int
getTargetRotationInternal()
Returns the rotation that the intended target resolution is expressed in.
Returns:
The rotation of the intended target.
protected <any>
getTargetFrameRateInternal()
Returns the target frame rate range for the associated VideoCapture use case.
Returns:
The target frame rate.
protected int
getMirrorModeInternal()
Returns the mirror mode.
If mirror mode is not set, defaults to MirrorMode.MIRROR_MODE_OFF.
Returns if the mirroring is required with the associated camera.
protected int
getAppTargetRotation()
Returns the target rotation set by apps explicitly.
Returns:
The rotation of the intended target.
Gets the relative rotation degrees without mirroring.
protected int
getRelativeRotation(
CameraInternal cameraInternal, boolean requireMirroring)
Gets the relative rotation degrees given whether the output should be mirrored.
protected void
updateSessionConfig(java.util.List<SessionConfig> sessionConfigs)
Sets the SessionConfig that will be used by the attached Camera.
Get the current SessionConfig.
Get the current SessionConfig of the secondary camera in dual camera case.
protected final void
notifyActive()
Notify all UseCase.StateChangeCallback that are listening to this UseCase that it has
transitioned to an active state.
protected final void
notifyInactive()
Notify all UseCase.StateChangeCallback that are listening to this UseCase that it has
transitioned to an inactive state.
protected final void
notifyUpdated()
Notify all UseCase.StateChangeCallback that are listening to this UseCase that the
settings have been updated.
protected final void
notifyReset()
Notify all UseCase.StateChangeCallback that are listening to this UseCase that the use
case needs to be completely reset.
public final void
notifyState()
Notify all UseCase.StateChangeCallback that are listening to this UseCase of its current
state.
protected java.lang.String
getCameraId()
Returns the camera ID for the currently attached camera, or throws an exception if no
camera is attached.
protected java.lang.String
getSecondaryCameraId()
Returns the camera ID for the currently attached secondary camera, or throws an exception if
no camera is attached.
protected boolean
isCurrentCamera(java.lang.String cameraId)
Checks whether the provided camera ID is the currently attached camera ID.
public java.lang.String
getName()
Retrieves the configuration set by applications.
Retrieves the configuration used by this use case.
Returns:
the configuration used by this use case.
Returns the currently attached Camera or null if none is attached.
Returns the currently attached secondary Camera or null if none is attached.
public Size
getAttachedSurfaceResolution()
Retrieves the currently attached surface resolution.
Returns:
the currently attached surface resolution for the given camera id.
Retrieves the currently attached stream specification.
Returns:
the currently attached stream specification.
Offers suggested stream specification for the UseCase.
Called when binding new use cases via CameraX#bindToLifecycle(LifecycleOwner,
CameraSelector, UseCase...) with additional information for dual cameras.
Override to create necessary objects like depending
on the stream specification.
Parameters:
primaryStreamSpec: The suggested stream specification that depends on camera device
capability and what and how many use cases will be bound.
secondaryStreamSpec: The suggested stream specification for secondary camera in
dual camera case.
Returns:
The stream specification that finally used to create the SessionConfig to
attach to the camera device.
public void
updateSuggestedStreamSpecImplementationOptions(
Config config)
Update the implementation options of the stream specification for the UseCase.
protected
StreamSpec onSuggestedStreamSpecImplementationOptionsUpdated(
Config config)
Called when updating the stream specifications' implementation options of existing use cases
via CameraUseCaseAdapter#updateUseCases.
Parameters:
config: The new implementationOptions for the stream specification.
public void
onCameraControlReady()
Called when CameraControlInternal is attached into the UseCase. UseCase may need to
override this method to configure the CameraControlInternal here. Ex. Setting correct flash
mode by CameraControlInternal.setFlashMode to enable correct AE mode and flash state.
Binds use case to a camera.
Before a use case can receive frame data, it needs to establish association with the
target camera first. An implementation of CameraInternal (e.g. a lifecycle camera
or lifecycle-less camera) is provided when
UseCase.bindToCamera(CameraInternal, CameraInternal, UseCaseConfig>, UseCaseConfig>) is
invoked, so that the use case can retrieve the necessary information from the camera
to calculate and set up the configs.
The default, extended and camera config settings are also applied to the use case config
in this stage. Subclasses can override UseCase.onMergeConfig(CameraInfoInternal, UseCaseConfig.Builder, ?, ?>) to update the use case
config for use case specific purposes.
Calling UseCase.getCameraControl() can retrieve a real CameraControlInternal
implementation of the associated camera after this function is invoked. Otherwise, a fake
no-op CameraControlInternal implementation is returned by
UseCase.getCameraControl() function.
Called when use case is binding to a camera.
Subclasses can override this callback function to create the necessary objects to
make the use case work correctly.
After this function is invoked, CameraX will also provide the selected resolution
information to subclasses via UseCase.onSuggestedStreamSpecUpdated(StreamSpec, StreamSpec). Subclasses should
override it to set up the pipeline according to the selected resolution, so that UseCase
becomes ready to receive data from the camera.
Unbinds use case from a camera.
The use case de-associates from the camera. Before this function is invoked, the use
case must have been detached from the camera. So that the CameraInternal
implementation can remove the related resource (e.g. surface) from the working capture
session. Then, when this function is invoked, the use case can also clear all objects and
settings to initial state like it is never bound to a camera.
After this function is invoked, calling UseCase.getCameraControl() returns a fake no-op
CameraControlInternal implementation.
Called when use case is unbinding from a camera.
Subclasses can override this callback function to clear the objects created for
their specific purposes.
public void
onStateAttached()
Called when use case is attached to the camera. This method is called on main thread.
Once this function is invoked, the use case is attached to the CameraInternal
implementation of the associated camera. CameraX starts to open the camera and capture
session with the use case session config. The use case can receive the frame data from the
camera after the capture session is configured.
public void
onStateDetached()
Called when use case is detached from the camera. This method is called on main thread.
Once this function is invoked, the use case is detached from the CameraInternal
implementation of the associated camera. The use case no longer receives frame data from
the camera.
Retrieves a previously attached CameraControlInternal.
public void
setViewPortCropRect(Rect viewPortCropRect)
Sets the view port crop rect calculated at the time of binding.
Sets the CameraEffect associated with this use case.
Gets the CameraEffect associated with this use case.
public Rect
getViewPortCropRect()
Gets the view port crop rect.
public void
setSensorToBufferTransformMatrix(Matrix sensorToBufferTransformMatrix)
Sets the sensor to image buffer transform matrix.
public Matrix
getSensorToBufferTransformMatrix()
Gets the sensor to image buffer transform matrix.
public int
getImageFormat()
Get image format for the use case.
Returns:
image format for the use case
Returns a new ResolutionInfo according to the latest settings of the use case, or
null if the use case is not bound yet.
This allows the subclasses to return different ResolutionInfo according to its
different design.
protected java.util.Set<java.lang.Integer>
getSupportedEffectTargets()
A set of CameraEffect.Targets bitmasks supported by the UseCase.
To apply the CameraEffect on the UseCase or one of its ancestors,
CameraEffect.getTargets() must be a superset of at least one of the bitmask. For
example:
- For Preview, the set only contains [PREVIEW]. Preview and its ancestors
supports effects that are supersets of [PREVIEW]: PREVIEW, PREVIEW|VIDEO_CAPTURE, or
PREVIEW|VIDEO_CAPTURE|IMAGE_CAPTURE. A CameraEffect that does not target PREVIEW
cannot be applied to Preview or its ancestors.
- For StreamSharing, the set contains [PREVIEW|VIDEO_CAPTURE].
StreamSharing supports effects with targets PREVIEW|VIDEO_CAPTURE or
PREVIEW|VIDEO_CAPTURE|IMAGE_CAPTURE.
The method returns an empty set if this UseCase does not support effects. By
default, this method returns an empty set.
public boolean
isEffectTargetsSupported(int effectTargets)
Returns whether the targets can be applied to this UseCase or one of its ancestors.
See also: UseCase.getSupportedEffectTargets()
Source
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.camera.core;
import static androidx.camera.core.MirrorMode.MIRROR_MODE_OFF;
import static androidx.camera.core.MirrorMode.MIRROR_MODE_ON;
import static androidx.camera.core.MirrorMode.MIRROR_MODE_ON_FRONT_ONLY;
import static androidx.camera.core.MirrorMode.MIRROR_MODE_UNSPECIFIED;
import static androidx.camera.core.impl.ImageOutputConfig.OPTION_MAX_RESOLUTION;
import static androidx.camera.core.impl.ImageOutputConfig.OPTION_RESOLUTION_SELECTOR;
import static androidx.camera.core.impl.ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO;
import static androidx.camera.core.impl.ImageOutputConfig.OPTION_TARGET_RESOLUTION;
import static androidx.camera.core.impl.StreamSpec.FRAME_RATE_RANGE_UNSPECIFIED;
import static androidx.camera.core.impl.utils.TransformUtils.within360;
import static androidx.camera.core.processing.TargetUtils.isSuperset;
import static androidx.core.util.Preconditions.checkArgument;
import static androidx.core.util.Preconditions.checkArgumentInRange;
import android.annotation.SuppressLint;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.media.ImageReader;
import android.util.Range;
import android.util.Size;
import android.view.OrientationEventListener;
import android.view.Surface;
import androidx.annotation.CallSuper;
import androidx.annotation.GuardedBy;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.camera.core.impl.CameraControlInternal;
import androidx.camera.core.impl.CameraInfoInternal;
import androidx.camera.core.impl.CameraInternal;
import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.Config.Option;
import androidx.camera.core.impl.DeferrableSurface;
import androidx.camera.core.impl.ImageOutputConfig;
import androidx.camera.core.impl.MutableOptionsBundle;
import androidx.camera.core.impl.SessionConfig;
import androidx.camera.core.impl.StreamSpec;
import androidx.camera.core.impl.UseCaseConfig;
import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.internal.TargetConfig;
import androidx.camera.core.internal.utils.UseCaseConfigUtil;
import androidx.camera.core.resolutionselector.ResolutionSelector;
import androidx.camera.core.streamsharing.StreamSharing;
import androidx.core.util.Preconditions;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* The use case which all other use cases are built on top of.
*
* <p>A UseCase provides functionality to map the set of arguments in a use case to arguments
* that are usable by a camera. UseCase also will communicate of the active/inactive state to
* the Camera.
*/
public abstract class UseCase {
////////////////////////////////////////////////////////////////////////////////////////////
// [UseCase lifetime constant] - Stays constant for the lifetime of the UseCase. Which means
// they could be created in the constructor.
////////////////////////////////////////////////////////////////////////////////////////////
/**
* The set of {@link StateChangeCallback} that are currently listening state transitions of this
* use case.
*/
private final Set<StateChangeCallback> mStateChangeCallbacks = new HashSet<>();
private final Object mCameraLock = new Object();
////////////////////////////////////////////////////////////////////////////////////////////
// [UseCase lifetime dynamic] - Dynamic variables which could change during anytime during
// the UseCase lifetime.
////////////////////////////////////////////////////////////////////////////////////////////
private State mState = State.INACTIVE;
/** Extended config, applied on top of the app defined Config (mUseCaseConfig). */
@Nullable
private UseCaseConfig<?> mExtendedConfig;
/**
* Store the app defined {@link UseCaseConfig} used to create the use case.
*/
@NonNull
private UseCaseConfig<?> mUseCaseConfig;
/**
* The currently used Config.
*
* <p> This is the combination of the extended Config, app provided Config, and camera
* implementation Config (with decreasing priority).
*/
@NonNull
private UseCaseConfig<?> mCurrentConfig;
////////////////////////////////////////////////////////////////////////////////////////////
// [UseCase attached constant] - Is only valid when the UseCase is attached to a camera.
////////////////////////////////////////////////////////////////////////////////////////////
/**
* The {@link StreamSpec} assigned to the {@link UseCase} based on the attached camera.
*/
private StreamSpec mAttachedStreamSpec;
/**
* The camera implementation provided Config. Its options has lowest priority and will be
* overwritten by any app defined or extended configs.
*/
@Nullable
private UseCaseConfig<?> mCameraConfig;
/**
* The crop rect calculated at the time of binding based on {@link ViewPort}.
*/
@Nullable
private Rect mViewPortCropRect;
/**
* The sensor to image buffer transform matrix.
*/
@NonNull
private Matrix mSensorToBufferTransformMatrix = new Matrix();
@GuardedBy("mCameraLock")
private CameraInternal mCamera;
@GuardedBy("mCameraLock")
@Nullable
private CameraInternal mSecondaryCamera;
@Nullable
private CameraEffect mEffect;
@Nullable
private String mPhysicalCameraId;
////////////////////////////////////////////////////////////////////////////////////////////
// [UseCase attached dynamic] - Can change but is only available when the UseCase is attached.
////////////////////////////////////////////////////////////////////////////////////////////
// The currently attached session config
@NonNull
private SessionConfig mAttachedSessionConfig = SessionConfig.defaultEmptySessionConfig();
// The currently attached session config for secondary camera in dual camera case
@NonNull
private SessionConfig mAttachedSecondarySessionConfig =
SessionConfig.defaultEmptySessionConfig();
/**
* Creates a named instance of the use case.
*
* @param currentConfig the configuration object used for this use case
*/
@RestrictTo(Scope.LIBRARY_GROUP)
protected UseCase(@NonNull UseCaseConfig<?> currentConfig) {
mUseCaseConfig = currentConfig;
mCurrentConfig = currentConfig;
}
/**
* Retrieve the default {@link UseCaseConfig} for the UseCase.
*
* @param applyDefaultConfig true if this is the base config applied to a UseCase.
* @param factory the factory that contains the default UseCases.
* @return The UseCaseConfig or null if there is no default Config.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public abstract UseCaseConfig<?> getDefaultConfig(boolean applyDefaultConfig,
@NonNull UseCaseConfigFactory factory);
/**
* Create a {@link UseCaseConfig.Builder} for the UseCase.
*
* @param config the Config to initialize the builder
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public abstract UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config);
/**
* Create a merged {@link UseCaseConfig} from the UseCase, camera, and an extended config.
*
* @param cameraInfo info about the camera which may be used to resolve conflicts.
* @param extendedConfig configs that take priority over the UseCase's default config
* @param cameraDefaultConfig configs that have lower priority than the UseCase's default.
* This Config comes from the camera implementation.
* @throws IllegalArgumentException if there exists conflicts in the merged config that can
* not be resolved
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public UseCaseConfig<?> mergeConfigs(
@NonNull CameraInfoInternal cameraInfo,
@Nullable UseCaseConfig<?> extendedConfig,
@Nullable UseCaseConfig<?> cameraDefaultConfig) {
MutableOptionsBundle mergedConfig;
if (cameraDefaultConfig != null) {
mergedConfig = MutableOptionsBundle.from(cameraDefaultConfig);
mergedConfig.removeOption(TargetConfig.OPTION_TARGET_NAME);
} else {
mergedConfig = MutableOptionsBundle.create();
}
// Removes the default resolution selector setting to go for the legacy resolution
// selection logic flow if applications call the legacy setTargetAspectRatio and
// setTargetResolution APIs to do the setting.
if (mUseCaseConfig.containsOption(OPTION_TARGET_ASPECT_RATIO)
|| mUseCaseConfig.containsOption(OPTION_TARGET_RESOLUTION)) {
if (mergedConfig.containsOption(OPTION_RESOLUTION_SELECTOR)) {
mergedConfig.removeOption(OPTION_RESOLUTION_SELECTOR);
}
}
// Removes the default max resolution setting if application sets any ResolutionStrategy
// to override it.
if (mUseCaseConfig.containsOption(OPTION_RESOLUTION_SELECTOR)
&& mergedConfig.containsOption(OPTION_MAX_RESOLUTION)) {
ResolutionSelector resolutionSelector =
mUseCaseConfig.retrieveOption(OPTION_RESOLUTION_SELECTOR);
if (resolutionSelector.getResolutionStrategy() != null) {
mergedConfig.removeOption(OPTION_MAX_RESOLUTION);
}
}
// If any options need special handling, this is the place to do it. For now we'll just copy
// over all options.
for (Option<?> opt : mUseCaseConfig.listOptions()) {
Config.mergeOptionValue(mergedConfig, mergedConfig, mUseCaseConfig, opt);
}
if (extendedConfig != null) {
// If any options need special handling, this is the place to do it. For now we'll
// just copy over all options.
for (Option<?> opt : extendedConfig.listOptions()) {
@SuppressWarnings("unchecked") // Options/values are being copied directly
Option<Object> objectOpt = (Option<Object>) opt;
if (objectOpt.getId().equals(TargetConfig.OPTION_TARGET_NAME.getId())) {
continue;
}
Config.mergeOptionValue(mergedConfig, mergedConfig, extendedConfig, opt);
}
}
// If OPTION_TARGET_RESOLUTION has been set by the user, remove
// OPTION_TARGET_ASPECT_RATIO from defaultConfigBuilder because these two settings cannot be
// set at the same time.
if (mergedConfig.containsOption(ImageOutputConfig.OPTION_TARGET_RESOLUTION)
&& mergedConfig.containsOption(
ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)) {
mergedConfig.removeOption(ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO);
}
// Forces disable ZSL when high resolution is enabled.
if (mergedConfig.containsOption(ImageOutputConfig.OPTION_RESOLUTION_SELECTOR)
&& mergedConfig.retrieveOption(
ImageOutputConfig.OPTION_RESOLUTION_SELECTOR).getAllowedResolutionMode()
!= ResolutionSelector.PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION) {
mergedConfig.insertOption(UseCaseConfig.OPTION_ZSL_DISABLED, true);
}
return onMergeConfig(cameraInfo, getUseCaseConfigBuilder(mergedConfig));
}
/**
* Called when a set of configs are merged so the UseCase can do additional handling.
*
* <p> This can be overridden by a UseCase which need to do additional verification of the
* configs to make sure there are no conflicting options.
*
* @param cameraInfo info about the camera which may be used to resolve conflicts.
* @param builder the builder containing the merged configs requiring addition conflict
* resolution
* @return the conflict resolved config
* @throws IllegalArgumentException if there exists conflicts in the merged config that can
* not be resolved
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
protected UseCaseConfig<?> onMergeConfig(@NonNull CameraInfoInternal cameraInfo,
@NonNull UseCaseConfig.Builder<?, ?, ?> builder) {
return builder.getUseCaseConfig();
}
/**
* A utility function that can convert the orientation degrees of
* {@link OrientationEventListener} to the nearest {@link Surface} rotation.
*
* <p>In general, it is best to use an {@link android.view.OrientationEventListener} to set
* the UseCase target rotation. This way, the rotation output will indicate which way is down
* for a given image or video. This is important since display orientation may be locked by
* device default, user setting, or app configuration, and some devices may not transition to a
* reverse-portrait display orientation. In these cases, set target rotation dynamically
* according to the {@link android.view.OrientationEventListener}, without re-creating the
* use case. The sample code is as below:
* <pre>{@code
* public class CameraXActivity extends AppCompatActivity {
*
* private OrientationEventListener mOrientationEventListener;
*
* @Override
* protected void onStart() {
* super.onStart();
* if (mOrientationEventListener == null) {
* mOrientationEventListener = new OrientationEventListener(this) {
* @Override
* public void onOrientationChanged(int orientation) {
* if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
* return;
* }
* int rotation = UseCase.snapToSurfaceRotation(orientation);
* mImageCapture.setTargetRotation(rotation);
* mImageAnalysis.setTargetRotation(rotation);
* mVideoCapture.setTargetRotation(rotation);
* }
* };
* }
* mOrientationEventListener.enable();
* }
*
* @Override
* protected void onStop() {
* super.onStop();
* mOrientationEventListener.disable();
* }
* }
* }</pre>
*
* @param orientation the orientation degrees in range [0, 359].
* @return surface rotation. One of {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90},
* {@link Surface#ROTATION_180} and {@link Surface#ROTATION_270}.
* @throws IllegalArgumentException if the input orientation degrees is not in range [0, 359].
* @see ImageCapture#setTargetRotation(int)
* @see ImageAnalysis#setTargetRotation(int)
*/
@ImageOutputConfig.RotationValue
public static int snapToSurfaceRotation(@IntRange(from = 0, to = 359) int orientation) {
checkArgumentInRange(orientation, 0, 359, "orientation");
if (orientation >= 315 || orientation < 45) {
return Surface.ROTATION_0;
} else if (orientation >= 225) {
return Surface.ROTATION_90;
} else if (orientation >= 135) {
return Surface.ROTATION_180;
} else {
return Surface.ROTATION_270;
}
}
@RestrictTo(Scope.LIBRARY_GROUP)
public void setPhysicalCameraId(@NonNull String physicalCameraId) {
mPhysicalCameraId = physicalCameraId;
}
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public String getPhysicalCameraId() {
return mPhysicalCameraId;
}
/**
* Updates the target rotation of the use case config.
*
* @param targetRotation Target rotation of the output image, expressed as one of
* {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90},
* {@link Surface#ROTATION_180}, or {@link Surface#ROTATION_270}.
* @return true if the target rotation was changed.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
protected boolean setTargetRotationInternal(
@ImageOutputConfig.RotationValue int targetRotation) {
ImageOutputConfig oldConfig = (ImageOutputConfig) getCurrentConfig();
int oldRotation = oldConfig.getTargetRotation(ImageOutputConfig.INVALID_ROTATION);
if (oldRotation == ImageOutputConfig.INVALID_ROTATION || oldRotation != targetRotation) {
UseCaseConfig.Builder<?, ?, ?> builder = getUseCaseConfigBuilder(mUseCaseConfig);
UseCaseConfigUtil.updateTargetRotationAndRelatedConfigs(builder, targetRotation);
mUseCaseConfig = builder.getUseCaseConfig();
// Only merge configs if currently attached to a camera. Otherwise, set the current
// config to the use case config and mergeConfig() will be called once the use case
// is attached to a camera.
CameraInternal camera = getCamera();
if (camera == null) {
mCurrentConfig = mUseCaseConfig;
} else {
mCurrentConfig = mergeConfigs(camera.getCameraInfoInternal(), mExtendedConfig,
mCameraConfig);
}
return true;
}
return false;
}
/**
* Returns the rotation that the intended target resolution is expressed in.
*
* @return The rotation of the intended target.
*/
@SuppressLint("WrongConstant")
@RestrictTo(Scope.LIBRARY_GROUP)
@ImageOutputConfig.RotationValue
protected int getTargetRotationInternal() {
return ((ImageOutputConfig) mCurrentConfig).getTargetRotation(Surface.ROTATION_0);
}
/**
* Returns the target frame rate range for the associated VideoCapture use case.
*
* @return The target frame rate.
*/
@NonNull
@RestrictTo(Scope.LIBRARY_GROUP)
protected Range<Integer> getTargetFrameRateInternal() {
return mCurrentConfig.getTargetFrameRate(FRAME_RATE_RANGE_UNSPECIFIED);
}
/**
* Returns the mirror mode.
*
* <p>If mirror mode is not set, defaults to {@link MirrorMode#MIRROR_MODE_OFF}.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@MirrorMode.Mirror
protected int getMirrorModeInternal() {
return ((ImageOutputConfig) mCurrentConfig).getMirrorMode(MIRROR_MODE_UNSPECIFIED);
}
/**
* Returns if the mirroring is required with the associated camera.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public boolean isMirroringRequired(@NonNull CameraInternal camera) {
int mirrorMode = getMirrorModeInternal();
switch (mirrorMode) {
case MIRROR_MODE_UNSPECIFIED:
case MIRROR_MODE_OFF:
return false;
case MIRROR_MODE_ON:
return true;
case MIRROR_MODE_ON_FRONT_ONLY:
return camera.isFrontFacing();
default:
throw new AssertionError("Unknown mirrorMode: " + mirrorMode);
}
}
/**
* Returns the target rotation set by apps explicitly.
*
* @return The rotation of the intended target.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@ImageOutputConfig.OptionalRotationValue
protected int getAppTargetRotation() {
return ((ImageOutputConfig) mCurrentConfig)
.getAppTargetRotation(ImageOutputConfig.ROTATION_NOT_SPECIFIED);
}
/**
* Gets the relative rotation degrees without mirroring.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@IntRange(from = 0, to = 359)
protected int getRelativeRotation(@NonNull CameraInternal cameraInternal) {
return getRelativeRotation(cameraInternal, /*requireMirroring=*/false);
}
/**
* Gets the relative rotation degrees given whether the output should be mirrored.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@IntRange(from = 0, to = 359)
protected int getRelativeRotation(@NonNull CameraInternal cameraInternal,
boolean requireMirroring) {
int rotation = cameraInternal.getCameraInfoInternal().getSensorRotationDegrees(
getTargetRotationInternal());
// Parent UseCase always mirror the stream if the child requires it. No camera transform
// means that the stream is copied by a parent, and if the child also requires mirroring,
// we know that the stream has been mirrored.
boolean inputStreamMirrored = !cameraInternal.getHasTransform() && requireMirroring;
if (inputStreamMirrored) {
// Flip rotation if the stream has been mirrored.
rotation = within360(-rotation);
}
return rotation;
}
/**
* Sets the {@link SessionConfig} that will be used by the attached {@link Camera}.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
protected void updateSessionConfig(@NonNull List<SessionConfig> sessionConfigs) {
if (sessionConfigs.isEmpty()) {
return;
}
mAttachedSessionConfig = sessionConfigs.get(0);
if (sessionConfigs.size() > 1) {
mAttachedSecondarySessionConfig = sessionConfigs.get(1);
}
for (SessionConfig sessionConfig : sessionConfigs) {
for (DeferrableSurface surface : sessionConfig.getSurfaces()) {
if (surface.getContainerClass() == null) {
surface.setContainerClass(this.getClass());
}
}
}
}
/**
* Add a {@link StateChangeCallback}, which listens to this UseCase's active and inactive
* transition events.
*/
private void addStateChangeCallback(@NonNull StateChangeCallback callback) {
mStateChangeCallbacks.add(callback);
}
/**
* Remove a {@link StateChangeCallback} from listening to this UseCase's active and inactive
* transition events.
*
* <p>If the listener isn't currently listening to the UseCase then this call does nothing.
*/
private void removeStateChangeCallback(@NonNull StateChangeCallback callback) {
mStateChangeCallbacks.remove(callback);
}
/**
* Get the current {@link SessionConfig}.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public SessionConfig getSessionConfig() {
return mAttachedSessionConfig;
}
/**
* Get the current {@link SessionConfig} of the secondary camera in dual camera case.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public SessionConfig getSecondarySessionConfig() {
return mAttachedSecondarySessionConfig;
}
/**
* Notify all {@link StateChangeCallback} that are listening to this UseCase that it has
* transitioned to an active state.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
protected final void notifyActive() {
mState = State.ACTIVE;
notifyState();
}
/**
* Notify all {@link StateChangeCallback} that are listening to this UseCase that it has
* transitioned to an inactive state.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
protected final void notifyInactive() {
mState = State.INACTIVE;
notifyState();
}
/**
* Notify all {@link StateChangeCallback} that are listening to this UseCase that the
* settings have been updated.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
protected final void notifyUpdated() {
for (StateChangeCallback stateChangeCallback : mStateChangeCallbacks) {
stateChangeCallback.onUseCaseUpdated(this);
}
}
/**
* Notify all {@link StateChangeCallback} that are listening to this UseCase that the use
* case needs to be completely reset.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
protected final void notifyReset() {
for (StateChangeCallback stateChangeCallback : mStateChangeCallbacks) {
stateChangeCallback.onUseCaseReset(this);
}
}
/**
* Notify all {@link StateChangeCallback} that are listening to this UseCase of its current
* state.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public final void notifyState() {
switch (mState) {
case INACTIVE:
for (StateChangeCallback stateChangeCallback : mStateChangeCallbacks) {
stateChangeCallback.onUseCaseInactive(this);
}
break;
case ACTIVE:
for (StateChangeCallback stateChangeCallback : mStateChangeCallbacks) {
stateChangeCallback.onUseCaseActive(this);
}
break;
}
}
/**
* Returns the camera ID for the currently attached camera, or throws an exception if no
* camera is attached.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
protected String getCameraId() {
return Preconditions.checkNotNull(getCamera(),
"No camera attached to use case: " + this).getCameraInfoInternal().getCameraId();
}
/**
* Returns the camera ID for the currently attached secondary camera, or throws an exception if
* no camera is attached.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
protected String getSecondaryCameraId() {
return getSecondaryCamera() == null ? null : getSecondaryCamera()
.getCameraInfoInternal().getCameraId();
}
/**
* Checks whether the provided camera ID is the currently attached camera ID.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
protected boolean isCurrentCamera(@NonNull String cameraId) {
if (getCamera() == null) {
return false;
}
return Objects.equals(cameraId, getCameraId());
}
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public String getName() {
return Objects.requireNonNull(
mCurrentConfig.getTargetName("<UnknownUseCase-" + hashCode() + ">"));
}
/**
* Retrieves the configuration set by applications.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
protected UseCaseConfig<?> getAppConfig() {
return mUseCaseConfig;
}
/**
* Retrieves the configuration used by this use case.
*
* @return the configuration used by this use case.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public UseCaseConfig<?> getCurrentConfig() {
return mCurrentConfig;
}
/**
* Returns the currently attached {@link Camera} or {@code null} if none is attached.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public CameraInternal getCamera() {
synchronized (mCameraLock) {
return mCamera;
}
}
/**
* Returns the currently attached secondary {@link Camera} or {@code null} if none is attached.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public CameraInternal getSecondaryCamera() {
synchronized (mCameraLock) {
return mSecondaryCamera;
}
}
/**
* Retrieves the currently attached surface resolution.
*
* @return the currently attached surface resolution for the given camera id.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Size getAttachedSurfaceResolution() {
return mAttachedStreamSpec != null ? mAttachedStreamSpec.getResolution() : null;
}
/**
* Retrieves the currently attached stream specification.
*
* @return the currently attached stream specification.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public StreamSpec getAttachedStreamSpec() {
return mAttachedStreamSpec;
}
/**
* Offers suggested stream specification for the UseCase.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public void updateSuggestedStreamSpec(
@NonNull StreamSpec primaryStreamSpec,
@Nullable StreamSpec secondaryStreamSpec) {
mAttachedStreamSpec = onSuggestedStreamSpecUpdated(
primaryStreamSpec, secondaryStreamSpec);
}
/**
* Called when binding new use cases via {@code CameraX#bindToLifecycle(LifecycleOwner,
* CameraSelector, UseCase...)} with additional information for dual cameras.
*
* <p>Override to create necessary objects like {@link ImageReader} depending
* on the stream specification.
*
* @param primaryStreamSpec The suggested stream specification that depends on camera device
* capability and what and how many use cases will be bound.
* @param secondaryStreamSpec The suggested stream specification for secondary camera in
* dual camera case.
* @return The stream specification that finally used to create the SessionConfig to
* attach to the camera device.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
protected StreamSpec onSuggestedStreamSpecUpdated(
@NonNull StreamSpec primaryStreamSpec,
@Nullable StreamSpec secondaryStreamSpec) {
return primaryStreamSpec;
}
/**
* Update the implementation options of the stream specification for the UseCase.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public void updateSuggestedStreamSpecImplementationOptions(@NonNull Config config) {
// TODO(b/349823704): investigate whether we need mAttachedSecondaryStreamSpec for
// StreamSharing
mAttachedStreamSpec = onSuggestedStreamSpecImplementationOptionsUpdated(config);
}
/**
* Called when updating the stream specifications' implementation options of existing use cases
* via {@code CameraUseCaseAdapter#updateUseCases}.
*
* @param config The new implementationOptions for the stream specification.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
protected StreamSpec onSuggestedStreamSpecImplementationOptionsUpdated(@NonNull Config config) {
if (mAttachedStreamSpec == null) {
throw new UnsupportedOperationException("Attempt to update the implementation options "
+ "for a use case without attached stream specifications.");
}
return mAttachedStreamSpec.toBuilder().setImplementationOptions(config).build();
}
/**
* Called when CameraControlInternal is attached into the UseCase. UseCase may need to
* override this method to configure the CameraControlInternal here. Ex. Setting correct flash
* mode by CameraControlInternal.setFlashMode to enable correct AE mode and flash state.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public void onCameraControlReady() {
}
/**
* Binds use case to a camera.
*
* <p>Before a use case can receive frame data, it needs to establish association with the
* target camera first. An implementation of {@link CameraInternal} (e.g. a lifecycle camera
* or lifecycle-less camera) is provided when
* {@link #bindToCamera(CameraInternal, CameraInternal, UseCaseConfig, UseCaseConfig)} is
* invoked, so that the use case can retrieve the necessary information from the camera
* to calculate and set up the configs.
*
* <p>The default, extended and camera config settings are also applied to the use case config
* in this stage. Subclasses can override {@link #onMergeConfig} to update the use case
* config for use case specific purposes.
*
* <p>Calling {@link #getCameraControl()} can retrieve a real {@link CameraControlInternal}
* implementation of the associated camera after this function is invoked. Otherwise, a fake
* no-op {@link CameraControlInternal} implementation is returned by
* {@link #getCameraControl()} function.
*/
@SuppressLint("WrongConstant")
@RestrictTo(Scope.LIBRARY_GROUP)
public final void bindToCamera(@NonNull CameraInternal camera,
@Nullable CameraInternal secondaryCamera,
@Nullable UseCaseConfig<?> extendedConfig,
@Nullable UseCaseConfig<?> cameraConfig) {
synchronized (mCameraLock) {
mCamera = camera;
mSecondaryCamera = secondaryCamera;
addStateChangeCallback(camera);
if (secondaryCamera != null) {
addStateChangeCallback(secondaryCamera);
}
}
mExtendedConfig = extendedConfig;
mCameraConfig = cameraConfig;
mCurrentConfig = mergeConfigs(camera.getCameraInfoInternal(), mExtendedConfig,
mCameraConfig);
onBind();
}
/**
* Called when use case is binding to a camera.
*
* <p>Subclasses can override this callback function to create the necessary objects to
* make the use case work correctly.
*
* <p>After this function is invoked, CameraX will also provide the selected resolution
* information to subclasses via {@link #onSuggestedStreamSpecUpdated}. Subclasses should
* override it to set up the pipeline according to the selected resolution, so that UseCase
* becomes ready to receive data from the camera.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public void onBind() {
}
/**
* Unbinds use case from a camera.
*
* <p>The use case de-associates from the camera. Before this function is invoked, the use
* case must have been detached from the camera. So that the {@link CameraInternal}
* implementation can remove the related resource (e.g. surface) from the working capture
* session. Then, when this function is invoked, the use case can also clear all objects and
* settings to initial state like it is never bound to a camera.
*
* <p>After this function is invoked, calling {@link #getCameraControl()} returns a fake no-op
* {@link CameraControlInternal} implementation.
*
*/
@RestrictTo(Scope.LIBRARY)
public final void unbindFromCamera(@NonNull CameraInternal camera) {
// Do any cleanup required by the UseCase implementation
onUnbind();
synchronized (mCameraLock) {
if (camera == mCamera) {
removeStateChangeCallback(mCamera);
mCamera = null;
}
if (camera == mSecondaryCamera) {
removeStateChangeCallback(mSecondaryCamera);
mSecondaryCamera = null;
}
}
mAttachedStreamSpec = null;
mViewPortCropRect = null;
// Resets the mUseCaseConfig to the initial status when the use case was created to make
// the use case reusable.
mCurrentConfig = mUseCaseConfig;
mExtendedConfig = null;
mCameraConfig = null;
}
/**
* Called when use case is unbinding from a camera.
*
* <p>Subclasses can override this callback function to clear the objects created for
* their specific purposes.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public void onUnbind() {
}
/**
* Called when use case is attached to the camera. This method is called on main thread.
*
* <p>Once this function is invoked, the use case is attached to the {@link CameraInternal}
* implementation of the associated camera. CameraX starts to open the camera and capture
* session with the use case session config. The use case can receive the frame data from the
* camera after the capture session is configured.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@CallSuper
public void onStateAttached() {
}
/**
* Called when use case is detached from the camera. This method is called on main thread.
*
* <p>Once this function is invoked, the use case is detached from the {@link CameraInternal}
* implementation of the associated camera. The use case no longer receives frame data from
* the camera.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public void onStateDetached() {
}
/**
* Retrieves a previously attached {@link CameraControlInternal}.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
protected CameraControlInternal getCameraControl() {
synchronized (mCameraLock) {
if (mCamera == null) {
return CameraControlInternal.DEFAULT_EMPTY_INSTANCE;
}
return mCamera.getCameraControlInternal();
}
}
/**
* Sets the view port crop rect calculated at the time of binding.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@CallSuper
public void setViewPortCropRect(@NonNull Rect viewPortCropRect) {
mViewPortCropRect = viewPortCropRect;
}
/**
* Sets the {@link CameraEffect} associated with this use case.
*
* @throws IllegalArgumentException if the effect targets are not supported by this use case.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public void setEffect(@Nullable CameraEffect effect) {
checkArgument(effect == null || isEffectTargetsSupported(effect.getTargets()));
mEffect = effect;
}
/**
* Gets the {@link CameraEffect} associated with this use case.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public CameraEffect getEffect() {
return mEffect;
}
/**
* Gets the view port crop rect.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Rect getViewPortCropRect() {
return mViewPortCropRect;
}
/**
* Sets the sensor to image buffer transform matrix.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@CallSuper
public void setSensorToBufferTransformMatrix(@NonNull Matrix sensorToBufferTransformMatrix) {
mSensorToBufferTransformMatrix = new Matrix(sensorToBufferTransformMatrix);
}
/**
* Gets the sensor to image buffer transform matrix.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public Matrix getSensorToBufferTransformMatrix() {
return mSensorToBufferTransformMatrix;
}
/**
* Get image format for the use case.
*
* @return image format for the use case
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public int getImageFormat() {
return mCurrentConfig.getInputFormat();
}
/**
* Returns a new {@link ResolutionInfo} according to the latest settings of the use case, or
* null if the use case is not bound yet.
*
* <p>This allows the subclasses to return different {@link ResolutionInfo} according to its
* different design.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
protected ResolutionInfo getResolutionInfoInternal() {
CameraInternal camera = getCamera();
Size resolution = getAttachedSurfaceResolution();
if (camera == null || resolution == null) {
return null;
}
Rect cropRect = getViewPortCropRect();
if (cropRect == null) {
cropRect = new Rect(0, 0, resolution.getWidth(), resolution.getHeight());
}
int rotationDegrees = getRelativeRotation(camera);
return new ResolutionInfo(resolution, cropRect, rotationDegrees);
}
/**
* A set of {@link CameraEffect.Targets} bitmasks supported by the {@link UseCase}.
*
* <p>To apply the {@link CameraEffect} on the {@link UseCase} or one of its ancestors,
* {@link CameraEffect#getTargets()} must be a superset of at least one of the bitmask. For
* example:
* <ul>
* <li>For {@link Preview}, the set only contains [PREVIEW]. {@link Preview} and its ancestors
* supports effects that are supersets of [PREVIEW]: PREVIEW, PREVIEW|VIDEO_CAPTURE, or
* PREVIEW|VIDEO_CAPTURE|IMAGE_CAPTURE. A {@link CameraEffect} that does not target PREVIEW
* cannot be applied to {@link Preview} or its ancestors.
* <li>For {@link StreamSharing}, the set contains [PREVIEW|VIDEO_CAPTURE].
* {@link StreamSharing} supports effects with targets PREVIEW|VIDEO_CAPTURE or
* PREVIEW|VIDEO_CAPTURE|IMAGE_CAPTURE.
* </ul>
*
* <p>The method returns an empty set if this {@link UseCase} does not support effects. By
* default, this method returns an empty set.
*
*/
@NonNull
@RestrictTo(Scope.LIBRARY_GROUP)
protected Set<Integer> getSupportedEffectTargets() {
return Collections.emptySet();
}
/**
* Returns whether the targets can be applied to this {@link UseCase} or one of its ancestors.
*
* @see #getSupportedEffectTargets()
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public boolean isEffectTargetsSupported(@CameraEffect.Targets int effectTargets) {
for (Integer useCaseTargets : getSupportedEffectTargets()) {
if (isSuperset(effectTargets, useCaseTargets)) {
return true;
}
}
return false;
}
enum State {
/** Currently waiting for image data. */
ACTIVE,
/** Currently not waiting for image data. */
INACTIVE
}
/**
* Callback for when a {@link UseCase} transitions between active/inactive states.
*
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public interface StateChangeCallback {
/**
* Called when a {@link UseCase} becomes active.
*
* <p>When a UseCase is active it expects that all data producers attached to itself
* should start producing data for it to consume. In addition the UseCase will start
* producing data that other classes can be consumed.
*/
void onUseCaseActive(@NonNull UseCase useCase);
/**
* Called when a {@link UseCase} becomes inactive.
*
* <p>When a UseCase is inactive it no longer expects data to be produced for it. In
* addition the UseCase will stop producing data for other classes to consume.
*/
void onUseCaseInactive(@NonNull UseCase useCase);
/**
* Called when a {@link UseCase} has updated settings.
*
* <p>When a {@link UseCase} has updated settings, it is expected that the listener will
* use these updated settings to reconfigure the listener's own state. A settings update is
* orthogonal to the active/inactive state change.
*/
void onUseCaseUpdated(@NonNull UseCase useCase);
/**
* Called when a {@link UseCase} has updated settings that require complete reset of the
* camera.
*
* <p>Updating certain parameters of the use case require a full reset of the camera. This
* includes updating the {@link Surface} used by the use case.
*/
void onUseCaseReset(@NonNull UseCase useCase);
}
}