NEW API: Add Image.getHardwareBuffer()

This mirror the corresponding NDK API. For some
reason this was missing from the java version
of Image.

Bug: 73784759
Test: manual
Change-Id: Iafa6dedda809fe38ea4453d9873d1ba886f88481
diff --git a/api/current.txt b/api/current.txt
index 39187b8..61f6147 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22756,6 +22756,7 @@
     method public abstract void close();
     method public android.graphics.Rect getCropRect();
     method public abstract int getFormat();
+    method public android.hardware.HardwareBuffer getHardwareBuffer();
     method public abstract int getHeight();
     method public abstract android.media.Image.Plane[] getPlanes();
     method public abstract long getTimestamp();
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index fbe5561..6dd4f69 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -19,7 +19,9 @@
 import java.nio.ByteBuffer;
 import java.lang.AutoCloseable;
 
+import android.annotation.Nullable;
 import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
 
 /**
  * <p>A single complete image buffer to use with a media source such as a
@@ -184,6 +186,23 @@
     public abstract long getTimestamp();
 
     /**
+     * Get the {@link android.hardware.HardwareBuffer HardwareBuffer} handle of the input image
+     * intended for GPU and/or hardware access.
+     * <p>
+     * The returned {@link android.hardware.HardwareBuffer HardwareBuffer} shall not be used
+     * after  {@link Image#close Image.close()} has been called.
+     * </p>
+     * @return the HardwareBuffer associated with this Image or null if this Image doesn't support
+     * this feature (e.g. {@link android.media.ImageWriter ImageWriter} or
+     * {@link android.media.MediaCodec MediaCodec} don't).
+     */
+    @Nullable
+    public HardwareBuffer getHardwareBuffer() {
+        throwISEIfImageIsInvalid();
+        return null;
+    }
+
+    /**
      * Set the timestamp associated with this frame.
      * <p>
      * The timestamp is measured in nanoseconds, and is normally monotonically
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 1019580..fb0de5c 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -876,6 +876,12 @@
         }
 
         @Override
+        public HardwareBuffer getHardwareBuffer() {
+            throwISEIfImageIsInvalid();
+            return nativeGetHardwareBuffer();
+        }
+
+        @Override
         public void setTimestamp(long timestampNs) {
             throwISEIfImageIsInvalid();
             mTimestamp = timestampNs;
@@ -1017,6 +1023,7 @@
         private synchronized native int nativeGetWidth();
         private synchronized native int nativeGetHeight();
         private synchronized native int nativeGetFormat(int readerFormat);
+        private synchronized native HardwareBuffer nativeGetHardwareBuffer();
     }
 
     private synchronized native void nativeInit(Object weakSelf, int w, int h,
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 3c8af8a..44e5d61 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -31,6 +31,7 @@
     shared_libs: [
         "libandroid_runtime",
         "libnativehelper",
+        "libnativewindow",
         "libutils",
         "libbinder",
         "libmedia",
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 885bf03..f5311764 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -33,11 +33,14 @@
 #include <android_runtime/android_hardware_HardwareBuffer.h>
 #include <grallocusage/GrallocUsageConversion.h>
 
+#include <private/android/AHardwareBufferHelpers.h>
+
 #include <jni.h>
 #include <nativehelper/JNIHelp.h>
 
 #include <stdint.h>
 #include <inttypes.h>
+#include <android/hardware_buffer_jni.h>
 
 #define ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID       "mNativeContext"
 #define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID   "mNativeBuffer"
@@ -797,6 +800,14 @@
     }
 }
 
+static jobject Image_getHardwareBuffer(JNIEnv* env, jobject thiz) {
+    BufferItem* buffer = Image_getBufferItem(env, thiz);
+    AHardwareBuffer* b = AHardwareBuffer_from_GraphicBuffer(buffer->mGraphicBuffer.get());
+    // don't user the public AHardwareBuffer_toHardwareBuffer() because this would force us
+    // to link against libandroid.so
+    return android_hardware_HardwareBuffer_createFromAHardwareBuffer(env, b);
+}
+
 } // extern "C"
 
 // ----------------------------------------------------------------------------
@@ -814,10 +825,12 @@
 
 static const JNINativeMethod gImageMethods[] = {
     {"nativeCreatePlanes",      "(II)[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
-                                                              (void*)Image_createSurfacePlanes },
-    {"nativeGetWidth",         "()I",                        (void*)Image_getWidth },
-    {"nativeGetHeight",        "()I",                        (void*)Image_getHeight },
-    {"nativeGetFormat",        "(I)I",                        (void*)Image_getFormat },
+                                                             (void*)Image_createSurfacePlanes },
+    {"nativeGetWidth",          "()I",                       (void*)Image_getWidth },
+    {"nativeGetHeight",         "()I",                       (void*)Image_getHeight },
+    {"nativeGetFormat",         "(I)I",                      (void*)Image_getFormat },
+    {"nativeGetHardwareBuffer", "()Landroid/hardware/HardwareBuffer;",
+                                                             (void*)Image_getHardwareBuffer },
 };
 
 int register_android_media_ImageReader(JNIEnv *env) {