Camera: Enable 10-bit output camera API

Allow camera clients to query and select a specific 10-bit
dynamic range profile when initializing camera capture
sessions.

Bug: 195946346
Test: Camera CTS
Change-Id: If46c16a7ea95b772dcaa3ae36807ed73d197749f
diff --git a/core/api/current.txt b/core/api/current.txt
index e702dad..9c72c9d 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -18452,12 +18452,14 @@
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REPROCESS_MAX_CAPTURE_STALL;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> REQUEST_AVAILABLE_CAPABILITIES;
+    field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.DynamicRangeProfiles> REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_INPUT_STREAMS;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC_STALLING;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_RAW;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_PARTIAL_RESULT_COUNT;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Byte> REQUEST_PIPELINE_MAX_DEPTH;
+    field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_ROTATE_AND_CROP_MODES;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SCALER_CROPPING_TYPE;
@@ -18465,6 +18467,7 @@
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_STREAM_COMBINATIONS;
+    field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_TEN_BIT_OUTPUT_STREAM_COMBINATIONS;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MultiResolutionStreamConfigurationMap> SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.StreamConfigurationMap> SCALER_STREAM_CONFIGURATION_MAP;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.StreamConfigurationMap> SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION;
@@ -18781,6 +18784,7 @@
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6; // 0x6
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO = 9; // 0x9
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8; // 0x8
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT = 18; // 0x12
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA = 11; // 0xb
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2; // 0x2
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 1; // 0x1
@@ -19134,6 +19138,25 @@
     field public static final long NORMAL = 0L; // 0x0L
   }
 
+  public final class DynamicRangeProfiles {
+    ctor public DynamicRangeProfiles(@NonNull int[]);
+    method @NonNull public java.util.Set<java.lang.Integer> getProfileCaptureRequestConstraints(int);
+    method @NonNull public java.util.Set<java.lang.Integer> getSupportedProfiles();
+    field public static final int DOLBY_VISION_10B_HDR_OEM = 64; // 0x40
+    field public static final int DOLBY_VISION_10B_HDR_OEM_PO = 128; // 0x80
+    field public static final int DOLBY_VISION_10B_HDR_REF = 16; // 0x10
+    field public static final int DOLBY_VISION_10B_HDR_REF_PO = 32; // 0x20
+    field public static final int DOLBY_VISION_8B_HDR_OEM = 1024; // 0x400
+    field public static final int DOLBY_VISION_8B_HDR_OEM_PO = 2048; // 0x800
+    field public static final int DOLBY_VISION_8B_HDR_REF = 256; // 0x100
+    field public static final int DOLBY_VISION_8B_HDR_REF_PO = 512; // 0x200
+    field public static final int HDR10 = 4; // 0x4
+    field public static final int HDR10_PLUS = 8; // 0x8
+    field public static final int HLG10 = 2; // 0x2
+    field public static final int PUBLIC_MAX = 4096; // 0x1000
+    field public static final int STANDARD = 1; // 0x1
+  }
+
   public final class ExtensionSessionConfiguration {
     ctor public ExtensionSessionConfiguration(int, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraExtensionSession.StateCallback);
     method @NonNull public java.util.concurrent.Executor getExecutor();
@@ -19180,8 +19203,10 @@
   }
 
   public static final class MandatoryStreamCombination.MandatoryStreamInformation {
+    method public int get10BitFormat();
     method @NonNull public java.util.List<android.util.Size> getAvailableSizes();
     method public int getFormat();
+    method public boolean is10BitCapable();
     method public boolean isInput();
     method public boolean isMaximumSize();
     method public boolean isUltraHighResolution();
@@ -19235,12 +19260,14 @@
     method @NonNull public static java.util.Collection<android.hardware.camera2.params.OutputConfiguration> createInstancesForMultiResolutionOutput(@NonNull android.hardware.camera2.MultiResolutionImageReader);
     method public int describeContents();
     method public void enableSurfaceSharing();
+    method public int getDynamicRangeProfile();
     method public int getMaxSharedSurfaceCount();
     method @Nullable public android.view.Surface getSurface();
     method public int getSurfaceGroupId();
     method @NonNull public java.util.List<android.view.Surface> getSurfaces();
     method public void removeSensorPixelModeUsed(int);
     method public void removeSurface(@NonNull android.view.Surface);
+    method public void setDynamicRangeProfile(int);
     method public void setPhysicalCameraId(@Nullable String);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
@@ -19266,6 +19293,7 @@
     method @Nullable public java.util.Set<java.lang.Integer> getValidOutputFormatsForInput(int);
     method public boolean isOutputSupportedFor(int);
     method public boolean isOutputSupportedFor(@NonNull android.view.Surface);
+    field public static final int USECASE_10BIT_OUTPUT = 8; // 0x8
     field public static final int USECASE_LOW_LATENCY_SNAPSHOT = 6; // 0x6
     field public static final int USECASE_PREVIEW = 0; // 0x0
     field public static final int USECASE_RAW = 5; // 0x5
diff --git a/core/java/android/hardware/CameraStreamStats.java b/core/java/android/hardware/CameraStreamStats.java
index 41d1e25..ed22de8 100644
--- a/core/java/android/hardware/CameraStreamStats.java
+++ b/core/java/android/hardware/CameraStreamStats.java
@@ -15,6 +15,7 @@
  */
 package android.hardware;
 
+import android.hardware.camera2.params.DynamicRangeProfiles;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
@@ -45,6 +46,7 @@
     private int mHistogramType;
     private float[] mHistogramBins;
     private long[] mHistogramCounts;
+    private int mDynamicRangeProfile;
 
     private static final String TAG = "CameraStreamStats";
 
@@ -60,11 +62,12 @@
         mMaxHalBuffers = 0;
         mMaxAppBuffers = 0;
         mHistogramType = HISTOGRAM_TYPE_UNKNOWN;
+        mDynamicRangeProfile = DynamicRangeProfiles.STANDARD;
     }
 
     public CameraStreamStats(int width, int height, int format,
             int dataSpace, long usage, long requestCount, long errorCount,
-            int startLatencyMs, int maxHalBuffers, int maxAppBuffers) {
+            int startLatencyMs, int maxHalBuffers, int maxAppBuffers, int dynamicRangeProfile) {
         mWidth = width;
         mHeight = height;
         mFormat = format;
@@ -76,6 +79,7 @@
         mMaxHalBuffers = maxHalBuffers;
         mMaxAppBuffers = maxAppBuffers;
         mHistogramType = HISTOGRAM_TYPE_UNKNOWN;
+        mDynamicRangeProfile = dynamicRangeProfile;
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<CameraStreamStats> CREATOR =
@@ -121,6 +125,7 @@
         dest.writeInt(mHistogramType);
         dest.writeFloatArray(mHistogramBins);
         dest.writeLongArray(mHistogramCounts);
+        dest.writeInt(mDynamicRangeProfile);
     }
 
     public void readFromParcel(Parcel in) {
@@ -137,6 +142,7 @@
         mHistogramType = in.readInt();
         mHistogramBins = in.createFloatArray();
         mHistogramCounts = in.createLongArray();
+        mDynamicRangeProfile = in.readInt();
     }
 
     public int getWidth() {
@@ -190,4 +196,8 @@
     public long[] getHistogramCounts() {
         return mHistogramCounts;
     }
+
+    public int getDynamicRangeProfile() {
+        return mDynamicRangeProfile;
+    }
 }
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index bd47463..691690c 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -321,6 +321,9 @@
      * can submit reprocess capture requests. Submitting a reprocess request to a regular capture
      * session will result in an {@link IllegalArgumentException}.</p>
      *
+     * <p>Submitting a request that targets Surfaces with an unsupported dynamic range combination
+     * will result in an {@link IllegalArgumentException}.</p>
+     *
      * @param request the settings for this capture
      * @param listener The callback object to notify once this request has been
      * processed. If null, no metadata will be produced for this capture,
@@ -347,13 +350,15 @@
      *                                  a different session; or the capture targets a Surface in
      *                                  the middle of being {@link #prepare prepared}; or the
      *                                  handler is null, the listener is not null, and the calling
-     *                                  thread has no looper.
+     *                                  thread has no looper; or the request targets Surfaces with
+     *                                  an unsupported dynamic range combination
      *
      * @see #captureBurst
      * @see #setRepeatingRequest
      * @see #setRepeatingBurst
      * @see #abortCaptures
      * @see CameraDevice#createReprocessableCaptureSession
+     * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints
      */
     public abstract int capture(@NonNull CaptureRequest request,
             @Nullable CaptureCallback listener, @Nullable Handler handler)
@@ -389,13 +394,16 @@
      *                                  request was created with a {@link TotalCaptureResult} from
      *                                  a different session; or the capture targets a Surface in
      *                                  the middle of being {@link #prepare prepared}; or the
-     *                                  executor is null, or the listener is not null.
+     *                                  executor is null, or the listener is not null;
+     *                                  or the request targets Surfaces with an unsupported dynamic
+     *                                  range combination;
      *
      * @see #captureBurst
      * @see #setRepeatingRequest
      * @see #setRepeatingBurst
      * @see #abortCaptures
      * @see CameraDevice#createReprocessableCaptureSession
+     * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints
      */
     public int captureSingleRequest(@NonNull CaptureRequest request,
             @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener)
@@ -427,6 +435,9 @@
      * can submit reprocess capture requests. Submitting a reprocess request to a regular
      * capture session will result in an {@link IllegalArgumentException}.</p>
      *
+     * <p>Submitting a request that targets Surfaces with an unsupported dynamic range combination
+     * will result in an {@link IllegalArgumentException}.</p>
+     *
      * @param requests the list of settings for this burst capture
      * @param listener The callback object to notify each time one of the
      * requests in the burst has been processed. If null, no metadata will be
@@ -454,12 +465,15 @@
      *                                  {@link TotalCaptureResult} from a different session; or one
      *                                  of the captures targets a Surface in the middle of being
      *                                  {@link #prepare prepared}; or if the handler is null, the
-     *                                  listener is not null, and the calling thread has no looper.
+     *                                  listener is not null, and the calling thread has no looper;
+     *                                  or the request targets Surfaces with an unsupported dynamic
+     *                                  range combination.
      *
      * @see #capture
      * @see #setRepeatingRequest
      * @see #setRepeatingBurst
      * @see #abortCaptures
+     * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints
      */
     public abstract int captureBurst(@NonNull List<CaptureRequest> requests,
             @Nullable CaptureCallback listener, @Nullable Handler handler)
@@ -499,12 +513,15 @@
      *                                  {@link TotalCaptureResult} from a different session; or one
      *                                  of the captures targets a Surface in the middle of being
      *                                  {@link #prepare prepared}; or if the executor is null; or if
-     *                                  the listener is null.
+     *                                  the listener is null;
+     *                                  or the request targets Surfaces with an unsupported dynamic
+     *                                  range combination.
      *
      * @see #capture
      * @see #setRepeatingRequest
      * @see #setRepeatingBurst
      * @see #abortCaptures
+     * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints
      */
     public int captureBurstRequests(@NonNull List<CaptureRequest> requests,
             @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener)
@@ -545,6 +562,9 @@
      * single reprocess input image. The request must be capturing images from the camera. If a
      * reprocess capture request is submitted, this method will throw IllegalArgumentException.</p>
      *
+     * <p>Submitting a request that targets Surfaces with an unsupported dynamic range combination
+     * will result in an {@link IllegalArgumentException}.</p>
+     *
      * @param request the request to repeat indefinitely
      * @param listener The callback object to notify every time the
      * request finishes processing. If null, no metadata will be
@@ -567,13 +587,16 @@
      *                                  is a reprocess capture request; or the capture targets a
      *                                  Surface in the middle of being {@link #prepare prepared}; or
      *                                  the handler is null, the listener is not null, and the
-     *                                  calling thread has no looper; or no requests were passed in.
+     *                                  calling thread has no looper; or no requests were passed in;
+     *                                  or the request targets Surfaces with an unsupported dynamic
+     *                                  range combination.
      *
      * @see #capture
      * @see #captureBurst
      * @see #setRepeatingBurst
      * @see #stopRepeating
      * @see #abortCaptures
+     * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints
      */
     public abstract int setRepeatingRequest(@NonNull CaptureRequest request,
             @Nullable CaptureCallback listener, @Nullable Handler handler)
@@ -604,13 +627,16 @@
      *                                  that are not currently configured as outputs; or the request
      *                                  is a reprocess capture request; or the capture targets a
      *                                  Surface in the middle of being {@link #prepare prepared}; or
-     *                                  the executor is null; or the listener is null.
+     *                                  the executor is null; or the listener is null;
+     *                                  or the request targets Surfaces with an unsupported dynamic
+     *                                  range combination.
      *
      * @see #capture
      * @see #captureBurst
      * @see #setRepeatingBurst
      * @see #stopRepeating
      * @see #abortCaptures
+     * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints
      */
     public int setSingleRepeatingRequest(@NonNull CaptureRequest request,
             @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener)
@@ -655,6 +681,9 @@
      * single reprocess input image. The request must be capturing images from the camera. If a
      * reprocess capture request is submitted, this method will throw IllegalArgumentException.</p>
      *
+     * <p>Submitting a request that targets Surfaces with an unsupported dynamic range combination
+     * will result in an {@link IllegalArgumentException}.</p>
+     *
      * @param requests the list of requests to cycle through indefinitely
      * @param listener The callback object to notify each time one of the
      * requests in the repeating bursts has finished processing. If null, no
@@ -678,13 +707,16 @@
      *                                  targets a Surface in the middle of being
      *                                  {@link #prepare prepared}; or the handler is null, the
      *                                  listener is not null, and the calling thread has no looper;
-     *                                  or no requests were passed in.
+     *                                  or no requests were passed in;
+     *                                  or the request targets Surfaces with an unsupported dynamic
+     *                                  range combination.
      *
      * @see #capture
      * @see #captureBurst
      * @see #setRepeatingRequest
      * @see #stopRepeating
      * @see #abortCaptures
+     * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints
      */
     public abstract int setRepeatingBurst(@NonNull List<CaptureRequest> requests,
             @Nullable CaptureCallback listener, @Nullable Handler handler)
@@ -717,13 +749,16 @@
      *                                  is a reprocess capture request; or one of the captures
      *                                  targets a Surface in the middle of being
      *                                  {@link #prepare prepared}; or the executor is null; or the
-     *                                  listener is null.
+     *                                  listener is null;
+     *                                  or the request targets Surfaces with an unsupported dynamic
+     *                                  range combination.
      *
      * @see #capture
      * @see #captureBurst
      * @see #setRepeatingRequest
      * @see #stopRepeating
      * @see #abortCaptures
+     * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints
      */
     public int setRepeatingBurstRequests(@NonNull List<CaptureRequest> requests,
             @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener)
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 48a9121..d2dc314 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -461,7 +461,7 @@
     public @Nullable RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap(
             @RecommendedStreamConfigurationMap.RecommendedUsecase int usecase) {
         if (((usecase >= RecommendedStreamConfigurationMap.USECASE_PREVIEW) &&
-                (usecase <= RecommendedStreamConfigurationMap.USECASE_LOW_LATENCY_SNAPSHOT)) ||
+                (usecase <= RecommendedStreamConfigurationMap.USECASE_10BIT_OUTPUT)) ||
                 ((usecase >= RecommendedStreamConfigurationMap.USECASE_VENDOR_START) &&
                 (usecase < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT))) {
             if (mRecommendedConfigurations == null) {
@@ -2213,6 +2213,7 @@
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING OFFLINE_PROCESSING}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR ULTRA_HIGH_RESOLUTION_SENSOR}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING REMOSAIC_REPROCESSING}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT DYNAMIC_RANGE_TEN_BIT}</li>
      * </ul>
      *
      * <p>This key is available on all devices.</p>
@@ -2236,6 +2237,7 @@
      * @see #REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING
      * @see #REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR
      * @see #REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT
      */
     @PublicKey
     @NonNull
@@ -2379,6 +2381,86 @@
             new Key<int[]>("android.request.characteristicKeysNeedingPermission", int[].class);
 
     /**
+     * <p>Devices supporting the 10-bit output capability
+     * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT }
+     * must list their supported dynamic range profiles along with capture request
+     * constraints for specific profile combinations.</p>
+     * <p>Camera clients can retrieve the list of supported 10-bit dynamic range profiles by calling
+     * {@link android.hardware.camera2.params.DynamicRangeProfiles#getSupportedProfiles }.
+     * Any of them can be configured by setting OutputConfiguration dynamic range profile in
+     * {@link android.hardware.camera2.params.OutputConfiguration#setDynamicRangeProfile }.
+     * Clients can also check if there are any constraints that limit the combination
+     * of supported profiles that can be referenced within a single capture request by calling
+     * {@link android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints }.</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     */
+    @PublicKey
+    @NonNull
+    @SyntheticKey
+    public static final Key<android.hardware.camera2.params.DynamicRangeProfiles> REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES =
+            new Key<android.hardware.camera2.params.DynamicRangeProfiles>("android.request.availableDynamicRangeProfiles", android.hardware.camera2.params.DynamicRangeProfiles.class);
+
+    /**
+     * <p>A map of all available 10-bit dynamic range profiles along with their
+     * capture request constraints.</p>
+     * <p>Devices supporting the 10-bit output capability
+     * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT }
+     * must list their supported dynamic range profiles. In case the camera is not able to
+     * support every possible profile combination within a single capture request, then the
+     * constraints must be listed here as well.</p>
+     * <p><b>Possible values:</b></p>
+     * <ul>
+     *   <li>{@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD STANDARD}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10 HLG10}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10 HDR10}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS HDR10_PLUS}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF DOLBY_VISION_10B_HDR_REF}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO DOLBY_VISION_10B_HDR_REF_PO}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM DOLBY_VISION_10B_HDR_OEM}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO DOLBY_VISION_10B_HDR_OEM_PO}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF DOLBY_VISION_8B_HDR_REF}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO DOLBY_VISION_8B_HDR_REF_PO}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM DOLBY_VISION_8B_HDR_OEM}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO DOLBY_VISION_8B_HDR_OEM_PO}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX MAX}</li>
+     * </ul>
+     *
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD
+     * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10
+     * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10
+     * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS
+     * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF
+     * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO
+     * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM
+     * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO
+     * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF
+     * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO
+     * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM
+     * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO
+     * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX
+     * @hide
+     */
+    public static final Key<int[]> REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP =
+            new Key<int[]>("android.request.availableDynamicRangeProfilesMap", int[].class);
+
+    /**
+     * <p>Recommended 10-bit dynamic range profile.</p>
+     * <p>Devices supporting the 10-bit output capability
+     * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT }
+     * must list a 10-bit supported dynamic range profile that is expected to perform
+     * optimally in terms of image quality, power and performance.
+     * The value advertised can be used as a hint by camera clients when configuring the dynamic
+     * range profile when calling
+     * {@link android.hardware.camera2.params.OutputConfiguration#setDynamicRangeProfile }.</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     */
+    @PublicKey
+    @NonNull
+    public static final Key<Integer> REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE =
+            new Key<Integer>("android.request.recommendedTenBitDynamicRangeProfile", int.class);
+
+    /**
      * <p>The list of image formats that are supported by this
      * camera device for output streams.</p>
      * <p>All camera devices will support JPEG and YUV_420_888 formats.</p>
@@ -3340,6 +3422,32 @@
             new Key<android.hardware.camera2.params.MandatoryStreamCombination[]>("android.scaler.mandatoryMaximumResolutionStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class);
 
     /**
+     * <p>An array of mandatory stream combinations which are applicable when device support the
+     * 10-bit output capability
+     * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT }
+     * This is an app-readable conversion of the maximum resolution mandatory stream combination
+     * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
+     * <p>The array of
+     * {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
+     * generated according to the documented
+     * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for each
+     * device which has the
+     * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT }
+     * capability.
+     * Clients can use the array as a quick reference to find an appropriate camera stream
+     * combination.
+     * The mandatory stream combination array will be {@code null} in case the device is not an
+     * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT }
+     * device.</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     */
+    @PublicKey
+    @NonNull
+    @SyntheticKey
+    public static final Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_TEN_BIT_OUTPUT_STREAM_COMBINATIONS =
+            new Key<android.hardware.camera2.params.MandatoryStreamCombination[]>("android.scaler.mandatoryTenBitOutputStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class);
+
+    /**
      * <p>Whether the camera device supports multi-resolution input or output streams</p>
      * <p>A logical multi-camera or an ultra high resolution camera may support multi-resolution
      * input or output streams. With multi-resolution output streams, the camera device is able
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 3c1ec3e..47eb79d 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -402,7 +402,9 @@
      *                                  registered surfaces do not meet the device-specific
      *                                  extension requirements such as dimensions and/or
      *                                  (output format)/(surface type), or if the extension is not
-     *                                  supported.
+     *                                  supported, or if any of the output configurations select
+     *                                  a dynamic range different from
+     *                                  {@link android.hardware.camera2.params.DynamicRangeProfiles#STANDARD}
      * @see CameraExtensionCharacteristics#getSupportedExtensions
      * @see CameraExtensionCharacteristics#getExtensionSupportedSizes
      */
@@ -822,7 +824,36 @@
      * be chosen from. {@code DEFAULT} refers to the default sensor pixel mode {@link
      * StreamConfigurationMap} and {@code MAX_RES} refers to the maximum resolution {@link
      * StreamConfigurationMap}. The same capture request must not mix targets from
-     * {@link StreamConfigurationMap}s corresponding to different sensor pixel modes.
+     * {@link StreamConfigurationMap}s corresponding to different sensor pixel modes. </p>
+     *
+     * <p> 10-bit output capable
+     * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT}
+     * devices support at least the following stream combinations: </p>
+     * <table>
+     * <tr><th colspan="7">10-bit output additional guaranteed configurations</th></tr>
+     * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
+     * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> }</td> <td colspan="4" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr>
+     * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> }</td> <td colspan="4" id="rb"></td> <td>In-application video/image processing.</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Standard still imaging.</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution in-app processing with preview.</td> </tr>
+     * <tr> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution two-input in-app processing.</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code RECORD }</td> <td colspan="2" id="rb"></td> <td>High-resolution video recording with preview.</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code RECORD }</td> <td>{@code YUV}</td><td id="rb">{@code RECORD }</td> <td>High-resolution recording with in-app snapshot.</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV }</td><td id="rb">{@code RECORD }</td> <td>{@code JPEG}</td><td id="rb">{@code RECORD }</td> <td>High-resolution recording with video snapshot.</td> </tr>
+     * </table><br>
+     * <p>Here PRIV can be either 8 or 10-bit {@link android.graphics.ImageFormat#PRIVATE} pixel
+     * format. YUV can be either {@link android.graphics.ImageFormat#YUV_420_888} or
+     * {@link android.graphics.ImageFormat#YCBCR_P010}.
+     * For the maximum size column, PREVIEW refers to the best size match to the device's screen
+     * resolution, or to 1080p (1920x1080), whichever is smaller. RECORD refers to the camera
+     * device's maximum supported recording resolution, as determined by
+     * {@link android.media.CamcorderProfile}. MAXIMUM refers to the camera device's maximum output
+     * resolution for that format or target from {@link StreamConfigurationMap#getOutputSizes(int)}.
+     * Do note that invalid combinations such as having a camera surface configured to use pixel
+     * format {@link android.graphics.ImageFormat#YUV_420_888} with a 10-bit profile
+     * will cause a capture session initialization failure.
+     * </p>
      *
      * <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
@@ -907,6 +938,13 @@
      * guaranteed output targets that can be submitted in a regular or reprocess
      * {@link CaptureRequest} simultaneously.</p>
      *
+     * <p>Reprocessing with 10-bit output targets on 10-bit capable
+     * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT} devices is
+     * not supported. Trying to initialize a repreocessable capture session with one ore more
+     * output configurations set {@link OutputConfiguration#setDynamicRangeProfile(int)} to use
+     * a 10-bit dynamic range profile {@link android.hardware.camera2.params.DynamicRangeProfiles}
+     * will trigger {@link IllegalArgumentException}.</p>
+     *
      * <style scoped>
      *  #rb { border-right-width: thick; }
      * </style>
@@ -1083,13 +1121,17 @@
      *
      * @throws IllegalArgumentException In case the session configuration is invalid; or the output
      *                                  configurations are empty; or the session configuration
-     *                                  executor is invalid.
+     *                                  executor is invalid;
+     *                                  or the output dynamic range combination is
+     *                                  invalid/unsupported.
      * @throws CameraAccessException In case the camera device is no longer connected or has
      *                               encountered a fatal error.
      * @see #createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)
      * @see #createCaptureSessionByOutputConfigurations
      * @see #createReprocessableCaptureSession
      * @see #createConstrainedHighSpeedCaptureSession
+     * @see OutputConfiguration#setDynamicRangeProfile(int)
+     * @see android.hardware.camera2.params.DynamicRangeProfiles
      */
     public void createCaptureSession(
             SessionConfiguration config) throws CameraAccessException {
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 639abe9..803684d 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1190,6 +1190,135 @@
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING = 17;
 
+    /**
+     * <p>The device supports one or more 10-bit camera outputs according to the dynamic range
+     * profiles specified in
+     * {@link android.hardware.camera2.params.DynamicRangeProfiles#getSupportedProfiles }.
+     * They can be configured as part of the capture session initialization via
+     * {@link android.hardware.camera2.params.OutputConfiguration#setDynamicRangeProfile }.
+     * Cameras that enable this capability must also support the following:
+     * * Profile {@link android.hardware.camera2.params.DynamicRangeProfiles#HLG10 }
+     * * All mandatory stream combinations for this specific capability as per
+     *   documentation {@link android.hardware.camera2.CameraDevice#createCaptureSession }
+     * * In case the device is not able to capture some combination of supported
+     *   standard 8-bit and/or 10-bit dynamic range profiles within the same capture request,
+     *   then those constraints must be listed in
+     *   {@link android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints }
+     * * Recommended dynamic range profile listed in
+     *   {@link android.hardware.camera2.CameraCharacteristics#REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE }.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT = 18;
+
+    //
+    // Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+    //
+
+    /**
+     * <p>8-bit SDR profile which is the default for all non 10-bit output capable devices.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+     * @hide
+     */
+    public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD = 0x1;
+
+    /**
+     * <p>10-bit pixel samples encoded using the Hybrid log-gamma transfer function.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+     * @hide
+     */
+    public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10 = 0x2;
+
+    /**
+     * <p>10-bit pixel samples encoded using the SMPTE ST 2084 transfer function.
+     * This profile utilizes internal static metadata to increase the quality
+     * of the capture.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+     * @hide
+     */
+    public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10 = 0x4;
+
+    /**
+     * <p>10-bit pixel samples encoded using the SMPTE ST 2084 transfer function.
+     * In contrast to HDR10, this profile uses internal per-frame metadata
+     * to further enhance the quality of the capture.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+     * @hide
+     */
+    public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS = 0x8;
+
+    /**
+     * <p>This is a camera mode for Dolby Vision capture optimized for a more scene
+     * accurate capture. This would typically differ from what a specific device
+     * might want to tune for a consumer optimized Dolby Vision general capture.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+     * @hide
+     */
+    public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF = 0x10;
+
+    /**
+     * <p>This is the power optimized mode for 10-bit Dolby Vision HDR Reference Mode.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+     * @hide
+     */
+    public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO = 0x20;
+
+    /**
+     * <p>This is the camera mode for the default Dolby Vision capture mode for the
+     * specific device. This would be tuned by each specific device for consumer
+     * pleasing results that resonate with their particular audience. We expect
+     * that each specific device would have a different look for their default
+     * Dolby Vision capture.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+     * @hide
+     */
+    public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM = 0x40;
+
+    /**
+     * <p>This is the power optimized mode for 10-bit Dolby Vision HDR device specific
+     * capture Mode.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+     * @hide
+     */
+    public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO = 0x80;
+
+    /**
+     * <p>This is the 8-bit version of the Dolby Vision reference capture mode optimized
+     * for scene accuracy.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+     * @hide
+     */
+    public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF = 0x100;
+
+    /**
+     * <p>This is the power optimized mode for 8-bit Dolby Vision HDR Reference Mode.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+     * @hide
+     */
+    public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO = 0x200;
+
+    /**
+     * <p>This is the 8-bit version of device specific tuned and optimized Dolby Vision
+     * capture mode.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+     * @hide
+     */
+    public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM = 0x400;
+
+    /**
+     * <p>This is the power optimized mode for 8-bit Dolby Vision HDR device specific
+     * capture Mode.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+     * @hide
+     */
+    public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO = 0x800;
+
+    /**
+     *
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+     * @hide
+     */
+    public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX = 0x1000;
+
     //
     // Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE
     //
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index b8443fb..9d2c901 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -35,7 +35,6 @@
 import android.hardware.camera2.TotalCaptureResult;
 import android.hardware.camera2.extension.CameraOutputConfig;
 import android.hardware.camera2.extension.CameraSessionConfig;
-import android.hardware.camera2.extension.CaptureStageImpl;
 import android.hardware.camera2.extension.IAdvancedExtenderImpl;
 import android.hardware.camera2.extension.ICaptureCallback;
 import android.hardware.camera2.extension.IImageProcessorImpl;
@@ -49,6 +48,7 @@
 import android.hardware.camera2.extension.ParcelImage;
 import android.hardware.camera2.extension.ParcelTotalCaptureResult;
 import android.hardware.camera2.extension.Request;
+import android.hardware.camera2.params.DynamicRangeProfiles;
 import android.hardware.camera2.params.ExtensionSessionConfiguration;
 import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.params.SessionConfiguration;
@@ -130,6 +130,13 @@
                     config.getOutputConfigurations().size() + " expected <= 2");
         }
 
+        for (OutputConfiguration c : config.getOutputConfigurations()) {
+            if (c.getDynamicRangeProfile() != DynamicRangeProfiles.STANDARD) {
+                throw new IllegalArgumentException("Unsupported dynamic range profile: " +
+                        c.getDynamicRangeProfile());
+            }
+        }
+
         int suitableSurfaceCount = 0;
         List<Size> supportedPreviewSizes = extensionChars.getExtensionSupportedSizes(
                 config.getExtension(), SurfaceTexture.class);
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 71047af..c8ecfd0 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -39,6 +39,7 @@
 import android.hardware.camera2.extension.IRequestUpdateProcessorImpl;
 import android.hardware.camera2.extension.ParcelImage;
 import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.DynamicRangeProfiles;
 import android.hardware.camera2.params.ExtensionSessionConfiguration;
 import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.params.SessionConfiguration;
@@ -145,6 +146,13 @@
                     config.getOutputConfigurations().size() + " expected <= 2");
         }
 
+        for (OutputConfiguration c : config.getOutputConfigurations()) {
+            if (c.getDynamicRangeProfile() != DynamicRangeProfiles.STANDARD) {
+                throw new IllegalArgumentException("Unsupported dynamic range profile: " +
+                        c.getDynamicRangeProfile());
+            }
+        }
+
         Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
                 CameraExtensionCharacteristics.initializeExtension(config.getExtension());
 
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index e393a66..0f8bdf6 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -51,6 +51,7 @@
 import android.hardware.camera2.marshal.impl.MarshalQueryableString;
 import android.hardware.camera2.params.Capability;
 import android.hardware.camera2.params.DeviceStateSensorOrientationMap;
+import android.hardware.camera2.params.DynamicRangeProfiles;
 import android.hardware.camera2.params.Face;
 import android.hardware.camera2.params.HighSpeedVideoConfiguration;
 import android.hardware.camera2.params.LensShadingMap;
@@ -331,6 +332,7 @@
     private static final int MANDATORY_STREAM_CONFIGURATIONS_DEFAULT = 0;
     private static final int MANDATORY_STREAM_CONFIGURATIONS_MAX_RESOLUTION = 1;
     private static final int MANDATORY_STREAM_CONFIGURATIONS_CONCURRENT = 2;
+    private static final int MANDATORY_STREAM_CONFIGURATIONS_10BIT = 3;
 
     private static String translateLocationProviderToProcess(final String provider) {
         if (provider == null) {
@@ -678,6 +680,16 @@
                 });
 
         sGetCommandMap.put(
+                CameraCharacteristics.SCALER_MANDATORY_TEN_BIT_OUTPUT_STREAM_COMBINATIONS.getNativeKey(),
+                new GetCommand() {
+                    @Override
+                    @SuppressWarnings("unchecked")
+                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+                        return (T) metadata.getMandatory10BitStreamCombinations();
+                    }
+                });
+
+        sGetCommandMap.put(
                 CameraCharacteristics.SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS.getNativeKey(),
                         new GetCommand() {
                     @Override
@@ -771,6 +783,15 @@
                     }
                 });
         sGetCommandMap.put(
+                CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES.getNativeKey(),
+                        new GetCommand() {
+                    @Override
+                    @SuppressWarnings("unchecked")
+                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+                        return (T) metadata.getDynamicRangeProfiles();
+                    }
+                });
+        sGetCommandMap.put(
                 CaptureResult.STATISTICS_OIS_SAMPLES.getNativeKey(),
                         new GetCommand() {
                     @Override
@@ -1015,6 +1036,17 @@
         return map;
     }
 
+    private DynamicRangeProfiles getDynamicRangeProfiles() {
+        int[] profileArray = getBase(
+                CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP);
+
+        if (profileArray == null) {
+            return null;
+        }
+
+        return new DynamicRangeProfiles(profileArray);
+    }
+
     private Location getGpsLocation() {
         String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
         double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES);
@@ -1378,6 +1410,9 @@
             case MANDATORY_STREAM_CONFIGURATIONS_MAX_RESOLUTION:
                 combs = build.getAvailableMandatoryMaximumResolutionStreamCombinations();
                 break;
+            case MANDATORY_STREAM_CONFIGURATIONS_10BIT:
+                combs = build.getAvailableMandatory10BitStreamCombinations();
+                break;
             default:
                 combs = build.getAvailableMandatoryStreamCombinations();
         }
@@ -1389,6 +1424,10 @@
         return null;
     }
 
+    private MandatoryStreamCombination[] getMandatory10BitStreamCombinations() {
+        return getMandatoryStreamCombinationsHelper(MANDATORY_STREAM_CONFIGURATIONS_10BIT);
+    }
+
     private MandatoryStreamCombination[] getMandatoryConcurrentStreamCombinations() {
         if (!mHasMandatoryConcurrentStreams) {
             return null;
diff --git a/core/java/android/hardware/camera2/params/DynamicRangeProfiles.java b/core/java/android/hardware/camera2/params/DynamicRangeProfiles.java
new file mode 100644
index 0000000..5c1a4aa
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/DynamicRangeProfiles.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2021 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 android.hardware.camera2.params;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+
+import android.hardware.camera2.CameraMetadata;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Immutable class with information about supported 10-bit dynamic range profiles.
+ *
+ * <p>An instance of this class can be queried by retrieving the value of
+ * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES}.
+ * </p>
+ *
+ * <p>All camera devices supporting the
+ * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT}
+ * capability must advertise the supported 10-bit dynamic range profiles in
+ * {@link #getSupportedProfiles}</p>
+ *
+ * <p>Some devices may not be able to support 8-bit and/or 10-bit output with different dynamic
+ * range profiles within the same capture request. Such device specific constraints can be queried
+ * by calling {@link #getProfileCaptureRequestConstraints(int)}. Do note that unsupported
+ * combinations will result in {@link IllegalArgumentException} when trying to submit a capture
+ * request. Capture requests that only reference outputs configured using the same dynamic range
+ * profile value will never fail due to such constraints.</p>
+ *
+ * @see OutputConfiguration#setDynamicRangeProfile(int)
+ */
+public final class DynamicRangeProfiles {
+    /**
+     * This the default 8-bit standard profile that will be used in case where camera clients do not
+     * explicitly configure a supported dynamic range profile by calling
+     * {@link OutputConfiguration#setDynamicRangeProfile(int)}.
+     */
+    public static final int STANDARD =
+            CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
+
+    /**
+     * 10-bit pixel samples encoded using the Hybrid log-gamma transfer function
+     *
+     * <p>All 10-bit output capable devices are required to support this profile.</p>
+     */
+    public static final int HLG10  =
+            CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10;
+
+    /**
+     * 10-bit pixel samples encoded using the SMPTE ST 2084 transfer function.
+     *
+     * <p>This profile utilizes internal static metadata to increase the quality
+     * of the capture.</p>
+     */
+    public static final int HDR10  =
+            CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10;
+
+    /**
+     * 10-bit pixel samples encoded using the SMPTE ST 2084 transfer function.
+     *
+     * <p>In contrast to HDR10, this profile uses internal per-frame metadata
+     * to further enhance the quality of the capture.</p>
+     */
+    public static final int HDR10_PLUS =
+            CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS;
+
+    /**
+     * <p>This is a camera mode for Dolby Vision capture optimized for a more scene
+     * accurate capture. This would typically differ from what a specific device
+     * might want to tune for a consumer optimized Dolby Vision general capture.</p>
+     */
+    public static final int DOLBY_VISION_10B_HDR_REF =
+            CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF;
+
+    /**
+     * <p>This is the power optimized mode for 10-bit Dolby Vision HDR Reference Mode.</p>
+     */
+    public static final int DOLBY_VISION_10B_HDR_REF_PO =
+            CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO;
+
+    /**
+     * <p>This is the camera mode for the default Dolby Vision capture mode for the
+     * specific device. This would be tuned by each specific device for consumer
+     * pleasing results that resonate with their particular audience. We expect
+     * that each specific device would have a different look for their default
+     * Dolby Vision capture.</p>
+     */
+    public static final int DOLBY_VISION_10B_HDR_OEM =
+            CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM;
+
+    /**
+     * <p>This is the power optimized mode for 10-bit Dolby Vision HDR device specific capture
+     * Mode.</p>
+     */
+    public static final int DOLBY_VISION_10B_HDR_OEM_PO =
+            CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO;
+
+    /**
+     * <p>This is the 8-bit version of the Dolby Vision reference capture mode optimized
+     * for scene accuracy.</p>
+     */
+    public static final int DOLBY_VISION_8B_HDR_REF =
+            CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF;
+
+    /**
+     * <p>This is the power optimized mode for 8-bit Dolby Vision HDR Reference Mode.</p>
+     */
+    public static final int DOLBY_VISION_8B_HDR_REF_PO =
+            CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO;
+
+    /**
+     * <p>This is the 8-bit version of device specific tuned and optimized Dolby Vision
+     * capture mode.</p>
+     */
+    public static final int DOLBY_VISION_8B_HDR_OEM =
+            CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM;
+
+    /**
+     * <p>This is the power optimized mode for 8-bit Dolby Vision HDR device specific
+     * capture Mode.</p>
+     */
+    public static final int DOLBY_VISION_8B_HDR_OEM_PO =
+            CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO;
+
+    /*
+     * @hide
+     */
+    public static final int PUBLIC_MAX =
+            CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX;
+
+     /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"PROFILE_"}, value =
+            {STANDARD,
+             HLG10,
+             HDR10,
+             HDR10_PLUS,
+             DOLBY_VISION_10B_HDR_REF,
+             DOLBY_VISION_10B_HDR_REF_PO,
+             DOLBY_VISION_10B_HDR_OEM,
+             DOLBY_VISION_10B_HDR_OEM_PO,
+             DOLBY_VISION_8B_HDR_REF,
+             DOLBY_VISION_8B_HDR_REF_PO,
+             DOLBY_VISION_8B_HDR_OEM,
+             DOLBY_VISION_8B_HDR_OEM_PO})
+    public @interface Profile {
+    }
+
+    private final HashMap<Integer, Set<Integer>> mProfileMap = new HashMap<>();
+
+    /**
+     * Create a new immutable DynamicRangeProfiles instance.
+     *
+     * <p>This constructor takes over the array; do not write to the array afterwards.</p>
+     *
+     * <p>Do note that the constructor is available for testing purposes only!
+     * Camera clients must always retrieve the value of
+     * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES}.
+     * for a given camera id in order to retrieve the device capabilities.</p>
+     *
+     * @param elements
+     *          An array of elements describing the map. It contains two elements per entry which
+     *          describe the supported dynamic range profile value in the first element and in the
+     *          second element a bitmap of concurrently supported dynamic range profiles within the
+     *          same capture request. Bitmap values of 0 indicate that there are no constraints.
+     *
+     * @throws IllegalArgumentException
+     *            if the {@code elements} array length is invalid, not divisible by 2 or contains
+     *            invalid element values
+     * @throws NullPointerException
+     *            if {@code elements} is {@code null}
+     *
+     */
+    public DynamicRangeProfiles(@NonNull final int[] elements) {
+        if ((elements.length % 2) != 0) {
+            throw new IllegalArgumentException("Dynamic range profile map length " +
+                    elements.length + " is not even!");
+        }
+
+        for (int i = 0; i < elements.length; i += 2) {
+            checkProfileValue(elements[i]);
+            // STANDARD is not expected to be included
+            if (elements[i] == STANDARD) {
+                throw new IllegalArgumentException("Dynamic range profile map must not include a"
+                        + " STANDARD profile entry!");
+            }
+            HashSet<Integer> profiles = new HashSet<>();
+
+            if (elements[i+1] != 0) {
+                for (int profile = STANDARD; profile < PUBLIC_MAX; profile <<= 1) {
+                    if ((elements[i+1] & profile) != 0) {
+                        profiles.add(profile);
+                    }
+                }
+            }
+
+            mProfileMap.put(elements[i], profiles);
+        }
+
+        // Build the STANDARD constraints depending on the advertised 10-bit limitations
+        HashSet<Integer> standardConstraints = new HashSet<>();
+        standardConstraints.add(STANDARD);
+        for(Integer profile : mProfileMap.keySet()) {
+            if (mProfileMap.get(profile).isEmpty() || mProfileMap.get(profile).contains(STANDARD)) {
+                standardConstraints.add(profile);
+            }
+        }
+
+        mProfileMap.put(STANDARD, standardConstraints);
+    }
+
+
+    /**
+     * @hide
+     */
+    public static void checkProfileValue(int profile) {
+        switch (profile) {
+            case STANDARD:
+            case HLG10:
+            case HDR10:
+            case HDR10_PLUS:
+            case DOLBY_VISION_10B_HDR_REF:
+            case DOLBY_VISION_10B_HDR_REF_PO:
+            case DOLBY_VISION_10B_HDR_OEM:
+            case DOLBY_VISION_10B_HDR_OEM_PO:
+            case DOLBY_VISION_8B_HDR_REF:
+            case DOLBY_VISION_8B_HDR_REF_PO:
+            case DOLBY_VISION_8B_HDR_OEM:
+            case DOLBY_VISION_8B_HDR_OEM_PO:
+                //No-op
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown profile " + profile);
+        }
+    }
+
+    /**
+     * Return a set of supported dynamic range profiles.
+     *
+     * @return non-modifiable set of dynamic range profiles
+     */
+     public @NonNull Set<Integer> getSupportedProfiles() {
+         return Collections.unmodifiableSet(mProfileMap.keySet());
+     }
+
+    /**
+     * Return a list of supported dynamic range profiles that
+     * can be referenced in a single capture request along with a given
+     * profile.
+     *
+     * <p>For example if assume that a particular 10-bit output capable device
+     * returns ({@link #STANDARD}, {@link #HLG10}, {@link #HDR10}) as result from calling
+     * {@link #getSupportedProfiles()} and {@link #getProfileCaptureRequestConstraints(int)}
+     * returns ({@link #STANDARD}, {@link #HLG10}) when given an argument of {@link #STANDARD}.
+     * This means that the corresponding camera device will only accept and process capture requests
+     * that reference outputs configured using {@link #HDR10} dynamic profile or alternatively
+     * some combination of {@link #STANDARD} and {@link #HLG10}. However trying to
+     * queue capture requests to outputs that reference both {@link #HDR10} and
+     * {@link #STANDARD}/{@link #HLG10} will result in {@link IllegalArgumentException}.</p>
+     *
+     * <p>The list will be empty in case there are no constraints for the given
+     * profile.</p>
+     *
+     * @return non-modifiable set of dynamic range profiles
+     * @throws IllegalArgumentException - If the profile argument is not
+     *                                    within the list returned by
+     *                                    getSupportedProfiles()
+     *
+     * @see OutputConfiguration#setDynamicRangeProfile(int)
+     */
+     public @NonNull Set<Integer> getProfileCaptureRequestConstraints(@Profile int profile) {
+         Set<Integer> ret = mProfileMap.get(profile);
+         if (ret == null) {
+             throw new IllegalArgumentException("Unsupported profile!");
+         }
+
+         return Collections.unmodifiableSet(ret);
+     }
+}
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index a678921..32c15da 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -18,8 +18,6 @@
 
 import static android.hardware.camera2.params.StreamConfigurationMap.checkArgumentFormat;
 
-import static com.android.internal.util.Preconditions.*;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.ImageFormat;
@@ -28,7 +26,6 @@
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CameraManager;
 import android.hardware.camera2.CameraMetadata;
-import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.HashCodeHelpers;
 import android.media.CamcorderProfile;
 import android.util.Log;
@@ -40,6 +37,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 
 /**
@@ -64,6 +62,7 @@
         private final boolean mIsInput;
         private final boolean mIsUltraHighResolution;
         private final boolean mIsMaximumSize;
+        private final boolean mIs10BitCapable;
 
         /**
          * Create a new {@link MandatoryStreamInformation}.
@@ -119,6 +118,29 @@
          */
         public MandatoryStreamInformation(@NonNull List<Size> availableSizes, @Format int format,
                 boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution) {
+            this(availableSizes, format, isMaximumSize, isInput, isUltraHighResolution,
+                    /*is10bitCapable*/ false);
+        }
+
+        /**
+         * Create a new {@link MandatoryStreamInformation}.
+         *
+         * @param availableSizes List of possible stream sizes.
+         * @param format Image format.
+         * @param isMaximumSize Whether this is a maximum size stream.
+         * @param isInput Flag indicating whether this stream is input.
+         * @param isUltraHighResolution Flag indicating whether this is a ultra-high resolution
+         *                              stream.
+         * @param is10BitCapable Flag indicating whether this stream is able to support 10-bit
+         *
+         * @throws IllegalArgumentException
+         *              if sizes is empty or if the format was not user-defined in
+         *              ImageFormat/PixelFormat.
+         * @hide
+         */
+        public MandatoryStreamInformation(@NonNull List<Size> availableSizes, @Format int format,
+                boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution,
+                boolean is10BitCapable) {
             if (availableSizes.isEmpty()) {
                 throw new IllegalArgumentException("No available sizes");
             }
@@ -127,6 +149,7 @@
             mIsMaximumSize = isMaximumSize;
             mIsInput = isInput;
             mIsUltraHighResolution = isUltraHighResolution;
+            mIs10BitCapable = is10BitCapable;
         }
 
         /**
@@ -180,6 +203,27 @@
         }
 
         /**
+         * Indicates whether this stream is able to support 10-bit output.
+         *
+         * <p>10-bit capable streams can be configured to output 10-bit sample data via calls to
+         * {@link android.hardware.camera2.params.OutputConfiguration#setDynamicRangeProfile} and
+         * selecting the appropriate output Surface pixel format which can be queried via
+         * {@link #get10BitFormat()} and will be either
+         * {@link ImageFormat#PRIVATE} (the default for Surfaces initialized by
+         * {@link android.view.SurfaceView}, {@link android.view.TextureView},
+         * {@link android.media.MediaRecorder}, {@link android.media.MediaCodec} etc.) or
+         * {@link ImageFormat#YCBCR_P010}.</p>
+         *
+         * @return true if stream is able to output 10-bit pixels
+         *
+         * @see android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT
+         * @see OutputConfiguration#setDynamicRangeProfile(int)
+         */
+        public boolean is10BitCapable() {
+            return mIs10BitCapable;
+        }
+
+        /**
          * Return the list of available sizes for this mandatory stream.
          *
          * <p>Per documented {@link CameraDevice#createCaptureSession guideline} the largest
@@ -201,6 +245,29 @@
          * @return integer format.
          */
         public @Format int getFormat() {
+            // P010 YUV streams must be supported along with SDR 8-bit YUV streams
+            if ((mIs10BitCapable)  && (mFormat == ImageFormat.YCBCR_P010)) {
+                return ImageFormat.YUV_420_888;
+            }
+            return mFormat;
+        }
+
+        /**
+         * Retrieve the mandatory stream 10-bit {@code format} for 10-bit capable streams.
+         *
+         * <p>In case {@link #is10BitCapable()} returns {@code true}, then this method
+         * will return the corresponding 10-bit output Surface pixel format. Depending on
+         * the stream type it will be either {@link ImageFormat#PRIVATE} or
+         * {@link ImageFormat#YCBCR_P010}.</p>
+         *
+         * @return integer format.
+         * @throws UnsupportedOperationException in case the stream is not capable of 10-bit output
+         * @see #is10BitCapable()
+         */
+        public @Format int get10BitFormat() {
+            if (!mIs10BitCapable) {
+                throw new UnsupportedOperationException("10-bit output is not supported!");
+            }
             return mFormat;
         }
 
@@ -932,6 +999,41 @@
                 /*reprocessType*/ ReprocessType.PRIVATE),
     };
 
+    private static StreamCombinationTemplate s10BitOutputStreamCombinations[] = {
+            new StreamCombinationTemplate(new StreamTemplate [] {
+                    new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.MAXIMUM)},
+                    "Simple preview, GPU video processing, or no-preview video recording"),
+            new StreamCombinationTemplate(new StreamTemplate [] {
+                    new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.MAXIMUM)},
+                    "In-application video/image processing"),
+            new StreamCombinationTemplate(new StreamTemplate [] {
+                    new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM),
+                    new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
+                    "Standard still imaging"),
+            new StreamCombinationTemplate(new StreamTemplate [] {
+                    new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.MAXIMUM),
+                    new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
+                    "Maximum-resolution in-app processing with preview"),
+            new StreamCombinationTemplate(new StreamTemplate [] {
+                    new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.MAXIMUM),
+                    new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.PREVIEW)},
+                    "Maximum-resolution two-input in-app processing"),
+            new StreamCombinationTemplate(new StreamTemplate [] {
+                    new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD),
+                    new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
+                    "High-resolution video recording with preview"),
+            new StreamCombinationTemplate(new StreamTemplate [] {
+                    new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.RECORD),
+                    new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD),
+                    new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
+                    "High-resolution recording with in-app snapshot"),
+            new StreamCombinationTemplate(new StreamTemplate [] {
+                    new StreamTemplate(ImageFormat.JPEG, SizeThreshold.RECORD),
+                    new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD),
+                    new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
+                    "High-resolution recording with video snapshot"),
+    };
+
     /**
      * Helper builder class to generate a list of available mandatory stream combinations.
      * @hide
@@ -971,6 +1073,86 @@
         }
 
         /**
+         * Retrieve a list of all available mandatory 10-bit output capable stream combinations.
+         *
+         * @return a non-modifiable list of supported mandatory 10-bit capable stream combinations,
+         *         null in case device is not 10-bit output capable.
+         */
+        public @NonNull List<MandatoryStreamCombination>
+        getAvailableMandatory10BitStreamCombinations() {
+            // Since 10-bit streaming support is optional, we mandate these stream
+            // combinations regardless of camera device capabilities.
+
+            StreamCombinationTemplate []chosenStreamCombinations = s10BitOutputStreamCombinations;
+            if (!is10BitOutputSupported()) {
+                Log.v(TAG, "Device is not able to output 10-bit!");
+                return null;
+            }
+
+            HashMap<Pair<SizeThreshold, Integer>, List<Size>> availableSizes =
+                    enumerateAvailableSizes();
+            if (availableSizes == null) {
+                Log.e(TAG, "Available size enumeration failed!");
+                return null;
+            }
+
+            ArrayList<MandatoryStreamCombination> availableStreamCombinations = new ArrayList<>();
+            availableStreamCombinations.ensureCapacity(chosenStreamCombinations.length);
+            for (StreamCombinationTemplate combTemplate : chosenStreamCombinations) {
+                ArrayList<MandatoryStreamInformation> streamsInfo = new ArrayList<>();
+                streamsInfo.ensureCapacity(combTemplate.mStreamTemplates.length);
+                for (StreamTemplate template : combTemplate.mStreamTemplates) {
+                    List<Size> sizes = null;
+                    Pair<SizeThreshold, Integer> pair;
+                    pair = new Pair<>(template.mSizeThreshold, new Integer(template.mFormat));
+                    sizes = availableSizes.get(pair);
+                    if (template.mFormat == ImageFormat.YCBCR_P010) {
+                        // Make sure that exactly the same 10 and 8-bit YUV streams sizes are
+                        // supported
+                        pair = new Pair<>(template.mSizeThreshold,
+                                new Integer(ImageFormat.YUV_420_888));
+                        HashSet<Size> sdrYuvSizes = new HashSet<>(availableSizes.get(pair));
+                        if (!sdrYuvSizes.equals(new HashSet<>(sizes))) {
+                            Log.e(TAG, "The supported 10-bit YUV sizes are different from the"
+                                    + " supported 8-bit YUV sizes!");
+                            return null;
+                        }
+                    }
+
+                    MandatoryStreamInformation streamInfo;
+                    boolean isMaximumSize =
+                            (template.mSizeThreshold == SizeThreshold.MAXIMUM);
+                    try {
+                        streamInfo = new MandatoryStreamInformation(sizes, template.mFormat,
+                                isMaximumSize, /*isInput*/ false,
+                                /*isUltraHighResolution*/ false,
+                                /*is10BitCapable*/ template.mFormat != ImageFormat.JPEG);
+                    } catch (IllegalArgumentException e) {
+                        Log.e(TAG, "No available sizes found for format: " + template.mFormat +
+                                " size threshold: " + template.mSizeThreshold + " combination: " +
+                                combTemplate.mDescription);
+                        return null;
+                    }
+                    streamsInfo.add(streamInfo);
+                }
+
+                MandatoryStreamCombination streamCombination;
+                try {
+                    streamCombination = new MandatoryStreamCombination(streamsInfo,
+                            combTemplate.mDescription, /*isReprocessable*/ false);
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG, "No stream information for mandatory combination: "
+                            + combTemplate.mDescription);
+                    return null;
+                }
+
+                availableStreamCombinations.add(streamCombination);
+            }
+
+            return Collections.unmodifiableList(availableStreamCombinations);
+        }
+
+        /**
           * Retrieve a list of all available mandatory concurrent stream combinations.
           * This method should only be called for devices which are listed in combinations returned
           * by CameraManager.getConcurrentCameraIds.
@@ -1444,7 +1626,8 @@
             final int[] formats = {
                 ImageFormat.PRIVATE,
                 ImageFormat.YUV_420_888,
-                ImageFormat.JPEG
+                ImageFormat.JPEG,
+                ImageFormat.YCBCR_P010
             };
             Size recordingMaxSize = new Size(0, 0);
             Size previewMaxSize = new Size(0, 0);
@@ -1464,7 +1647,11 @@
             HashMap<Integer, Size[]> allSizes = new HashMap<Integer, Size[]>();
             for (int format : formats) {
                 Integer intFormat = new Integer(format);
-                allSizes.put(intFormat, mStreamConfigMap.getOutputSizes(format));
+                Size[] sizes = mStreamConfigMap.getOutputSizes(format);
+                if (sizes == null) {
+                    sizes = new Size[0];
+                }
+                allSizes.put(intFormat, sizes);
             }
 
             List<Size> previewSizes = getSizesWithinBound(
@@ -1646,6 +1833,14 @@
         }
 
         /**
+         * Check whether the current device supports 10-bit output.
+         */
+        private boolean is10BitOutputSupported() {
+            return isCapabilitySupported(
+                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT);
+        }
+
+        /**
          * Check whether the current device supports private reprocessing.
          */
         private boolean isPrivateReprocessingSupported() {
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 5bb7201..f2b881b 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -29,6 +29,8 @@
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.MultiResolutionImageReader;
+import android.hardware.camera2.params.DynamicRangeProfiles;
+import android.hardware.camera2.params.DynamicRangeProfiles.Profile;
 import android.hardware.camera2.params.MultiResolutionStreamInfo;
 import android.hardware.camera2.utils.HashCodeHelpers;
 import android.hardware.camera2.utils.SurfaceUtils;
@@ -258,6 +260,39 @@
     }
 
     /**
+     * Set a specific device supported dynamic range profile.
+     *
+     * <p>Clients can choose from any profile advertised as supported in
+     * CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES
+     * queried using {@link DynamicRangeProfiles#getSupportedProfiles()}.
+     * If this is not explicitly set, then the default profile will be
+     * {@link DynamicRangeProfiles#STANDARD}.</p>
+     *
+     * <p>Do note that invalid combinations between the registered output
+     * surface pixel format and the configured dynamic range profile will
+     * cause capture session initialization failure. Invalid combinations
+     * include any 10-bit dynamic range profile advertised in
+     * {@link DynamicRangeProfiles#getSupportedProfiles()} combined with
+     * an output Surface pixel format different from {@link ImageFormat#PRIVATE}
+     * (the default for Surfaces initialized by {@link android.view.SurfaceView},
+     * {@link android.view.TextureView}, {@link android.media.MediaRecorder},
+     * {@link android.media.MediaCodec} etc.)
+     * or {@link ImageFormat#YCBCR_P010}.</p>
+     */
+    public void setDynamicRangeProfile(@Profile int profile) {
+        mDynamicRangeProfile = profile;
+    }
+
+    /**
+     * Return current dynamic range profile.
+     *
+     * @return the currently set dynamic range profile
+     */
+    public @Profile int getDynamicRangeProfile() {
+        return mDynamicRangeProfile;
+    }
+
+    /**
      * Create a new {@link OutputConfiguration} instance.
      *
      * <p>This constructor takes an argument for desired camera rotation</p>
@@ -319,6 +354,7 @@
         mPhysicalCameraId = null;
         mIsMultiResolution = false;
         mSensorPixelModesUsed = new ArrayList<Integer>();
+        mDynamicRangeProfile = DynamicRangeProfiles.STANDARD;
     }
 
     /**
@@ -416,6 +452,7 @@
         mPhysicalCameraId = null;
         mIsMultiResolution = false;
         mSensorPixelModesUsed = new ArrayList<Integer>();
+        mDynamicRangeProfile = DynamicRangeProfiles.STANDARD;
     }
 
     /**
@@ -718,6 +755,7 @@
         this.mPhysicalCameraId = other.mPhysicalCameraId;
         this.mIsMultiResolution = other.mIsMultiResolution;
         this.mSensorPixelModesUsed = other.mSensorPixelModesUsed;
+        this.mDynamicRangeProfile = other.mDynamicRangeProfile;
     }
 
     /**
@@ -737,6 +775,8 @@
         boolean isMultiResolutionOutput = source.readInt() == 1;
         int[] sensorPixelModesUsed = source.createIntArray();
         checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
+        int dynamicRangeProfile = source.readInt();
+        DynamicRangeProfiles.checkProfileValue(dynamicRangeProfile);
 
         mSurfaceGroupId = surfaceSetId;
         mRotation = rotation;
@@ -760,6 +800,7 @@
         mPhysicalCameraId = physicalCameraId;
         mIsMultiResolution = isMultiResolutionOutput;
         mSensorPixelModesUsed = convertIntArrayToIntegerList(sensorPixelModesUsed);
+        mDynamicRangeProfile = dynamicRangeProfile;
     }
 
     /**
@@ -875,6 +916,7 @@
         dest.writeInt(mIsMultiResolution ? 1 : 0);
         // writeList doesn't seem to work well with Integer list.
         dest.writeIntArray(convertIntegerToIntList(mSensorPixelModesUsed));
+        dest.writeInt(mDynamicRangeProfile);
     }
 
     /**
@@ -920,6 +962,9 @@
                 if (mSurfaces.get(i) != other.mSurfaces.get(i))
                     return false;
             }
+            if (mDynamicRangeProfile != other.mDynamicRangeProfile) {
+                return false;
+            }
 
             return true;
         }
@@ -939,7 +984,8 @@
                     mRotation, mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace,
                     mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0,
                     mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
-                    mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode());
+                    mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(),
+                    mDynamicRangeProfile);
         }
 
         return HashCodeHelpers.hashCode(
@@ -947,7 +993,8 @@
                 mConfiguredSize.hashCode(), mConfiguredFormat,
                 mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0,
                 mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
-                mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode());
+                mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(),
+                mDynamicRangeProfile);
     }
 
     private static final String TAG = "OutputConfiguration";
@@ -979,4 +1026,6 @@
     private boolean mIsMultiResolution;
     // The sensor pixel modes that this OutputConfiguration will use
     private ArrayList<Integer> mSensorPixelModesUsed;
+    // Dynamic range profile
+    private int mDynamicRangeProfile;
 }
diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
index 2d72598..80db38f 100644
--- a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
@@ -16,6 +16,8 @@
 
 package android.hardware.camera2.params;
 
+import static com.android.internal.R.string.hardware;
+
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -149,6 +151,16 @@
     public static final int USECASE_LOW_LATENCY_SNAPSHOT = 0x6;
 
     /**
+     * If supported, the recommended 10-bit output stream configurations must include
+     * a subset of the advertised {@link android.graphics.ImageFormat#YCBCR_P010} and
+     * {@link android.graphics.ImageFormat#PRIVATE} outputs that are optimized for power
+     * and performance when registered along with a supported 10-bit dynamic range profile.
+     * {@see android.hardware.camera2.params.OutputConfiguration#setDynamicRangeProfile} for
+     * details.
+     */
+     public static final int USECASE_10BIT_OUTPUT = 0x8;
+
+    /**
      * Device specific use cases.
      * @hide
      */
@@ -163,7 +175,8 @@
         USECASE_SNAPSHOT,
         USECASE_ZSL,
         USECASE_RAW,
-        USECASE_LOW_LATENCY_SNAPSHOT})
+        USECASE_LOW_LATENCY_SNAPSHOT,
+        USECASE_10BIT_OUTPUT})
      public @interface RecommendedUsecase {};
 
     /**
diff --git a/proto/src/camera.proto b/proto/src/camera.proto
index d07a525..0338b93 100644
--- a/proto/src/camera.proto
+++ b/proto/src/camera.proto
@@ -62,4 +62,7 @@
     // The frame counts for each histogram bins
     // Expected number of fields: 10
     repeated int64 histogram_counts = 13;
+
+    // The dynamic range profile of the stream
+    optional int32 dynamic_range_profile = 14;
 }
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 3120dc5..9d9b90c 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -788,6 +788,7 @@
                     streamProtos[i].histogramType = streamStats.getHistogramType();
                     streamProtos[i].histogramBins = streamStats.getHistogramBins();
                     streamProtos[i].histogramCounts = streamStats.getHistogramCounts();
+                    streamProtos[i].dynamicRangeProfile = streamStats.getDynamicRangeProfile();
 
                     if (CameraServiceProxy.DEBUG) {
                         String histogramTypeName =
@@ -807,7 +808,8 @@
                                 + ", histogramBins "
                                 + Arrays.toString(streamProtos[i].histogramBins)
                                 + ", histogramCounts "
-                                + Arrays.toString(streamProtos[i].histogramCounts));
+                                + Arrays.toString(streamProtos[i].histogramCounts)
+                                + ", dynamicRangeProfile " + streamProtos[i].dynamicRangeProfile);
                     }
                 }
             }