Enable camera preview to a SurfaceTexture.

This change adds a public Java API to use a SurfaceTexture as the
destination of camera preview frames.

Change-Id: If537fed2df12c5c181e2af5f817985c1bda853fb
diff --git a/api/current.xml b/api/current.xml
index 15d16d4..5307cd9 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -90535,6 +90535,19 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
+<method name="setPreviewTexture"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="surfaceTexture" type="android.graphics.SurfaceTexture">
+</parameter>
+</method>
 <method name="setZoomChangeListener"
  return="void"
  abstract="false"
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index d4bef75..207785c 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -27,6 +27,7 @@
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.graphics.ImageFormat;
+import android.graphics.SurfaceTexture;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -324,8 +325,10 @@
 
     /**
      * Sets the {@link Surface} to be used for live preview.
-     * A surface is necessary for preview, and preview is necessary to take
-     * pictures.  The same surface can be re-set without harm.
+     * Either a surface or surface texture is necessary for preview, and
+     * preview is necessary to take pictures.  The same surface can be re-set
+     * without harm.  Setting a preview surface will un-set any preview surface
+     * texture that was set via {@link #setPreviewTexture}.
      *
      * <p>The {@link SurfaceHolder} must already contain a surface when this
      * method is called.  If you are using {@link android.view.SurfaceView},
@@ -357,6 +360,29 @@
     private native final void setPreviewDisplay(Surface surface);
 
     /**
+     * Sets the {@link SurfaceTexture} to be used for live preview.
+     * Either a surface or surface texture is necessary for preview, and
+     * preview is necessary to take pictures.  The same surface texture can be
+     * re-set without harm.  Setting a preview surface texture will un-set any
+     * preview surface that was set via {@link #setPreviewDisplay}.
+     *
+     * <p>This method must be called before {@link #startPreview()}.  The
+     * one exception is that if the preview surface texture is not set (or set
+     * to null) before startPreview() is called, then this method may be called
+     * once with a non-null parameter to set the preview surface.  (This allows
+     * camera setup and surface creation to happen in parallel, saving time.)
+     * The preview surface texture may not otherwise change while preview is
+     * running.
+     *
+     * @param surfaceTexture the {@link SurfaceTexture} to which the preview
+     *     images are to be sent or null to remove the current preview surface
+     *     texture
+     * @throws IOException if the method fails (for example, if the surface
+     *     texture is unavailable or unsuitable).
+     */
+    public native final void setPreviewTexture(SurfaceTexture surfaceTexture);
+
+    /**
      * Callback interface used to deliver copies of preview frames as
      * they are displayed.
      *
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 10fe583..9f70509 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -25,6 +25,7 @@
 
 #include <utils/Vector.h>
 
+#include <gui/SurfaceTexture.h>
 #include <surfaceflinger/Surface.h>
 #include <camera/Camera.h>
 #include <binder/IMemory.h>
@@ -34,6 +35,7 @@
 struct fields_t {
     jfieldID    context;
     jfieldID    surface;
+    jfieldID    surfaceTexture;
     jfieldID    facing;
     jfieldID    orientation;
     jmethodID   post_event;
@@ -393,6 +395,24 @@
     }
 }
 
+static void android_hardware_Camera_setPreviewTexture(JNIEnv *env,
+        jobject thiz, jobject jSurfaceTexture)
+{
+    LOGV("setPreviewTexture");
+    sp<Camera> camera = get_native_camera(env, thiz, NULL);
+    if (camera == 0) return;
+
+    sp<SurfaceTexture> surfaceTexture = NULL;
+    if (jSurfaceTexture != NULL) {
+        surfaceTexture = reinterpret_cast<SurfaceTexture*>(env->GetIntField(
+                jSurfaceTexture, fields.surfaceTexture));
+    }
+    if (camera->setPreviewTexture(surfaceTexture) != NO_ERROR) {
+        jniThrowException(env, "java/io/IOException",
+                "setPreviewTexture failed");
+    }
+}
+
 static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
 {
     LOGV("startPreview");
@@ -603,6 +623,9 @@
   { "setPreviewDisplay",
     "(Landroid/view/Surface;)V",
     (void *)android_hardware_Camera_setPreviewDisplay },
+  { "setPreviewTexture",
+    "(Landroid/graphics/SurfaceTexture;)V",
+    (void *)android_hardware_Camera_setPreviewTexture },
   { "startPreview",
     "()V",
     (void *)android_hardware_Camera_startPreview },
@@ -688,6 +711,8 @@
     field fields_to_find[] = {
         { "android/hardware/Camera", "mNativeContext",   "I", &fields.context },
         { "android/view/Surface",    ANDROID_VIEW_SURFACE_JNI_ID, "I", &fields.surface },
+        { "android/graphics/SurfaceTexture",
+          ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I", &fields.surfaceTexture },
         { "android/hardware/Camera$CameraInfo", "facing",   "I", &fields.facing },
         { "android/hardware/Camera$CameraInfo", "orientation",   "I", &fields.orientation },
     };
@@ -708,4 +733,3 @@
     return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",
                                               camMethods, NELEM(camMethods));
 }
-