ret = new ArrayList<>();
final IBinder token = new Binder(TAG + "#getSupportedExtensions:" + mCameraId);
IntArray extensionList = new IntArray(EXTENSION_LIST.length);
extensionList.addAll(EXTENSION_LIST);
if (Flags.concertModeApi()) {
extensionList.add(EXTENSION_EYES_FREE_VIDEOGRAPHY);
}
for (int extensionType : extensionList.toArray()) {
try {
boolean success = registerClient(mContext, token, extensionType, mCameraId,
mCharacteristicsMapNative);
if (success && isExtensionSupported(mCameraId, extensionType,
mCharacteristicsMapNative)) {
ret.add(extensionType);
}
} finally {
unregisterClient(mContext, token, extensionType);
}
}
return Collections.unmodifiableList(ret);
}
/**
* Gets an extension specific camera characteristics field value.
*
* An extension can have a reduced set of camera capabilities (such as limited zoom ratio
* range, available video stabilization modes, etc). This API enables applications to query for
* an extension’s specific camera characteristics. Applications are recommended to prioritize
* obtaining camera characteristics using this API when using an extension. A {@code null}
* result indicates that the extension specific characteristic is not defined or available.
*
* @param extension The extension type.
* @param key The characteristics field to read.
* @return The value of that key, or {@code null} if the field is not set.
*
* @throws IllegalArgumentException if the key is not valid or extension type is not a supported
* device-specific extension.
*/
@FlaggedApi(Flags.FLAG_CAMERA_EXTENSIONS_CHARACTERISTICS_GET)
public @Nullable T get(@Extension int extension,
@NonNull CameraCharacteristics.Key key) {
final IBinder token = new Binder(TAG + "#get:" + mCameraId);
boolean success = registerClient(mContext, token, extension, mCameraId,
mCharacteristicsMapNative);
if (!success) {
throw new IllegalArgumentException("Unsupported extensions");
}
try {
if (!isExtensionSupported(mCameraId, extension, mCharacteristicsMapNative)) {
throw new IllegalArgumentException("Unsupported extension");
}
if (areAdvancedExtensionsSupported(extension) && getKeys(extension).contains(key)) {
IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
extender.init(mCameraId, mCharacteristicsMapNative);
CameraMetadataNative metadata =
extender.getAvailableCharacteristicsKeyValues(mCameraId);
if (metadata == null) {
return null;
}
CameraCharacteristics characteristics = new CameraCharacteristics(metadata);
return characteristics.get(key);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to query the extension for the specified key! Extension "
+ "service does not respond!");
} finally {
unregisterClient(mContext, token, extension);
}
return null;
}
/**
* Returns the {@link CameraCharacteristics} keys that have extension-specific values.
*
* An application can query the value from the key using
* {@link #get(int, CameraCharacteristics.Key)} API.
*
* @param extension The extension type.
* @return An unmodifiable set of keys that are extension specific.
*
* @throws IllegalArgumentException in case the extension type is not a
* supported device-specific extension
*/
@FlaggedApi(Flags.FLAG_CAMERA_EXTENSIONS_CHARACTERISTICS_GET)
public @NonNull Set getKeys(@Extension int extension) {
final IBinder token =
new Binder(TAG + "#getKeys:" + mCameraId);
boolean success = registerClient(mContext, token, extension, mCameraId,
mCharacteristicsMapNative);
if (!success) {
throw new IllegalArgumentException("Unsupported extensions");
}
HashSet ret = new HashSet<>();
try {
if (!isExtensionSupported(mCameraId, extension, mCharacteristicsMapNative)) {
throw new IllegalArgumentException("Unsupported extension");
}
if (areAdvancedExtensionsSupported(extension)) {
IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
extender.init(mCameraId, mCharacteristicsMapNative);
CameraMetadataNative metadata =
extender.getAvailableCharacteristicsKeyValues(mCameraId);
if (metadata == null) {
return Collections.emptySet();
}
int[] keys = metadata.get(
CameraCharacteristics.REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
if (keys == null) {
throw new AssertionError(
"android.request.availableCharacteristicsKeys must be non-null"
+ " in the characteristics");
}
CameraCharacteristics chars = new CameraCharacteristics(metadata);
Object key = CameraCharacteristics.Key.class;
Class> keyTyped =
(Class>) key;
ret.addAll(chars.getAvailableKeyList(CameraCharacteristics.class, keyTyped, keys,
/*includeSynthetic*/ false));
// Add synthetic keys to the available key list if they are part of the supported
// synthetic camera characteristic key list
for (CameraCharacteristics.Key charKey :
SUPPORTED_SYNTHETIC_CAMERA_CHARACTERISTICS) {
if (chars.get(charKey) != null) {
ret.add(charKey);
}
}
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to query the extension for all available keys! Extension "
+ "service does not respond!");
} finally {
unregisterClient(mContext, token, extension);
}
return Collections.unmodifiableSet(ret);
}
/**
* Checks for postview support of still capture.
*
* A postview is a preview version of the still capture that is available before the final
* image. For example, it can be used as a temporary placeholder for the requested capture
* while the final image is being processed. The supported sizes for a still capture's postview
* can be retrieved using
* {@link CameraExtensionCharacteristics#getPostviewSupportedSizes(int, Size, int)}.
*
* Starting with Android {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM},
* the formats of the still capture and postview are not required to be equivalent upon capture
* request.
*
* @param extension the extension type
* @return {@code true} in case postview is supported, {@code false} otherwise
*
* @throws IllegalArgumentException in case the extension type is not a
* supported device-specific extension
*/
public boolean isPostviewAvailable(@Extension int extension) {
final IBinder token = new Binder(TAG + "#isPostviewAvailable:" + mCameraId);
boolean success = registerClient(mContext, token, extension, mCameraId,
mCharacteristicsMapNative);
if (!success) {
throw new IllegalArgumentException("Unsupported extensions");
}
try {
if (!isExtensionSupported(mCameraId, extension, mCharacteristicsMapNative)) {
throw new IllegalArgumentException("Unsupported extension");
}
if (areAdvancedExtensionsSupported(extension)) {
IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
extender.init(mCameraId, mCharacteristicsMapNative);
return extender.isPostviewAvailable();
} else {
Pair extenders =
initializeExtension(extension);
extenders.second.init(mCameraId, mCharacteristicsMapNative.get(mCameraId));
return extenders.second.isPostviewAvailable();
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to query the extension for postview availability! Extension "
+ "service does not respond!");
} finally {
unregisterClient(mContext, token, extension);
}
return false;
}
/**
* Get a list of the postview sizes supported for a still capture, using its
* capture size {@code captureSize}, to use as an output for the postview request.
*
* Available postview sizes will always be either equal to or less than the still
* capture size. When choosing the most applicable postview size for a usecase, it should
* be noted that lower resolution postviews will generally be available more quickly
* than larger resolution postviews. For example, when choosing a size for an optimized
* postview that will be displayed as a placeholder while the final image is processed,
* the resolution closest to the preview size may be most suitable.
*
* Note that device-specific extensions are allowed to support only a subset
* of the camera resolutions advertised by
* {@link StreamConfigurationMap#getOutputSizes}.
*
* @param extension the extension type
* @param captureSize size of the still capture for which the postview is requested
* @param format device-specific extension output format of the postview
* @return non-modifiable list of available sizes or an empty list if the format and
* size is not supported.
* @throws IllegalArgumentException in case of unsupported extension or if postview
* feature is not supported by extension.
*/
@NonNull
public List getPostviewSupportedSizes(@Extension int extension,
@NonNull Size captureSize, int format) {
final IBinder token = new Binder(TAG + "#getPostviewSupportedSizes:" + mCameraId);
boolean success = registerClient(mContext, token, extension, mCameraId,
mCharacteristicsMapNative);
if (!success) {
throw new IllegalArgumentException("Unsupported extensions");
}
try {
if (!isExtensionSupported(mCameraId, extension, mCharacteristicsMapNative)) {
throw new IllegalArgumentException("Unsupported extension");
}
android.hardware.camera2.extension.Size sz =
new android.hardware.camera2.extension.Size();
sz.width = captureSize.getWidth();
sz.height = captureSize.getHeight();
StreamConfigurationMap streamMap = mCharacteristicsMap.get(mCameraId).get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (areAdvancedExtensionsSupported(extension)) {
switch(format) {
case ImageFormat.YUV_420_888:
case ImageFormat.JPEG:
case ImageFormat.JPEG_R:
case ImageFormat.YCBCR_P010:
break;
default:
throw new IllegalArgumentException("Unsupported format: " + format);
}
IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
extender.init(mCameraId, mCharacteristicsMapNative);
return getSupportedSizes(extender.getSupportedPostviewResolutions(sz),
format);
} else {
Pair extenders =
initializeExtension(extension);
extenders.second.init(mCameraId, mCharacteristicsMapNative.get(mCameraId));
if ((extenders.second.getCaptureProcessor() == null) ||
!isPostviewAvailable(extension)) {
// Extensions that don't implement any capture processor
// and have processing occur in the HAL don't currently support the
// postview feature
throw new IllegalArgumentException("Extension does not support "
+ "postview feature");
}
if (format == ImageFormat.YUV_420_888) {
return getSupportedSizes(
extenders.second.getSupportedPostviewResolutions(sz), format);
} else if (format == ImageFormat.JPEG) {
// The framework will perform the additional encoding pass on the
// processed YUV_420 buffers.
return getSupportedSizes(
extenders.second.getSupportedPostviewResolutions(sz), format);
} else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010) {
// Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the basic
// extension case
return new ArrayList<>();
} else {
throw new IllegalArgumentException("Unsupported format: " + format);
}
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to query the extension postview supported sizes! Extension "
+ "service does not respond!");
return Collections.emptyList();
} finally {
unregisterClient(mContext, token, extension);
}
}
/**
* Get a list of sizes compatible with {@code klass} to use as an output for the
* repeating request
* {@link CameraExtensionSession#setRepeatingRequest}.
*
* Note that device-specific extensions are allowed to support only a subset
* of the camera output surfaces and resolutions.
* The {@link android.graphics.SurfaceTexture} class is guaranteed at least one size for
* backward compatible cameras whereas other output classes are not guaranteed to be supported.
*
*
* Starting with Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}
* {@link android.view.SurfaceView} classes are also guaranteed to be supported and include
* the same resolutions as {@link android.graphics.SurfaceTexture}.
* Clients must set the desired SurfaceView resolution by calling
* {@link android.view.SurfaceHolder#setFixedSize}.
*
* @param extension the extension type
* @param klass a non-{@code null} {@link Class} object reference
* @return non-modifiable list of available sizes or an empty list if the Surface output is not
* supported
* @throws NullPointerException if {@code klass} was {@code null}
* @throws IllegalArgumentException in case of unsupported extension.
*/
@NonNull
public List getExtensionSupportedSizes(@Extension int extension,
@NonNull Class klass) {
if (!isOutputSupportedFor(klass)) {
return new ArrayList<>();
}
// TODO: Revisit this code once the Extension preview processor output format
// ambiguity is resolved in b/169799538.
final IBinder token = new Binder(TAG + "#getExtensionSupportedSizes:" + mCameraId);
boolean success = registerClient(mContext, token, extension, mCameraId,
mCharacteristicsMapNative);
if (!success) {
throw new IllegalArgumentException("Unsupported extensions");
}
try {
if (!isExtensionSupported(mCameraId, extension, mCharacteristicsMapNative)) {
throw new IllegalArgumentException("Unsupported extension");
}
StreamConfigurationMap streamMap = mCharacteristicsMap.get(mCameraId).get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (areAdvancedExtensionsSupported(extension)) {
IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
extender.init(mCameraId, mCharacteristicsMapNative);
return generateSupportedSizes(
extender.getSupportedPreviewOutputResolutions(mCameraId),
ImageFormat.PRIVATE, streamMap);
} else {
Pair extenders =
initializeExtension(extension);
extenders.first.init(mCameraId,
mCharacteristicsMapNative.get(mCameraId));
return generateSupportedSizes(extenders.first.getSupportedResolutions(),
ImageFormat.PRIVATE, streamMap);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to query the extension supported sizes! Extension service does"
+ " not respond!");
return new ArrayList<>();
} finally {
unregisterClient(mContext, token, extension);
}
}
/**
* Check whether a given extension is available and return the
* supported output surface resolutions that can be used for high-quality capture
* requests via {@link CameraExtensionSession#capture}.
*
* Note that device-specific extensions are allowed to support only a subset
* of the camera resolutions advertised by
* {@link StreamConfigurationMap#getOutputSizes}.
*
* Device-specific extensions currently support at most three
* multi-frame capture surface formats. ImageFormat.JPEG will be supported by all
* extensions while ImageFormat.YUV_420_888, ImageFormat.JPEG_R, or ImageFormat.YCBCR_P010
* may or may not be supported.
*
* @param extension the extension type
* @param format device-specific extension output format
* @return non-modifiable list of available sizes or an empty list if the format is not
* supported.
* @throws IllegalArgumentException in case of format different from ImageFormat.JPEG,
* ImageFormat.YUV_420_888, ImageFormat.JPEG_R,
* ImageFormat.YCBCR_P010; or unsupported extension.
*/
public @NonNull
List getExtensionSupportedSizes(@Extension int extension, int format) {
try {
final IBinder token = new Binder(TAG + "#getExtensionSupportedSizes:" + mCameraId);
boolean success = registerClient(mContext, token, extension, mCameraId,
mCharacteristicsMapNative);
if (!success) {
throw new IllegalArgumentException("Unsupported extensions");
}
try {
if (!isExtensionSupported(mCameraId, extension, mCharacteristicsMapNative)) {
throw new IllegalArgumentException("Unsupported extension");
}
StreamConfigurationMap streamMap = mCharacteristicsMap.get(mCameraId).get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (areAdvancedExtensionsSupported(extension)) {
switch(format) {
case ImageFormat.YUV_420_888:
case ImageFormat.JPEG:
case ImageFormat.JPEG_R:
case ImageFormat.YCBCR_P010:
break;
default:
throw new IllegalArgumentException("Unsupported format: " + format);
}
IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
extender.init(mCameraId, mCharacteristicsMapNative);
return generateSupportedSizes(extender.getSupportedCaptureOutputResolutions(
mCameraId), format, streamMap);
} else {
if (format == ImageFormat.YUV_420_888) {
Pair extenders =
initializeExtension(extension);
extenders.second.init(mCameraId, mCharacteristicsMapNative.get(mCameraId));
if (extenders.second.getCaptureProcessor() == null) {
// Extensions that don't implement any capture processor are limited to
// JPEG only!
return new ArrayList<>();
}
return generateSupportedSizes(extenders.second.getSupportedResolutions(),
format, streamMap);
} else if (format == ImageFormat.JPEG) {
Pair extenders =
initializeExtension(extension);
extenders.second.init(mCameraId, mCharacteristicsMapNative.get(mCameraId));
if (extenders.second.getCaptureProcessor() != null) {
// The framework will perform the additional encoding pass on the
// processed YUV_420 buffers.
return generateJpegSupportedSizes(
extenders.second.getSupportedResolutions(), streamMap);
} else {
return generateSupportedSizes(null, format, streamMap);
}
} else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010) {
// Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the
// basic extension case
return new ArrayList<>();
} else {
throw new IllegalArgumentException("Unsupported format: " + format);
}
}
} finally {
unregisterClient(mContext, token, extension);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to query the extension supported sizes! Extension service does"
+ " not respond!");
return new ArrayList<>();
}
}
/**
* Returns the estimated capture latency range in milliseconds for the
* target capture resolution during the calls to {@link CameraExtensionSession#capture}. This
* includes the time spent processing the multi-frame capture request along with any additional
* time for encoding of the processed buffer if necessary.
*
* @param extension the extension type
* @param captureOutputSize size of the capture output surface. If it is not in the supported
* output sizes, maximum capture output size is used for the estimation
* @param format device-specific extension output format
* @return the range of estimated minimal and maximal capture latency in milliseconds
* or null if no capture latency info can be provided
* @throws IllegalArgumentException in case of format different from {@link ImageFormat#JPEG},
* {@link ImageFormat#YUV_420_888}, {@link ImageFormat#JPEG_R}
* {@link ImageFormat#YCBCR_P010};
* or unsupported extension.
*/
public @Nullable Range getEstimatedCaptureLatencyRangeMillis(@Extension int extension,
@NonNull Size captureOutputSize, @ImageFormat.Format int format) {
switch (format) {
case ImageFormat.YUV_420_888:
case ImageFormat.JPEG:
case ImageFormat.JPEG_R:
case ImageFormat.YCBCR_P010:
//No op
break;
default:
throw new IllegalArgumentException("Unsupported format: " + format);
}
final IBinder token = new Binder(TAG + "#getEstimatedCaptureLatencyRangeMillis:" + mCameraId);
boolean success = registerClient(mContext, token, extension, mCameraId,
mCharacteristicsMapNative);
if (!success) {
throw new IllegalArgumentException("Unsupported extensions");
}
try {
if (!isExtensionSupported(mCameraId, extension, mCharacteristicsMapNative)) {
throw new IllegalArgumentException("Unsupported extension");
}
android.hardware.camera2.extension.Size sz =
new android.hardware.camera2.extension.Size();
sz.width = captureOutputSize.getWidth();
sz.height = captureOutputSize.getHeight();
if (areAdvancedExtensionsSupported(extension)) {
IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
extender.init(mCameraId, mCharacteristicsMapNative);
LatencyRange latencyRange = extender.getEstimatedCaptureLatencyRange(mCameraId,
sz, format);
if (latencyRange != null) {
return new Range(latencyRange.min, latencyRange.max);
}
} else {
Pair extenders =
initializeExtension(extension);
extenders.second.init(mCameraId, mCharacteristicsMapNative.get(mCameraId));
if ((format == ImageFormat.YUV_420_888) &&
(extenders.second.getCaptureProcessor() == null) ){
// Extensions that don't implement any capture processor are limited to
// JPEG only!
return null;
}
if ((format == ImageFormat.JPEG) &&
(extenders.second.getCaptureProcessor() != null)) {
// The framework will perform the additional encoding pass on the
// processed YUV_420 buffers. Latency in this case is very device
// specific and cannot be estimated accurately enough.
return null;
}
if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010) {
// JpegR/UltraHDR + YCBCR_P010 is not supported for basic extensions
return null;
}
LatencyRange latencyRange = extenders.second.getEstimatedCaptureLatencyRange(sz);
if (latencyRange != null) {
return new Range(latencyRange.min, latencyRange.max);
}
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to query the extension capture latency! Extension service does"
+ " not respond!");
} finally {
unregisterClient(mContext, token, extension);
}
return null;
}
/**
* Retrieve support for capture progress callbacks via
* {@link CameraExtensionSession.ExtensionCaptureCallback#onCaptureProcessProgressed}.
*
* @param extension the extension type
* @return {@code true} in case progress callbacks are supported, {@code false} otherwise
*
* @throws IllegalArgumentException in case of an unsupported extension.
*/
public boolean isCaptureProcessProgressAvailable(@Extension int extension) {
final IBinder token = new Binder(TAG + "#isCaptureProcessProgressAvailable:" + mCameraId);
boolean success = registerClient(mContext, token, extension, mCameraId,
mCharacteristicsMapNative);
if (!success) {
throw new IllegalArgumentException("Unsupported extensions");
}
try {
if (!isExtensionSupported(mCameraId, extension, mCharacteristicsMapNative)) {
throw new IllegalArgumentException("Unsupported extension");
}
if (areAdvancedExtensionsSupported(extension)) {
IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
extender.init(mCameraId, mCharacteristicsMapNative);
return extender.isCaptureProcessProgressAvailable();
} else {
Pair extenders =
initializeExtension(extension);
extenders.second.init(mCameraId, mCharacteristicsMapNative.get(mCameraId));
return extenders.second.isCaptureProcessProgressAvailable();
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to query the extension progress callbacks! Extension service does"
+ " not respond!");
} finally {
unregisterClient(mContext, token, extension);
}
return false;
}
/**
* Returns the set of keys supported by a {@link CaptureRequest} submitted in a
* {@link CameraExtensionSession} with a given extension type.
*
* The set returned is not modifiable, so any attempts to modify it will throw
* a {@code UnsupportedOperationException}.
*
* Devices launching on Android {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}
* or newer versions are required to support {@link CaptureRequest#CONTROL_AF_MODE},
* {@link CaptureRequest#CONTROL_AF_REGIONS}, {@link CaptureRequest#CONTROL_AF_TRIGGER},
* {@link CaptureRequest#CONTROL_ZOOM_RATIO} for
* {@link CameraExtensionCharacteristics#EXTENSION_NIGHT}.
*
* @param extension the extension type
*
* @return non-modifiable set of capture keys supported by camera extension session initialized
* with the given extension type.
* @throws IllegalArgumentException in case of unsupported extension.
*/
@NonNull
public Set getAvailableCaptureRequestKeys(@Extension int extension) {
final IBinder token = new Binder(TAG + "#getAvailableCaptureRequestKeys:" + mCameraId);
boolean success = registerClient(mContext, token, extension, mCameraId,
mCharacteristicsMapNative);
if (!success) {
throw new IllegalArgumentException("Unsupported extensions");
}
HashSet ret = new HashSet<>();
try {
if (!isExtensionSupported(mCameraId, extension, mCharacteristicsMapNative)) {
throw new IllegalArgumentException("Unsupported extension");
}
CameraMetadataNative captureRequestMeta = null;
if (areAdvancedExtensionsSupported(extension)) {
IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
extender.init(mCameraId, mCharacteristicsMapNative);
captureRequestMeta = extender.getAvailableCaptureRequestKeys(mCameraId);
} else {
Pair extenders =
initializeExtension(extension);
extenders.second.onInit(token, mCameraId,
mCharacteristicsMapNative.get(mCameraId));
extenders.second.init(mCameraId, mCharacteristicsMapNative.get(mCameraId));
captureRequestMeta = extenders.second.getAvailableCaptureRequestKeys();
extenders.second.onDeInit(token);
}
if (captureRequestMeta != null) {
int[] requestKeys = captureRequestMeta.get(
CameraCharacteristics.REQUEST_AVAILABLE_REQUEST_KEYS);
if (requestKeys == null) {
throw new AssertionError(
"android.request.availableRequestKeys must be non-null"
+ " in the characteristics");
}
CameraCharacteristics requestChars = new CameraCharacteristics(
captureRequestMeta);
Object crKey = CaptureRequest.Key.class;
Class> crKeyTyped = (Class>) crKey;
ret.addAll(requestChars.getAvailableKeyList(CaptureRequest.class, crKeyTyped,
requestKeys, /*includeSynthetic*/ true));
}
// Jpeg quality and orientation must always be supported
if (!ret.contains(CaptureRequest.JPEG_QUALITY)) {
ret.add(CaptureRequest.JPEG_QUALITY);
}
if (!ret.contains(CaptureRequest.JPEG_ORIENTATION)) {
ret.add(CaptureRequest.JPEG_ORIENTATION);
}
} catch (RemoteException e) {
throw new IllegalStateException("Failed to query the available capture request keys!");
} finally {
unregisterClient(mContext, token, extension);
}
return Collections.unmodifiableSet(ret);
}
/**
* Returns the set of keys supported by a {@link CaptureResult} passed as an argument to
* {@link CameraExtensionSession.ExtensionCaptureCallback#onCaptureResultAvailable}.
*
* The set returned is not modifiable, so any attempts to modify it will throw
* a {@code UnsupportedOperationException}.
*
* In case the set is empty, then the extension is not able to support any capture results
* and the {@link CameraExtensionSession.ExtensionCaptureCallback#onCaptureResultAvailable}
* callback will not be fired.
*
* Devices launching on Android {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}
* or newer versions are required to support {@link CaptureResult#CONTROL_AF_MODE},
* {@link CaptureResult#CONTROL_AF_REGIONS}, {@link CaptureResult#CONTROL_AF_TRIGGER},
* {@link CaptureResult#CONTROL_AF_STATE}, {@link CaptureResult#CONTROL_ZOOM_RATIO} for
* {@link CameraExtensionCharacteristics#EXTENSION_NIGHT}.
*
* @param extension the extension type
*
* @return non-modifiable set of capture result keys supported by camera extension session
* initialized with the given extension type.
* @throws IllegalArgumentException in case of unsupported extension.
*/
@NonNull
public Set getAvailableCaptureResultKeys(@Extension int extension) {
final IBinder token = new Binder(TAG + "#getAvailableCaptureResultKeys:" + mCameraId);
boolean success = registerClient(mContext, token, extension, mCameraId,
mCharacteristicsMapNative);
if (!success) {
throw new IllegalArgumentException("Unsupported extensions");
}
HashSet ret = new HashSet<>();
try {
if (!isExtensionSupported(mCameraId, extension, mCharacteristicsMapNative)) {
throw new IllegalArgumentException("Unsupported extension");
}
CameraMetadataNative captureResultMeta = null;
if (areAdvancedExtensionsSupported(extension)) {
IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
extender.init(mCameraId, mCharacteristicsMapNative);
captureResultMeta = extender.getAvailableCaptureResultKeys(mCameraId);
} else {
Pair extenders =
initializeExtension(extension);
extenders.second.onInit(token, mCameraId,
mCharacteristicsMapNative.get(mCameraId));
extenders.second.init(mCameraId, mCharacteristicsMapNative.get(mCameraId));
captureResultMeta = extenders.second.getAvailableCaptureResultKeys();
extenders.second.onDeInit(token);
}
if (captureResultMeta != null) {
int[] resultKeys = captureResultMeta.get(
CameraCharacteristics.REQUEST_AVAILABLE_RESULT_KEYS);
if (resultKeys == null) {
throw new AssertionError("android.request.availableResultKeys must be non-null "
+ "in the characteristics");
}
CameraCharacteristics resultChars = new CameraCharacteristics(captureResultMeta);
Object crKey = CaptureResult.Key.class;
Class> crKeyTyped = (Class>) crKey;
ret.addAll(resultChars.getAvailableKeyList(CaptureResult.class, crKeyTyped,
resultKeys, /*includeSynthetic*/ true));
// Jpeg quality, orientation and sensor timestamp must always be supported
if (!ret.contains(CaptureResult.JPEG_QUALITY)) {
ret.add(CaptureResult.JPEG_QUALITY);
}
if (!ret.contains(CaptureResult.JPEG_ORIENTATION)) {
ret.add(CaptureResult.JPEG_ORIENTATION);
}
if (!ret.contains(CaptureResult.SENSOR_TIMESTAMP)) {
ret.add(CaptureResult.SENSOR_TIMESTAMP);
}
}
} catch (RemoteException e) {
throw new IllegalStateException("Failed to query the available capture result keys!");
} finally {
unregisterClient(mContext, token, extension);
}
return Collections.unmodifiableSet(ret);
}
/**
* Minimum and maximum padding zoom factors supported by this camera device for
* {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } used for
* the {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
* extension.
* The minimum and maximum padding zoom factors supported by the device for
* {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } used as part of the
* {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
* extension feature. This extension specific camera characteristic can be queried using
* {@link android.hardware.camera2.CameraExtensionCharacteristics#get}.
* Units: A pair of padding zoom factors in floating-points:
* (minPaddingZoomFactor, maxPaddingZoomFactor)
* Range of valid values:
* 1.0 < minPaddingZoomFactor <= maxPaddingZoomFactor
* Optional - The value for this key may be {@code null} on some devices.
*/
@PublicKey
@NonNull
@ExtensionKey
@FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
public static final Key> EFV_PADDING_ZOOM_FACTOR_RANGE =
CameraCharacteristics.EFV_PADDING_ZOOM_FACTOR_RANGE;
}