Add DataSpace API to convert between ADataSpace and ColorSpace

Also implement getDataSpace functions in SurfaceTexture and Image field
to help with upstream HDR work.

Bug: 201539996
Bug: 201535454
Test: android.hardware.camera2.cts.ImageWriterTest, android.hardware.cts.DataSpaceTest pass
Change-Id: I17fa43c1ba60e6f59da1910cebcef0dab993ce3b
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index bac44ad..f7bd614 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -17,9 +17,12 @@
 package android.media;
 
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Rect;
+import android.hardware.DataSpace;
+import android.hardware.DataSpace.NamedDataSpace;
 import android.hardware.HardwareBuffer;
 
 import java.nio.ByteBuffer;
@@ -272,6 +275,31 @@
         return;
     }
 
+    private @NamedDataSpace long mDataSpace = DataSpace.DATASPACE_UNKNOWN;
+
+    /**
+     * Get the dataspace associated with this frame.
+     */
+    @SuppressLint("MethodNameUnits")
+    public @NamedDataSpace long getDataSpace() {
+        throwISEIfImageIsInvalid();
+        return mDataSpace;
+    }
+
+    /**
+     * Set the dataspace associated with this frame.
+     * <p>
+     * If dataspace for an image is not set, dataspace value depends on {@link android.view.Surface}
+     * that is provided in the {@link ImageWriter} constructor.
+     * </p>
+     *
+     * @param dataSpace The Dataspace to be set for this image
+     */
+    public void setDataSpace(@NamedDataSpace long dataSpace) {
+        throwISEIfImageIsInvalid();
+        mDataSpace = dataSpace;
+    }
+
     private Rect mCropRect;
 
     /**
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 5656dff..bd0f32e 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -16,7 +16,6 @@
 
 package android.media;
 
-import android.annotation.CallbackExecutor;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.graphics.GraphicBuffer;
@@ -28,7 +27,6 @@
 import android.hardware.camera2.MultiResolutionImageReader;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.Message;
 import android.view.Surface;
 
 import dalvik.system.VMRuntime;
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 1b74367..1fc2cf9 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -23,9 +23,9 @@
 import android.graphics.ImageFormat.Format;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.SurfaceUtils;
-import android.hardware.HardwareBuffer;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -454,8 +454,9 @@
         }
 
         Rect crop = image.getCropRect();
-        nativeQueueInputImage(mNativeContext, image, image.getTimestamp(), crop.left, crop.top,
-                crop.right, crop.bottom, image.getTransform(), image.getScalingMode());
+        nativeQueueInputImage(mNativeContext, image, image.getTimestamp(), image.getDataSpace(),
+                crop.left, crop.top, crop.right, crop.bottom, image.getTransform(),
+                image.getScalingMode());
 
         /**
          * Only remove and cleanup the Images that are owned by this
@@ -642,13 +643,13 @@
         Rect crop = image.getCropRect();
         if (image.getNativeContext() != 0) {
             nativeAttachAndQueueImage(mNativeContext, image.getNativeContext(), image.getFormat(),
-                    image.getTimestamp(), crop.left, crop.top, crop.right, crop.bottom,
-                    image.getTransform(), image.getScalingMode());
+                    image.getTimestamp(), image.getDataSpace(), crop.left, crop.top, crop.right,
+                    crop.bottom, image.getTransform(), image.getScalingMode());
         } else {
             GraphicBuffer gb = GraphicBuffer.createFromHardwareBuffer(image.getHardwareBuffer());
             nativeAttachAndQueueGraphicBuffer(mNativeContext, gb, image.getFormat(),
-                    image.getTimestamp(), crop.left, crop.top, crop.right, crop.bottom,
-                    image.getTransform(), image.getScalingMode());
+                    image.getTimestamp(), image.getDataSpace(), crop.left, crop.top, crop.right,
+                    crop.bottom, image.getTransform(), image.getScalingMode());
             gb.destroy();
             image.close();
         }
@@ -976,15 +977,15 @@
     private synchronized native void nativeDequeueInputImage(long nativeCtx, Image wi);
 
     private synchronized native void nativeQueueInputImage(long nativeCtx, Image image,
-            long timestampNs, int left, int top, int right, int bottom, int transform,
-            int scalingMode);
+            long timestampNs, long dataSpace, int left, int top, int right, int bottom,
+            int transform, int scalingMode);
 
     private synchronized native int nativeAttachAndQueueImage(long nativeCtx,
-            long imageNativeBuffer, int imageFormat, long timestampNs, int left,
-            int top, int right, int bottom, int transform, int scalingMode);
+            long imageNativeBuffer, int imageFormat, long timestampNs, long dataSpace,
+            int left, int top, int right, int bottom, int transform, int scalingMode);
     private synchronized native int nativeAttachAndQueueGraphicBuffer(long nativeCtx,
-            GraphicBuffer graphicBuffer, int imageFormat, long timestampNs, int left,
-            int top, int right, int bottom, int transform, int scalingMode);
+            GraphicBuffer graphicBuffer, int imageFormat, long timestampNs, long dataSpace,
+            int left, int top, int right, int bottom, int transform, int scalingMode);
 
     private synchronized native void cancelImage(long nativeCtx, Image image);
 
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 5174c0c..021507c 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -48,6 +48,7 @@
 #define ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID       "mNativeContext"
 #define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID   "mNativeBuffer"
 #define ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID       "mTimestamp"
+#define ANDROID_MEDIA_SURFACEIMAGE_DS_JNI_ID       "mDataSpace"
 #define ANDROID_MEDIA_SURFACEIMAGE_TF_JNI_ID       "mTransform"
 #define ANDROID_MEDIA_SURFACEIMAGE_SM_JNI_ID       "mScalingMode"
 
@@ -71,6 +72,7 @@
 static struct {
     jfieldID mNativeBuffer;
     jfieldID mTimestamp;
+    jfieldID mDataSpace;
     jfieldID mTransform;
     jfieldID mScalingMode;
     jfieldID mPlanes;
@@ -319,6 +321,12 @@
                         "can't find android/graphics/ImageReader.%s",
                         ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID);
 
+    gSurfaceImageClassInfo.mDataSpace = env->GetFieldID(
+            imageClazz, ANDROID_MEDIA_SURFACEIMAGE_DS_JNI_ID, "J");
+    LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mDataSpace == NULL,
+                        "can't find android/graphics/ImageReader.%s",
+                        ANDROID_MEDIA_SURFACEIMAGE_DS_JNI_ID);
+
     gSurfaceImageClassInfo.mTransform = env->GetFieldID(
             imageClazz, ANDROID_MEDIA_SURFACEIMAGE_TF_JNI_ID, "I");
     LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mTransform == NULL,
@@ -619,6 +627,8 @@
     Image_setBufferItem(env, image, buffer);
     env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
             static_cast<jlong>(buffer->mTimestamp));
+    env->SetLongField(image, gSurfaceImageClassInfo.mDataSpace,
+            static_cast<jlong>(buffer->mDataSpace));
     auto transform = buffer->mTransform;
     if (buffer->mTransformToDisplayInverse) {
         transform |= NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index b291ac95b..0a5490d 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -53,6 +53,7 @@
 } gImageWriterClassInfo;
 
 static struct {
+    jfieldID mDataSpace;
     jfieldID mNativeBuffer;
     jfieldID mNativeFenceFd;
     jfieldID mPlanes;
@@ -87,6 +88,9 @@
     void setBufferHeight(int height) { mHeight = height; }
     int getBufferHeight() { return mHeight; }
 
+    void setBufferDataSpace(android_dataspace dataSpace) { mDataSpace = dataSpace; }
+    android_dataspace getBufferDataSpace() { return mDataSpace; }
+
     void queueAttachedFlag(bool isAttached) {
         Mutex::Autolock l(mAttachedFlagQueueLock);
         mAttachedFlagQueue.push_back(isAttached);
@@ -105,6 +109,7 @@
     int mFormat;
     int mWidth;
     int mHeight;
+    android_dataspace mDataSpace;
 
     // Class for a shared thread used to detach buffers from buffer queues
     // to discard buffers after consumers are done using them.
@@ -316,7 +321,7 @@
 // -------------------------------Private method declarations--------------
 
 static void Image_setNativeContext(JNIEnv* env, jobject thiz,
-        sp<GraphicBuffer> buffer, int fenceFd);
+        sp<GraphicBuffer> buffer, int fenceFd, long dataSpace);
 static void Image_getNativeContext(JNIEnv* env, jobject thiz,
         GraphicBuffer** buffer, int* fenceFd);
 static void Image_unlockIfLocked(JNIEnv* env, jobject thiz);
@@ -328,6 +333,12 @@
     jclass imageClazz = env->FindClass("android/media/ImageWriter$WriterSurfaceImage");
     LOG_ALWAYS_FATAL_IF(imageClazz == NULL,
             "can't find android/media/ImageWriter$WriterSurfaceImage");
+
+    gSurfaceImageClassInfo.mDataSpace = env->GetFieldID(
+            imageClazz, "mDataSpace", "J");
+    LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mDataSpace == NULL,
+            "can't find android/media/ImageWriter$WriterSurfaceImage.mDataSpace");
+
     gSurfaceImageClassInfo.mNativeBuffer = env->GetFieldID(
             imageClazz, IMAGE_BUFFER_JNI_ID, "J");
     LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mNativeBuffer == NULL,
@@ -465,6 +476,7 @@
             jniThrowRuntimeException(env, "Failed to set Surface dataspace");
             return 0;
         }
+        ctx->setBufferDataSpace(nativeDataspace);
         surfaceFormat = userFormat;
     }
 
@@ -544,7 +556,7 @@
     // 3. need use lockAsync here, as it will handle the dequeued fence for us automatically.
 
     // Finally, set the native info into image object.
-    Image_setNativeContext(env, image, buffer, fenceFd);
+    Image_setNativeContext(env, image, buffer, fenceFd, ctx->getBufferDataSpace());
 }
 
 static void ImageWriter_close(JNIEnv* env, jobject thiz, jlong nativeCtx) {
@@ -605,12 +617,12 @@
 
     anw->cancelBuffer(anw.get(), buffer, fenceFd);
 
-    Image_setNativeContext(env, image, NULL, -1);
+    Image_setNativeContext(env, image, NULL, -1, HAL_DATASPACE_UNKNOWN);
 }
 
 static void ImageWriter_queueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, jobject image,
-        jlong timestampNs, jint left, jint top, jint right, jint bottom, jint transform,
-        jint scalingMode) {
+        jlong timestampNs, jlong dataSpace, jint left, jint top, jint right,
+        jint bottom, jint transform, jint scalingMode) {
     ALOGV("%s", __FUNCTION__);
     JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
     if (ctx == NULL || thiz == NULL) {
@@ -642,6 +654,15 @@
         return;
     }
 
+    // Set dataSpace
+    ALOGV("dataSpace to be queued: %" PRId64, dataSpace);
+    res = native_window_set_buffers_data_space(
+        anw.get(), static_cast<android_dataspace>(dataSpace));
+    if (res != OK) {
+        jniThrowRuntimeException(env, "Set dataspace failed");
+        return;
+    }
+
     // Set crop
     android_native_rect_t cropRect;
     cropRect.left = left;
@@ -689,12 +710,12 @@
     }
 
     // Clear the image native context: end of this image's lifecycle in public API.
-    Image_setNativeContext(env, image, NULL, -1);
+    Image_setNativeContext(env, image, NULL, -1, HAL_DATASPACE_UNKNOWN);
 }
 
 static status_t attachAndQeueuGraphicBuffer(JNIEnv* env, JNIImageWriterContext *ctx,
-        sp<Surface> surface, sp<GraphicBuffer> gb, jlong timestampNs, jint left, jint top,
-        jint right, jint bottom, jint transform, jint scalingMode) {
+        sp<Surface> surface, sp<GraphicBuffer> gb, jlong timestampNs, jlong dataSpace,
+        jint left, jint top, jint right, jint bottom, jint transform, jint scalingMode) {
     status_t res = OK;
     // Step 1. Attach Image
     res = surface->attachBuffer(gb.get());
@@ -713,8 +734,8 @@
     }
     sp < ANativeWindow > anw = surface;
 
-    // Step 2. Set timestamp, crop, transform and scaling mode. Note that we do not need unlock the
-    // image because it was not locked.
+    // Step 2. Set timestamp, dataspace, crop, transform and scaling mode.
+    // Note that we do not need unlock the image because it was not locked.
     ALOGV("timestamp to be queued: %" PRId64, timestampNs);
     res = native_window_set_buffers_timestamp(anw.get(), timestampNs);
     if (res != OK) {
@@ -722,6 +743,14 @@
         return res;
     }
 
+    ALOGV("dataSpace to be queued: %" PRId64, dataSpace);
+    res = native_window_set_buffers_data_space(
+        anw.get(), static_cast<android_dataspace>(dataSpace));
+    if (res != OK) {
+        jniThrowRuntimeException(env, "Set dataSpace failed");
+        return res;
+    }
+
     android_native_rect_t cropRect;
     cropRect.left = left;
     cropRect.top = top;
@@ -775,8 +804,8 @@
 }
 
 static jint ImageWriter_attachAndQueueImage(JNIEnv* env, jobject thiz, jlong nativeCtx,
-        jlong nativeBuffer, jint imageFormat, jlong timestampNs, jint left, jint top,
-        jint right, jint bottom, jint transform, jint scalingMode) {
+        jlong nativeBuffer, jint imageFormat, jlong timestampNs, jlong dataSpace,
+        jint left, jint top, jint right, jint bottom, jint transform, jint scalingMode) {
     ALOGV("%s", __FUNCTION__);
     JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
     if (ctx == NULL || thiz == NULL) {
@@ -801,12 +830,12 @@
         return -1;
     }
 
-    return attachAndQeueuGraphicBuffer(env, ctx, surface, buffer->mGraphicBuffer, timestampNs, left,
-            top, right, bottom, transform, scalingMode);
+    return attachAndQeueuGraphicBuffer(env, ctx, surface, buffer->mGraphicBuffer, timestampNs,
+            dataSpace, left, top, right, bottom, transform, scalingMode);
 }
 
 static jint ImageWriter_attachAndQueueGraphicBuffer(JNIEnv* env, jobject thiz, jlong nativeCtx,
-        jobject buffer, jint format, jlong timestampNs, jint left, jint top,
+        jobject buffer, jint format, jlong timestampNs, jlong dataSpace, jint left, jint top,
         jint right, jint bottom, jint transform, jint scalingMode) {
     ALOGV("%s", __FUNCTION__);
     JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
@@ -830,9 +859,8 @@
                 "Trying to attach an invalid graphic buffer");
         return -1;
     }
-
-    return attachAndQeueuGraphicBuffer(env, ctx, surface, graphicBuffer, timestampNs, left,
-            top, right, bottom, transform, scalingMode);
+    return attachAndQeueuGraphicBuffer(env, ctx, surface, graphicBuffer, timestampNs,
+            dataSpace, left, top, right, bottom, transform, scalingMode);
 }
 
 // --------------------------Image methods---------------------------------------
@@ -853,7 +881,7 @@
 }
 
 static void Image_setNativeContext(JNIEnv* env, jobject thiz,
-        sp<GraphicBuffer> buffer, int fenceFd) {
+        sp<GraphicBuffer> buffer, int fenceFd, long dataSpace) {
     ALOGV("%s:", __FUNCTION__);
     GraphicBuffer* p = NULL;
     Image_getNativeContext(env, thiz, &p, /*fenceFd*/NULL);
@@ -867,6 +895,8 @@
             reinterpret_cast<jlong>(buffer.get()));
 
     env->SetIntField(thiz, gSurfaceImageClassInfo.mNativeFenceFd, reinterpret_cast<jint>(fenceFd));
+
+    env->SetLongField(thiz, gSurfaceImageClassInfo.mDataSpace, dataSpace);
 }
 
 static void Image_unlockIfLocked(JNIEnv* env, jobject thiz) {
@@ -1066,12 +1096,15 @@
     {"nativeInit",              "(Ljava/lang/Object;Landroid/view/Surface;IIII)J",
                                                               (void*)ImageWriter_init },
     {"nativeClose",              "(J)V",                      (void*)ImageWriter_close },
-    {"nativeAttachAndQueueImage", "(JJIJIIIIII)I",          (void*)ImageWriter_attachAndQueueImage },
+    {"nativeAttachAndQueueImage",
+        "(JJIJJIIIIII)I",
+        (void*)ImageWriter_attachAndQueueImage },
     {"nativeAttachAndQueueGraphicBuffer",
-        "(JLandroid/graphics/GraphicBuffer;IJIIIIII)I",
+        "(JLandroid/graphics/GraphicBuffer;IJJIIIIII)I",
         (void*)ImageWriter_attachAndQueueGraphicBuffer },
     {"nativeDequeueInputImage", "(JLandroid/media/Image;)V",  (void*)ImageWriter_dequeueImage },
-    {"nativeQueueInputImage",   "(JLandroid/media/Image;JIIIIII)V",  (void*)ImageWriter_queueImage },
+    {"nativeQueueInputImage",   "(JLandroid/media/Image;JJIIIIII)V",
+                                                               (void*)ImageWriter_queueImage },
     {"cancelImage",             "(JLandroid/media/Image;)V",   (void*)ImageWriter_cancelImage },
 };