Camera: Add support for isSessionConfigurationWithParametersSupported
- isSessionConfigurationWithParametersSupported takes into consideration
the session parameters.
- As part of CameraManager so that the application doesn't need to
open the camera device first.
Test: Camera CTS test with flag enabled
Bug: 309627704
Change-Id: I863b5c65a91d6d5b0f6f30749bfa8c66248c31e3
diff --git a/core/api/current.txt b/core/api/current.txt
index 5310fdc..26d3fb0 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -18828,6 +18828,7 @@
field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_TORCH_STRENGTH_MAX_LEVEL;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.DeviceStateSensorOrientationMap> INFO_DEVICE_STATE_SENSOR_ORIENTATION_MAP;
+ field @FlaggedApi("com.android.internal.camera.flags.feature_combination_query") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SESSION_CONFIGURATION_QUERY_VERSION;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SUPPORTED_HARDWARE_LEVEL;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.String> INFO_VERSION;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES;
@@ -18938,7 +18939,7 @@
method @Deprecated public abstract void createReprocessableCaptureSessionByConfigurations(@NonNull android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public int getCameraAudioRestriction() throws android.hardware.camera2.CameraAccessException;
method @NonNull public abstract String getId();
- method public boolean isSessionConfigurationSupported(@NonNull android.hardware.camera2.params.SessionConfiguration) throws android.hardware.camera2.CameraAccessException;
+ method @Deprecated public boolean isSessionConfigurationSupported(@NonNull android.hardware.camera2.params.SessionConfiguration) throws android.hardware.camera2.CameraAccessException;
method public void setCameraAudioRestriction(int) throws android.hardware.camera2.CameraAccessException;
field public static final int AUDIO_RESTRICTION_NONE = 0; // 0x0
field public static final int AUDIO_RESTRICTION_VIBRATION = 1; // 0x1
@@ -19016,12 +19017,14 @@
}
public final class CameraManager {
+ method @FlaggedApi("com.android.internal.camera.flags.feature_combination_query") @NonNull @RequiresPermission(android.Manifest.permission.CAMERA) public android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(@NonNull String, int) throws android.hardware.camera2.CameraAccessException;
method @NonNull public android.hardware.camera2.CameraCharacteristics getCameraCharacteristics(@NonNull String) throws android.hardware.camera2.CameraAccessException;
method @NonNull public android.hardware.camera2.CameraExtensionCharacteristics getCameraExtensionCharacteristics(@NonNull String) throws android.hardware.camera2.CameraAccessException;
method @NonNull public String[] getCameraIdList() throws android.hardware.camera2.CameraAccessException;
method @NonNull public java.util.Set<java.util.Set<java.lang.String>> getConcurrentCameraIds() throws android.hardware.camera2.CameraAccessException;
method public int getTorchStrengthLevel(@NonNull String) throws android.hardware.camera2.CameraAccessException;
method @RequiresPermission(android.Manifest.permission.CAMERA) public boolean isConcurrentSessionConfigurationSupported(@NonNull java.util.Map<java.lang.String,android.hardware.camera2.params.SessionConfiguration>) throws android.hardware.camera2.CameraAccessException;
+ method @FlaggedApi("com.android.internal.camera.flags.feature_combination_query") @RequiresPermission(android.Manifest.permission.CAMERA) public boolean isSessionConfigurationWithParametersSupported(@NonNull String, @NonNull android.hardware.camera2.params.SessionConfiguration) throws android.hardware.camera2.CameraAccessException;
method @RequiresPermission(android.Manifest.permission.CAMERA) public void openCamera(@NonNull String, @NonNull android.hardware.camera2.CameraDevice.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method @RequiresPermission(android.Manifest.permission.CAMERA) public void openCamera(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException;
method public void registerAvailabilityCallback(@NonNull android.hardware.camera2.CameraManager.AvailabilityCallback, @Nullable android.os.Handler);
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 9125856..f8d48d1 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -3490,7 +3490,7 @@
* <p>When the key is present, only a PRIVATE/YUV output of the specified size is guaranteed
* to be supported by the camera HAL in the secure camera mode. Any other format or
* resolutions might not be supported. Use
- * {@link CameraDevice#isSessionConfigurationSupported }
+ * {@link CameraManager#isSessionConfigurationWithParametersSupported }
* API to query if a secure session configuration is supported if the device supports this
* API.</p>
* <p>If this key returns null on a device with SECURE_IMAGE_DATA capability, the application
@@ -5009,6 +5009,290 @@
new Key<long[]>("android.info.deviceStateOrientations", long[].class);
/**
+ * <p>The version of the session configuration query
+ * {@link android.hardware.camera2.CameraManager#isSessionConfigurationWithParametersSupported }
+ * API</p>
+ * <p>The possible values in this key correspond to the values defined in
+ * android.os.Build.VERSION_CODES. Each version defines a set of feature combinations the
+ * camera device must reliably report whether they are supported via
+ * {@link android.hardware.camera2.CameraManager#isSessionConfigurationWithParametersSupported }
+ * API. And the version is always less or equal to android.os.Build.VERSION.SDK_INT.</p>
+ * <p>If set to UPSIDE_DOWN_CAKE, this camera device doesn't support
+ * {@link android.hardware.camera2.CameraManager#isSessionConfigurationWithParametersSupported }.
+ * Calling the method for this camera ID throws an UnsupportedOperationException.</p>
+ * <p>If set to VANILLA_ICE_CREAM, the application can call
+ * {@link android.hardware.camera2.CameraManager#isSessionConfigurationWithParametersSupported }
+ * to check if the combinations of below features are supported.</p>
+ * <ul>
+ * <li>A subset of LIMITED-level device stream combinations.</li>
+ * </ul>
+ * <table>
+ * <thead>
+ * <tr>
+ * <th style="text-align: center;">Target 1</th>
+ * <th style="text-align: center;">Size</th>
+ * <th style="text-align: center;">Target 2</th>
+ * <th style="text-align: center;">Size</th>
+ * <th style="text-align: center;">Sample use case(s)</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">MAXIMUM</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;">Simple preview, GPU video processing, or no-preview video recording.</td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PREVIEW</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S1440P</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S720P</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">MAXIMUM</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;">In-application video/image processing.</td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">PREVIEW</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">S1440P</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">S720P</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PREVIEW</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">MAXIMUM</td>
+ * <td style="text-align: center;">Standard still imaging.</td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S1440P</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">MAXIMUM</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">MAXIMUM</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S720P</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">MAXIMUM</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S1440P</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">S1440P</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S720P</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">PREVIEW</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">MAXIMUM</td>
+ * <td style="text-align: center;">In-app processing plus still capture.</td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">S1440P</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">MAXIMUM</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">MAXIMUM</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">S720P</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">MAXIMUM</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">S1440P</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">S1440P</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">S720P</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PREVIEW</td>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PREVIEW</td>
+ * <td style="text-align: center;">Standard recording.</td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S1440P</td>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S1440P</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S720P</td>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S720P</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PREVIEW</td>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">PREVIEW</td>
+ * <td style="text-align: center;">Preview plus in-app processing.</td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S1440P</td>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">S1440P</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">S720P</td>
+ * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">S720P</td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * <pre><code>- {@code MAXIMUM} size refers to the camera device's maximum output resolution for
+ * that format from {@code StreamConfigurationMap#getOutputSizes}. {@code PREVIEW} size
+ * refers to the best size match to the device's screen resolution, or to 1080p
+ * (@code 1920x1080}, whichever is smaller. Both sizes are guaranteed to be supported.
+ *
+ * - {@code S1440P} refers to {@code 1920x1440 (4:3)} and {@code 2560x1440 (16:9)}.
+ * {@code S1080P} refers to {@code 1440x1080 (4:3)} and {@code 1920x1080 (16:9)}.
+ * And {@code S720P} refers to {@code 960x720 (4:3)} and {@code 1280x720 (16:9)}.
+ *
+ * - If a combination contains a S1440P, S1080P, or S720P stream,
+ * both 4:3 and 16:9 aspect ratio sizes can be queried. For example, for the
+ * stream combination of {PRIV, S1440P, JPEG, MAXIMUM}, and if MAXIMUM ==
+ * 4032 x 3024, the application will be able to query both
+ * {PRIV, 1920 x 1440, JPEG, 4032 x 3024} and {PRIV, 2560 x 1440, JPEG, 4032 x 2268}
+ * without an exception being thrown.
+ * </code></pre>
+ * <ul>
+ * <li>VIDEO_STABILIZATION_MODES: {OFF, PREVIEW}</li>
+ * <li>AE_TARGET_FPS_RANGE: {{<em>, 30}, {</em>, 60}}</li>
+ * <li>DYNAMIC_RANGE_PROFILE: {STANDARD, HLG10}</li>
+ * </ul>
+ * <p>This key is available on all devices.</p>
+ */
+ @PublicKey
+ @NonNull
+ @FlaggedApi(Flags.FLAG_FEATURE_COMBINATION_QUERY)
+ public static final Key<Integer> INFO_SESSION_CONFIGURATION_QUERY_VERSION =
+ new Key<Integer>("android.info.sessionConfigurationQueryVersion", int.class);
+
+ /**
* <p>The maximum number of frames that can occur after a request
* (different than the previous) has been submitted, and before the
* result's state becomes synchronized.</p>
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index f4d783a..58cba41 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -894,7 +894,7 @@
* supported sizes.
* Camera clients that register a Jpeg/R output within a stream combination that doesn't fit
* in the mandatory stream table above can call
- * {@link CameraDevice#isSessionConfigurationSupported} to ensure that this particular
+ * {@link CameraManager#isSessionConfigurationWithParametersSupported} to ensure that this particular
* configuration is supported.</p>
*
* <h5>STREAM_USE_CASE capability additional guaranteed configurations</h5>
@@ -967,8 +967,8 @@
*
* <p>Since the capabilities of camera devices vary greatly, a given camera device may support
* target combinations with sizes outside of these guarantees, but this can only be tested for
- * by calling {@link #isSessionConfigurationSupported} or attempting to create a session with
- * such targets.</p>
+ * by calling {@link CameraManager#isSessionConfigurationWithParametersSupported} or attempting
+ * to create a session with such targets.</p>
*
* <p>Exception on 176x144 (QCIF) resolution:
* Camera devices usually have a fixed capability for downscaling from larger resolution to
@@ -1403,7 +1403,10 @@
* @throws CameraAccessException if the camera device is no longer connected or has
* encountered a fatal error
* @throws IllegalStateException if the camera device has been closed
+ * @deprecated Please use {@link CameraManager#isSessionConfigurationWithParametersSupported}
+ * to check whether a SessionConfiguration is supported by the device.
*/
+ @Deprecated
public boolean isSessionConfigurationSupported(
@NonNull SessionConfiguration sessionConfig) throws CameraAccessException {
throw new UnsupportedOperationException("Subclasses must override this method");
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index c80124c..002c0b2 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -17,6 +17,7 @@
package android.hardware.camera2;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -35,6 +36,7 @@
import android.hardware.CameraStatus;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
+import android.hardware.camera2.CameraDevice.RequestTemplate;
import android.hardware.camera2.impl.CameraDeviceImpl;
import android.hardware.camera2.impl.CameraInjectionSessionImpl;
import android.hardware.camera2.impl.CameraMetadataNative;
@@ -61,6 +63,7 @@
import android.util.Size;
import android.view.Display;
+import com.android.internal.camera.flags.Flags;
import com.android.internal.util.ArrayUtils;
import java.lang.ref.WeakReference;
@@ -349,6 +352,71 @@
}
/**
+ * Checks whether a particular {@link SessionConfiguration} is supported by a camera device.
+ *
+ * <p>This method performs a runtime check of a given {@link SessionConfiguration}. The result
+ * confirms whether or not the session configuration, including the
+ * {@link SessionConfiguration#setSessionParameters specified session parameters}, can
+ * be successfully used to create a camera capture session using
+ * {@link CameraDevice#createCaptureSession(
+ * android.hardware.camera2.params.SessionConfiguration)}.
+ * </p>
+ *
+ * <p>Supported if the {@link CameraCharacteristics#INFO_SESSION_CONFIGURATION_QUERY_VERSION}
+ * is at least {@code android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM}. If less or equal to
+ * {@code android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE}, this function throws
+ * {@code UnsupportedOperationException}.</p>
+ *
+ * <p>Although this method is much faster than creating a new capture session, it is not
+ * trivial cost: the latency is less than 5 milliseconds in most cases. As a result, the
+ * app should not use this to explore the entire space of supported session combinations.</p>
+ *
+ * <p>Instead, the application should use this method to query whether the
+ * combination of certain features are supported. See {@link
+ * CameraCharacteristics#INFO_SESSION_CONFIGURATION_QUERY_VERSION} for the list of feature
+ * combinations the camera device will reliably report.</p>
+ *
+ * <p>IMPORTANT:</p>
+ *
+ * <ul>
+ *
+ * <li>If a feature support can be queried with {@code CameraCharacteristics},
+ * the application must directly use {@code CameraCharacteristics} rather than
+ * calling this function. The reasons are: (1) using {@code CameraCharacteristics} is more
+ * efficient, and (2) calling this function with a non-supported feature will throw a {@code
+ * IllegalArgumentException}.</li>
+ *
+ * <li>To minimize latency for {@code SessionConfiguration} creation, the application should
+ * use deferred surfaces for SurfaceView and SurfaceTexture to avoid delays. Alternatively,
+ * the application can create {@code ImageReader} with {@code USAGE_COMPOSER_OVERLAY} and
+ * {@code USAGE_GPU_SAMPLED_IMAGE} usage respectively. For {@code MediaRecorder} and {@code
+ * MediaCodec}, the application can use {@code ImageReader} with {@code
+ * USAGE_VIDEO_ENCODE}. The lightweight nature of {@code ImageReader} helps minimize the
+ * latency cost.</li>
+ *
+ * </ul>
+ *
+ *
+ * @return {@code true} if the given session configuration is supported by the camera device
+ * {@code false} otherwise.
+ * @throws CameraAccessException if the camera device is no longer connected or has
+ * encountered a fatal error
+ * @throws IllegalArgumentException if the session configuration is invalid
+ * @throws UnsupportedOperationException if the query operation is not supported by the camera
+ * device
+ *
+ * @see CameraCharacteristics#INFO_SESSION_CONFIGURATION_QUERY_VERSION
+ */
+ @RequiresPermission(android.Manifest.permission.CAMERA)
+ @FlaggedApi(Flags.FLAG_FEATURE_COMBINATION_QUERY)
+ public boolean isSessionConfigurationWithParametersSupported(@NonNull String cameraId,
+ @NonNull SessionConfiguration sessionConfig) throws CameraAccessException {
+ //TODO: b/298033056: restructure the OutputConfiguration API for better usability
+ return CameraManagerGlobal.get().isSessionConfigurationWithParametersSupported(
+ cameraId, sessionConfig);
+ }
+
+ /**
* Register a callback to be notified about camera device availability.
*
* <p>Registering the same callback again will replace the handler with the
@@ -1242,6 +1310,48 @@
}
/**
+ * Create a {@link CaptureRequest.Builder} for new capture requests,
+ * initialized with template for a target use case.
+ *
+ * <p>The settings are chosen to be the best options for the specific camera device,
+ * so it is not recommended to reuse the same request for a different camera device;
+ * create a builder specific for that device and template and override the
+ * settings as desired, instead.</p>
+ *
+ * <p>Supported if the {@link CameraCharacteristics#INFO_SESSION_CONFIGURATION_QUERY_VERSION}
+ * is at least {@code android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM}. If less or equal to
+ * {@code android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE}, this function throws a
+ * {@code UnsupportedOperationException}.
+ *
+ * @param cameraId The camera ID to create capture request for.
+ * @param templateType An enumeration selecting the use case for this request. Not all template
+ * types are supported on every device. See the documentation for each template type for
+ * details.
+ * @return a builder for a capture request, initialized with default
+ * settings for that template, and no output streams
+ *
+ * @throws CameraAccessException if the camera device is no longer connected or has
+ * encountered a fatal error
+ * @throws IllegalArgumentException if the cameraId is not valid, or the templateType is
+ * not supported by this device.
+ * @throws UnsupportedOperationException if this method is not supported by the camera device,
+ * for example, if {@link CameraCharacteristics#INFO_SESSION_CONFIGURATION_QUERY_VERSION}
+ * is less than {@code android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM}.
+ */
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.CAMERA)
+ @FlaggedApi(Flags.FLAG_FEATURE_COMBINATION_QUERY)
+ public CaptureRequest.Builder createCaptureRequest(@NonNull String cameraId,
+ @RequestTemplate int templateType) throws CameraAccessException {
+ if (CameraManagerGlobal.sCameraServiceDisabled) {
+ throw new IllegalArgumentException("No camera available on device.");
+ }
+
+ return CameraManagerGlobal.get().createCaptureRequest(cameraId, templateType,
+ mContext.getApplicationInfo().targetSdkVersion);
+ }
+
+ /**
* @hide
*/
public static boolean shouldOverrideToPortrait(@Nullable Context context) {
@@ -2245,6 +2355,26 @@
return false;
}
+ public boolean isSessionConfigurationWithParametersSupported(
+ @NonNull String cameraId, @NonNull SessionConfiguration sessionConfiguration)
+ throws CameraAccessException {
+
+ synchronized (mLock) {
+ try {
+ return mCameraService.isSessionConfigurationWithParametersSupported(
+ cameraId, sessionConfiguration);
+ } catch (ServiceSpecificException e) {
+ throwAsPublicException(e);
+ } catch (RemoteException e) {
+ // Camera service died - act as if the camera was disconnected
+ throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
+ "Camera service is currently unavailable", e);
+ }
+ }
+
+ return false;
+ }
+
/**
* Helper function to find out if a camera id is in the set of combinations returned by
* getConcurrentCameraIds()
@@ -2344,6 +2474,45 @@
return torchStrength;
}
+ public CaptureRequest.Builder createCaptureRequest(@NonNull String cameraId,
+ @RequestTemplate int templateType, int targetSdkVersion)
+ throws CameraAccessException {
+ CaptureRequest.Builder builder = null;
+ synchronized (mLock) {
+ if (cameraId == null) {
+ throw new IllegalArgumentException("cameraId was null");
+ }
+
+ ICameraService cameraService = getCameraService();
+ if (cameraService == null) {
+ throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
+ "Camera service is currently unavailable.");
+ }
+
+ try {
+ CameraMetadataNative defaultRequest =
+ cameraService.createDefaultRequest(cameraId, templateType);
+
+ CameraDeviceImpl.disableZslIfNeeded(defaultRequest,
+ targetSdkVersion, templateType);
+
+ builder = new CaptureRequest.Builder(defaultRequest, /*reprocess*/false,
+ CameraCaptureSession.SESSION_ID_NONE, cameraId,
+ /*physicalCameraIdSet*/null);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ICameraService.ERROR_INVALID_OPERATION) {
+ throw new UnsupportedOperationException(e.getMessage());
+ }
+
+ throwAsPublicException(e);
+ } catch (RemoteException e) {
+ throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
+ "Camera service is currently unavailable.");
+ }
+ }
+ return builder;
+ }
+
private void handleRecoverableSetupErrors(ServiceSpecificException e) {
switch (e.errorCode) {
case ICameraService.ERROR_DISCONNECTED:
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 530f75e..765a8f7 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -907,10 +907,10 @@
* </ul>
* <p>Combinations of logical and physical streams, or physical streams from different
* physical cameras are not guaranteed. However, if the camera device supports
- * {@link CameraDevice#isSessionConfigurationSupported },
+ * {@link CameraManager#isSessionConfigurationWithParametersSupported },
* application must be able to query whether a stream combination involving physical
* streams is supported by calling
- * {@link CameraDevice#isSessionConfigurationSupported }.</p>
+ * {@link CameraManager#isSessionConfigurationWithParametersSupported }.</p>
* <p>Camera application shouldn't assume that there are at most 1 rear camera and 1 front
* camera in the system. For an application that switches between front and back cameras,
* the recommendation is to switch between the first rear camera and the first front
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 93cae54..06397c9 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -55,7 +55,8 @@
* capture.</p>
*
* <p>CaptureRequests can be created by using a {@link Builder} instance,
- * obtained by calling {@link CameraDevice#createCaptureRequest}</p>
+ * obtained by calling {@link CameraDevice#createCaptureRequest} or {@link
+ * CameraManager#createCaptureRequest}</p>
*
* <p>CaptureRequests are given to {@link CameraCaptureSession#capture} or
* {@link CameraCaptureSession#setRepeatingRequest} to capture images from a camera.</p>
@@ -82,6 +83,7 @@
* @see CameraCaptureSession#setRepeatingBurst
* @see CameraDevice#createCaptureRequest
* @see CameraDevice#createReprocessCaptureRequest
+ * @see CameraManager#createCaptureRequest
*/
public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
implements Parcelable {
@@ -793,8 +795,9 @@
* A builder for capture requests.
*
* <p>To obtain a builder instance, use the
- * {@link CameraDevice#createCaptureRequest} method, which initializes the
- * request fields to one of the templates defined in {@link CameraDevice}.
+ * {@link CameraDevice#createCaptureRequest} or {@link CameraManager#createCaptureRequest}
+ * method, which initializes the request fields to one of the templates defined in
+ * {@link CameraDevice}.
*
* @see CameraDevice#createCaptureRequest
* @see CameraDevice#TEMPLATE_PREVIEW
@@ -802,6 +805,7 @@
* @see CameraDevice#TEMPLATE_STILL_CAPTURE
* @see CameraDevice#TEMPLATE_VIDEO_SNAPSHOT
* @see CameraDevice#TEMPLATE_MANUAL
+ * @see CameraManager#createCaptureRequest
*/
public final static class Builder {
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 994037b..3851e36 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -779,7 +779,7 @@
public boolean isSessionConfigurationSupported(
@NonNull SessionConfiguration sessionConfig) throws CameraAccessException,
UnsupportedOperationException, IllegalArgumentException {
- synchronized(mInterfaceLock) {
+ synchronized (mInterfaceLock) {
checkIfCameraClosedOrInError();
return mRemoteDevice.isSessionConfigurationSupported(sessionConfig);
@@ -795,14 +795,25 @@
}
}
- private void overrideEnableZsl(CameraMetadataNative request, boolean newValue) {
+ /**
+ * Disable CONTROL_ENABLE_ZSL based on targetSdkVersion and capture template.
+ */
+ public static void disableZslIfNeeded(CameraMetadataNative request,
+ int targetSdkVersion, int templateType) {
+ // If targetSdkVersion is at least O, no need to set ENABLE_ZSL to false
+ // for STILL_CAPTURE template.
+ if (targetSdkVersion >= Build.VERSION_CODES.O
+ && templateType == TEMPLATE_STILL_CAPTURE) {
+ return;
+ }
+
Boolean enableZsl = request.get(CaptureRequest.CONTROL_ENABLE_ZSL);
if (enableZsl == null) {
// If enableZsl is not available, don't override.
return;
}
- request.set(CaptureRequest.CONTROL_ENABLE_ZSL, newValue);
+ request.set(CaptureRequest.CONTROL_ENABLE_ZSL, false);
}
@Override
@@ -822,12 +833,7 @@
templatedRequest = mRemoteDevice.createDefaultRequest(templateType);
- // If app target SDK is older than O, or it's not a still capture template, enableZsl
- // must be false in the default request.
- if (mAppTargetSdkVersion < Build.VERSION_CODES.O ||
- templateType != TEMPLATE_STILL_CAPTURE) {
- overrideEnableZsl(templatedRequest, false);
- }
+ disableZslIfNeeded(templatedRequest, mAppTargetSdkVersion, templateType);
CaptureRequest.Builder builder = new CaptureRequest.Builder(
templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE,
@@ -847,12 +853,7 @@
templatedRequest = mRemoteDevice.createDefaultRequest(templateType);
- // If app target SDK is older than O, or it's not a still capture template, enableZsl
- // must be false in the default request.
- if (mAppTargetSdkVersion < Build.VERSION_CODES.O ||
- templateType != TEMPLATE_STILL_CAPTURE) {
- overrideEnableZsl(templatedRequest, false);
- }
+ disableZslIfNeeded(templatedRequest, mAppTargetSdkVersion, templateType);
CaptureRequest.Builder builder = new CaptureRequest.Builder(
templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE,
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 0a4a1f0..9fbe348 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -260,7 +260,7 @@
* smaller sizes, then the resulting
* {@link android.hardware.camera2.params.SessionConfiguration session configuration} can
* be tested either by calling {@link CameraDevice#createCaptureSession} or
- * {@link CameraDevice#isSessionConfigurationSupported}.
+ * {@link CameraManager#isSessionConfigurationWithParametersSupported}.
*
* @return non-modifiable ascending list of available sizes.
*/
diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java
index 8f611a8..991f545 100644
--- a/core/java/android/hardware/camera2/params/SessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java
@@ -29,13 +29,15 @@
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.params.InputConfiguration;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.utils.HashCodeHelpers;
import android.media.ImageReader;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Log;
+
+import com.android.internal.camera.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -124,7 +126,7 @@
/**
* Create a SessionConfiguration from Parcel.
- * No support for parcelable 'mStateCallback', 'mExecutor' and 'mSessionParameters' yet.
+ * No support for parcelable 'mStateCallback' and 'mExecutor' yet.
*/
private SessionConfiguration(@NonNull Parcel source) {
int sessionType = source.readInt();
@@ -134,6 +136,15 @@
boolean isInputMultiResolution = source.readBoolean();
ArrayList<OutputConfiguration> outConfigs = new ArrayList<OutputConfiguration>();
source.readTypedList(outConfigs, OutputConfiguration.CREATOR);
+ // Ignore the values for hasSessionParameters and settings because we cannot reconstruct
+ // the CaptureRequest object.
+ if (Flags.featureCombinationQuery()) {
+ boolean hasSessionParameters = source.readBoolean();
+ if (hasSessionParameters) {
+ CameraMetadataNative settings = new CameraMetadataNative();
+ settings.readFromParcel(source);
+ }
+ }
if ((inputWidth > 0) && (inputHeight > 0) && (inputFormat != -1)) {
mInputConfig = new InputConfiguration(inputWidth, inputHeight,
@@ -174,6 +185,15 @@
dest.writeBoolean(/*isMultiResolution*/ false);
}
dest.writeTypedList(mOutputConfigurations);
+ if (Flags.featureCombinationQuery()) {
+ if (mSessionParameters != null) {
+ dest.writeBoolean(/*hasSessionParameters*/true);
+ CameraMetadataNative metadata = mSessionParameters.getNativeCopy();
+ metadata.writeToParcel(dest, /*flags*/0);
+ } else {
+ dest.writeBoolean(/*hasSessionParameters*/false);
+ }
+ }
}
@Override