Merge "Camera Extensions: Add Get API to Framework" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index f4a9bd1..d7a99d3 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -19154,11 +19154,13 @@
}
public final class CameraExtensionCharacteristics {
+ method @FlaggedApi("com.android.internal.camera.flags.camera_extensions_characteristics_get") public <T> T get(int, @NonNull android.hardware.camera2.CameraCharacteristics.Key<T>);
method @NonNull public java.util.Set<android.hardware.camera2.CaptureRequest.Key> getAvailableCaptureRequestKeys(int);
method @NonNull public java.util.Set<android.hardware.camera2.CaptureResult.Key> getAvailableCaptureResultKeys(int);
method @Nullable public android.util.Range<java.lang.Long> getEstimatedCaptureLatencyRangeMillis(int, @NonNull android.util.Size, int);
method @NonNull public <T> java.util.List<android.util.Size> getExtensionSupportedSizes(int, @NonNull Class<T>);
method @NonNull public java.util.List<android.util.Size> getExtensionSupportedSizes(int, int);
+ method @FlaggedApi("com.android.internal.camera.flags.camera_extensions_characteristics_get") @NonNull public java.util.Set<android.hardware.camera2.CameraCharacteristics.Key> getKeys(int);
method @NonNull public java.util.List<android.util.Size> getPostviewSupportedSizes(int, @NonNull android.util.Size, int);
method @NonNull public java.util.List<java.lang.Integer> getSupportedExtensions();
method public boolean isCaptureProcessProgressAvailable(int);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index f026b57..ca45be8 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4581,6 +4581,7 @@
ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") protected AdvancedExtender(@NonNull android.hardware.camera2.CameraManager);
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public abstract java.util.List<android.hardware.camera2.CaptureRequest.Key> getAvailableCaptureRequestKeys(@NonNull String);
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public abstract java.util.List<android.hardware.camera2.CaptureResult.Key> getAvailableCaptureResultKeys(@NonNull String);
+ method @FlaggedApi("com.android.internal.camera.flags.camera_extensions_characteristics_get") @NonNull public abstract java.util.List<android.util.Pair<android.hardware.camera2.CameraCharacteristics.Key,java.lang.Object>> getAvailableCharacteristicsKeyValues();
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public long getMetadataVendorId(@NonNull String);
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public abstract android.hardware.camera2.extension.SessionProcessor getSessionProcessor();
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public abstract java.util.Map<java.lang.Integer,java.util.List<android.util.Size>> getSupportedCaptureOutputResolutions(@NonNull String);
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 1867a17..7abe821 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -624,6 +624,120 @@
}
/**
+ * Gets an extension specific camera characteristics field value.
+ *
+ * <p>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 <T> @Nullable T get(@Extension int extension,
+ @NonNull CameraCharacteristics.Key<T> key) {
+ final IBinder token = new Binder(TAG + "#get:" + mCameraId);
+ boolean success = registerClient(mContext, token);
+ if (!success) {
+ throw new IllegalArgumentException("Unsupported extensions");
+ }
+
+ try {
+ if (!isExtensionSupported(mCameraId, extension, mCharacteristicsMapNative)) {
+ throw new IllegalArgumentException("Unsupported extension");
+ }
+
+ if (areAdvancedExtensionsSupported() && getKeys(extension).contains(key)) {
+ IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
+ extender.init(mCameraId, mCharacteristicsMapNative);
+ CameraMetadataNative metadata =
+ extender.getAvailableCharacteristicsKeyValues(mCameraId);
+ CameraCharacteristics fallbackCharacteristics = mCharacteristicsMap.get(mCameraId);
+ if (metadata == null) {
+ return fallbackCharacteristics.get(key);
+ }
+ CameraCharacteristics characteristics = new CameraCharacteristics(metadata);
+ T value = characteristics.get(key);
+ return value == null ? fallbackCharacteristics.get(key) : value;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to query the extension for the specified key! Extension "
+ + "service does not respond!");
+ } finally {
+ unregisterClient(mContext, token);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the {@link CameraCharacteristics} keys that have extension-specific values.
+ *
+ * <p>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<CameraCharacteristics.Key> getKeys(@Extension int extension) {
+ final IBinder token =
+ new Binder(TAG + "#getKeys:" + mCameraId);
+ boolean success = registerClient(mContext, token);
+ if (!success) {
+ throw new IllegalArgumentException("Unsupported extensions");
+ }
+
+ HashSet<CameraCharacteristics.Key> ret = new HashSet<>();
+
+ try {
+ if (!isExtensionSupported(mCameraId, extension, mCharacteristicsMapNative)) {
+ throw new IllegalArgumentException("Unsupported extension");
+ }
+
+ if (areAdvancedExtensionsSupported()) {
+ 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<CameraCharacteristics.Key<?>> keyTyped =
+ (Class<CameraCharacteristics.Key<?>>) key;
+
+ ret.addAll(chars.getAvailableKeyList(CameraCharacteristics.class, keyTyped, keys,
+ /*includeSynthetic*/ true));
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to query the extension for all available keys! Extension "
+ + "service does not respond!");
+ } finally {
+ unregisterClient(mContext, token);
+ }
+ return Collections.unmodifiableSet(ret);
+ }
+
+ /**
* Checks for postview support of still capture.
*
* <p>A postview is a preview version of the still capture that is available before the final
diff --git a/core/java/android/hardware/camera2/extension/AdvancedExtender.java b/core/java/android/hardware/camera2/extension/AdvancedExtender.java
index fb2df54..a06f017 100644
--- a/core/java/android/hardware/camera2/extension/AdvancedExtender.java
+++ b/core/java/android/hardware/camera2/extension/AdvancedExtender.java
@@ -27,6 +27,7 @@
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.impl.CaptureCallback;
import android.util.Log;
+import android.util.Pair;
import android.util.Size;
import com.android.internal.camera.flags.Flags;
@@ -222,6 +223,23 @@
public abstract List<CaptureResult.Key> getAvailableCaptureResultKeys(
@NonNull String cameraId);
+ /**
+ * Returns a list of {@link CameraCharacteristics} key/value pairs for apps to use when
+ * querying the Extensions specific {@link CameraCharacteristics}.
+ *
+ * <p>To ensure the correct {@link CameraCharacteristics} are used when an extension is
+ * enabled, an application should prioritize the value returned from the list if the
+ * {@link CameraCharacteristics} key is present. If the key doesn't exist in the returned list,
+ * then the application should query the value using
+ * {@link CameraCharacteristics#get(CameraCharacteristics.Key)}.
+ *
+ * <p>For example, an extension may limit the zoom ratio range. In this case, an OEM can return
+ * a new zoom ratio range for the key {@link CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE}.
+ */
+ @FlaggedApi(Flags.FLAG_CAMERA_EXTENSIONS_CHARACTERISTICS_GET)
+ @NonNull
+ public abstract List<Pair<CameraCharacteristics.Key, Object>>
+ getAvailableCharacteristicsKeyValues();
private final class AdvancedExtenderImpl extends IAdvancedExtenderImpl.Stub {
@Override
@@ -322,6 +340,33 @@
// Feature is currently unsupported
return false;
}
+
+ @FlaggedApi(Flags.FLAG_CAMERA_EXTENSIONS_CHARACTERISTICS_GET)
+ @Override
+ public CameraMetadataNative getAvailableCharacteristicsKeyValues(String cameraId) {
+ List<Pair<CameraCharacteristics.Key, Object>> entries =
+ AdvancedExtender.this.getAvailableCharacteristicsKeyValues();
+
+ if ((entries != null) && !entries.isEmpty()) {
+ CameraMetadataNative ret = new CameraMetadataNative();
+ long vendorId = mMetadataVendorIdMap.containsKey(cameraId)
+ ? mMetadataVendorIdMap.get(cameraId) : Long.MAX_VALUE;
+ ret.setVendorId(vendorId);
+ int[] characteristicsKeyTags = new int[entries.size()];
+ int i = 0;
+ for (Pair<CameraCharacteristics.Key, Object> entry : entries) {
+ int tag = CameraMetadataNative.getTag(entry.first.getName(), vendorId);
+ characteristicsKeyTags[i++] = tag;
+ ret.set(entry.first, entry.second);
+ }
+ ret.set(CameraCharacteristics.REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
+ characteristicsKeyTags);
+
+ return ret;
+ }
+
+ return null;
+ }
}
@NonNull IAdvancedExtenderImpl getAdvancedExtenderBinder() {
diff --git a/core/java/android/hardware/camera2/extension/IAdvancedExtenderImpl.aidl b/core/java/android/hardware/camera2/extension/IAdvancedExtenderImpl.aidl
index 101442f..3071f0d 100644
--- a/core/java/android/hardware/camera2/extension/IAdvancedExtenderImpl.aidl
+++ b/core/java/android/hardware/camera2/extension/IAdvancedExtenderImpl.aidl
@@ -38,4 +38,5 @@
CameraMetadataNative getAvailableCaptureResultKeys(in String cameraId);
boolean isCaptureProcessProgressAvailable();
boolean isPostviewAvailable();
+ CameraMetadataNative getAvailableCharacteristicsKeyValues(in String cameraId);
}
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 155c523..c134a4c 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -120,6 +120,7 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -142,11 +143,13 @@
// Support for various latency improvements
private static final String LATENCY_VERSION_PREFIX = "1.4";
private static final String EFV_VERSION_PREFIX = "1.5";
+ private static final String GET_VERSION_PREFIX = "1.5";
private static final String[] ADVANCED_VERSION_PREFIXES = {EFV_VERSION_PREFIX,
- LATENCY_VERSION_PREFIX, ADVANCED_VERSION_PREFIX, RESULTS_VERSION_PREFIX };
+ LATENCY_VERSION_PREFIX, ADVANCED_VERSION_PREFIX, RESULTS_VERSION_PREFIX,
+ GET_VERSION_PREFIX};
private static final String[] SUPPORTED_VERSION_PREFIXES = {EFV_VERSION_PREFIX,
LATENCY_VERSION_PREFIX, RESULTS_VERSION_PREFIX, ADVANCED_VERSION_PREFIX, "1.1",
- NON_INIT_VERSION_PREFIX};
+ NON_INIT_VERSION_PREFIX, GET_VERSION_PREFIX};
private static final boolean EXTENSIONS_PRESENT = checkForExtensions();
private static final String EXTENSIONS_VERSION = EXTENSIONS_PRESENT ?
(new ExtensionVersionImpl()).checkApiVersion(LATEST_VERSION) : null;
@@ -156,6 +159,8 @@
(EXTENSIONS_VERSION.startsWith(EFV_VERSION_PREFIX)));
private static final boolean EFV_SUPPORTED = EXTENSIONS_PRESENT &&
(EXTENSIONS_VERSION.startsWith(EFV_VERSION_PREFIX));
+ private static final boolean GET_API_SUPPORTED = EXTENSIONS_PRESENT
+ && (EXTENSIONS_VERSION.startsWith(GET_VERSION_PREFIX));
private static final boolean ADVANCED_API_SUPPORTED = checkForAdvancedAPI();
private static final boolean INIT_API_SUPPORTED = EXTENSIONS_PRESENT &&
(!EXTENSIONS_VERSION.startsWith(NON_INIT_VERSION_PREFIX));
@@ -777,6 +782,12 @@
public boolean isPostviewAvailable() {
return false;
}
+
+ @Override
+ public List<Pair<CameraCharacteristics.Key, Object>>
+ getAvailableCharacteristicsKeyValues() {
+ return Collections.emptyList();
+ }
};
}
}
@@ -1186,6 +1197,35 @@
return false;
}
+
+ @Override
+ public CameraMetadataNative getAvailableCharacteristicsKeyValues(String cameraId) {
+ if (GET_API_SUPPORTED) {
+ List<Pair<CameraCharacteristics.Key, Object>> entries =
+ mAdvancedExtender.getAvailableCharacteristicsKeyValues();
+
+ if ((entries != null) && !entries.isEmpty()) {
+ CameraMetadataNative ret = new CameraMetadataNative();
+ long vendorId = mMetadataVendorIdMap.containsKey(cameraId)
+ ? mMetadataVendorIdMap.get(cameraId) : Long.MAX_VALUE;
+ ret.setVendorId(vendorId);
+ int[] characteristicsKeyTags = new int[entries.size()];
+ int i = 0;
+ for (Pair<CameraCharacteristics.Key, Object> entry : entries) {
+ int tag = CameraMetadataNative.getTag(entry.first.getName(), vendorId);
+ characteristicsKeyTags[i++] = tag;
+ ret.set(entry.first, entry.second);
+ }
+ ret.set(CameraCharacteristics.REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
+ characteristicsKeyTags);
+
+ return ret;
+ }
+ }
+
+ return null;
+ }
+
}
private class CaptureCallbackStub implements SessionProcessorImpl.CaptureCallback {