merge in klp-factoryrom-release history after reset to klp-dev
diff --git a/api/current.txt b/api/current.txt
index a67512a..91fcab1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12334,7 +12334,7 @@
     field public static final int EULER_Z = 2; // 0x2
   }
 
-  public abstract class Image implements java.lang.AutoCloseable {
+  public abstract interface Image implements java.lang.AutoCloseable {
     method public abstract void close();
     method public abstract int getFormat();
     method public abstract int getHeight();
@@ -12343,23 +12343,23 @@
     method public abstract int getWidth();
   }
 
-  public static abstract class Image.Plane {
+  public static abstract interface Image.Plane {
     method public abstract java.nio.ByteBuffer getBuffer();
     method public abstract int getPixelStride();
     method public abstract int getRowStride();
   }
 
-  public class ImageReader implements java.lang.AutoCloseable {
-    method public android.media.Image acquireLatestImage();
-    method public android.media.Image acquireNextImage();
+  public final class ImageReader implements java.lang.AutoCloseable {
+    ctor public ImageReader(int, int, int, int);
     method public void close();
     method public int getHeight();
     method public int getImageFormat();
     method public int getMaxImages();
+    method public android.media.Image getNextImage();
     method public android.view.Surface getSurface();
     method public int getWidth();
-    method public static android.media.ImageReader newInstance(int, int, int, int);
-    method public void setOnImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
+    method public void releaseImage(android.media.Image);
+    method public void setImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
   }
 
   public static abstract interface ImageReader.OnImageAvailableListener {
diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
index a2e9ae8..ebecf2e3 100644
--- a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
+++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
@@ -83,8 +83,8 @@
 
         mImageReaderLock.lock();
         try {
-            mImageReader = ImageReader.newInstance(WIDTH, HEIGHT, PixelFormat.RGBA_8888, 2);
-            mImageReader.setOnImageAvailableListener(mImageListener, mHandler);
+            mImageReader = new ImageReader(WIDTH, HEIGHT, PixelFormat.RGBA_8888, 2);
+            mImageReader.setImageAvailableListener(mImageListener, mHandler);
             mSurface = mImageReader.getSurface();
         } finally {
             mImageReaderLock.unlock();
@@ -409,11 +409,19 @@
                 }
 
                 Log.d(TAG, "New image available from virtual display.");
-
-                // Get the latest buffer.
-                Image image = reader.acquireLatestImage();
+                Image image = reader.getNextImage();
                 if (image != null) {
                     try {
+                        // Get the latest buffer.
+                        for (;;) {
+                            Image nextImage = reader.getNextImage();
+                            if (nextImage == null) {
+                                break;
+                            }
+                            reader.releaseImage(image);
+                            image = nextImage;
+                        }
+
                         // Scan for colors.
                         int color = scanImage(image);
                         synchronized (this) {
@@ -423,7 +431,7 @@
                             }
                         }
                     } finally {
-                        image.close();
+                        reader.releaseImage(image);
                     }
                 }
             } finally {
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index a346e17..9f442f5 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -16,19 +16,20 @@
 
 package android.media;
 
+import android.graphics.ImageFormat;
 import java.nio.ByteBuffer;
 import java.lang.AutoCloseable;
 
 /**
  * <p>A single complete image buffer to use with a media source such as a
  * {@link MediaCodec} or a
- * {@link android.hardware.camera2.CameraDevice CameraDevice}.</p>
+ * {@link android.hardware.camera2.CameraDevice}.</p>
  *
  * <p>This class allows for efficient direct application access to the pixel
  * data of the Image through one or more
  * {@link java.nio.ByteBuffer ByteBuffers}. Each buffer is encapsulated in a
  * {@link Plane} that describes the layout of the pixel data in that plane. Due
- * to this direct access, and unlike the {@link android.graphics.Bitmap Bitmap} class,
+ * to this direct access, and unlike the {@link android.graphics.Bitmap} class,
  * Images are not directly usable as as UI resources.</p>
  *
  * <p>Since Images are often directly produced or consumed by hardware
@@ -39,28 +40,19 @@
  * from various media sources, not closing old Image objects will prevent the
  * availability of new Images once
  * {@link ImageReader#getMaxImages the maximum outstanding image count} is
- * reached. When this happens, the function acquiring new Images will typically
- * throw an {@link IllegalStateException}.</p>
+ * reached.</p>
  *
  * @see ImageReader
  */
-public abstract class Image implements AutoCloseable {
-    /**
-     * @hide
-     */
-    protected Image() {
-    }
-
+public interface Image extends AutoCloseable {
     /**
      * Get the format for this image. This format determines the number of
      * ByteBuffers needed to represent the image, and the general layout of the
      * pixel data in each in ByteBuffer.
      *
-     * <p>
      * The format is one of the values from
-     * {@link android.graphics.ImageFormat ImageFormat}. The mapping between the
-     * formats and the planes is as follows:
-     * </p>
+     * {@link android.graphics.ImageFormat}. The mapping between the formats and
+     * the planes is as follows:
      *
      * <table>
      * <tr>
@@ -69,14 +61,13 @@
      *   <th>Layout details</th>
      * </tr>
      * <tr>
-     *   <td>{@link android.graphics.ImageFormat#JPEG JPEG}</td>
+     *   <td>{@link android.graphics.ImageFormat#JPEG}</td>
      *   <td>1</td>
      *   <td>Compressed data, so row and pixel strides are 0. To uncompress, use
-     *      {@link android.graphics.BitmapFactory#decodeByteArray BitmapFactory#decodeByteArray}.
-     *   </td>
+     *      {@link android.graphics.BitmapFactory#decodeByteArray}.</td>
      * </tr>
      * <tr>
-     *   <td>{@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}</td>
+     *   <td>{@link android.graphics.ImageFormat#YUV_420_888}</td>
      *   <td>3</td>
      *   <td>A luminance plane followed by the Cb and Cr chroma planes.
      *     The chroma planes have half the width and height of the luminance
@@ -84,60 +75,53 @@
      *     Each plane has its own row stride and pixel stride.</td>
      * </tr>
      * <tr>
-     *   <td>{@link android.graphics.ImageFormat#RAW_SENSOR RAW_SENSOR}</td>
+     *   <td>{@link android.graphics.ImageFormat#RAW_SENSOR}</td>
      *   <td>1</td>
      *   <td>A single plane of raw sensor image data, with 16 bits per color
      *     sample. The details of the layout need to be queried from the source of
      *     the raw sensor data, such as
-     *     {@link android.hardware.camera2.CameraDevice CameraDevice}.
+     *     {@link android.hardware.camera2.CameraDevice}.
      *   </td>
      * </tr>
      * </table>
      *
      * @see android.graphics.ImageFormat
      */
-    public abstract int getFormat();
+    public int getFormat();
 
     /**
      * The width of the image in pixels. For formats where some color channels
      * are subsampled, this is the width of the largest-resolution plane.
      */
-    public abstract int getWidth();
+    public int getWidth();
 
     /**
      * The height of the image in pixels. For formats where some color channels
      * are subsampled, this is the height of the largest-resolution plane.
      */
-    public abstract int getHeight();
+    public int getHeight();
 
     /**
-     * Get the timestamp associated with this frame.
-     * <p>
-     * The timestamp is measured in nanoseconds, and is monotonically
-     * increasing. However, the zero point and whether the timestamp can be
-     * compared against other sources of time or images depend on the source of
-     * this image.
-     * </p>
+     * Get the timestamp associated with this frame. The timestamp is measured
+     * in nanoseconds, and is monotonically increasing. However, the zero point
+     * and whether the timestamp can be compared against other sources of time
+     * or images depend on the source of this image.
      */
-    public abstract long getTimestamp();
+    public long getTimestamp();
 
     /**
      * Get the array of pixel planes for this Image. The number of planes is
      * determined by the format of the Image.
      */
-    public abstract Plane[] getPlanes();
+    public Plane[] getPlanes();
 
     /**
-     * Free up this frame for reuse.
-     * <p>
-     * After calling this method, calling any methods on this {@code Image} will
-     * result in an {@link IllegalStateException}, and attempting to read from
-     * {@link ByteBuffer ByteBuffers} returned by an earlier
-     * {@link Plane#getBuffer} call will have undefined behavior.
-     * </p>
+     * Free up this frame for reuse. After calling this method, calling any
+     * methods on this Image will result in an IllegalStateException, and
+     * attempting to read from ByteBuffers returned by an earlier
+     * {@code Plane#getBuffer} call will have undefined behavior.
      */
-    @Override
-    public abstract void close();
+    public void close();
 
     /**
      * <p>A single color plane of image data.</p>
@@ -150,41 +134,29 @@
      *
      * @see #getFormat
      */
-    public static abstract class Plane {
+    public interface Plane {
         /**
-         * @hide
-         */
-        protected Plane() {
-        }
-
-        /**
-         * <p>The row stride for this color plane, in bytes.</p>
+         * <p>The row stride for this color plane, in bytes.
          *
          * <p>This is the distance between the start of two consecutive rows of
-         * pixels in the image. The row stride is always greater than 0.</p>
+         * pixels in the image.</p>
          */
-        public abstract int getRowStride();
+        public int getRowStride();
         /**
          * <p>The distance between adjacent pixel samples, in bytes.</p>
          *
          * <p>This is the distance between two consecutive pixel values in a row
          * of pixels. It may be larger than the size of a single pixel to
-         * account for interleaved image data or padded formats.
-         * The pixel stride is always greater than 0.</p>
+         * account for interleaved image data or padded formats.</p>
          */
-        public abstract int getPixelStride();
+        public int getPixelStride();
         /**
-         * <p>Get a direct {@link java.nio.ByteBuffer ByteBuffer}
+         * <p>Get a set of direct {@link java.nio.ByteBuffer byte buffers}
          * containing the frame data.</p>
          *
-         * <p>In particular, the buffer returned will always have
-         * {@link java.nio.ByteBuffer#isDirect isDirect} return {@code true}, so
-         * the underlying data could be mapped as a pointer in JNI without doing
-         * any copies with {@code GetDirectBufferAddress}.</p>
-         *
          * @return the byte buffer containing the image data for this plane.
          */
-        public abstract ByteBuffer getBuffer();
+        public ByteBuffer getBuffer();
     }
 
 }
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index f9e48d4..b14a899 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -20,7 +20,6 @@
 import android.graphics.PixelFormat;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.Message;
 import android.view.Surface;
 
 import java.lang.ref.WeakReference;
@@ -41,67 +40,41 @@
  * <p>The image data is encapsulated in {@link Image} objects, and multiple such
  * objects can be accessed at the same time, up to the number specified by the
  * {@code maxImages} constructor parameter. New images sent to an ImageReader
- * through its {@link Surface} are queued until accessed through the {@link #acquireLatestImage}
- * or {@link #acquireNextImage} call. Due to memory limits, an image source will
+ * through its Surface are queued until accessed through the
+ * {@link #getNextImage} call. Due to memory limits, an image source will
  * eventually stall or drop Images in trying to render to the Surface if the
  * ImageReader does not obtain and release Images at a rate equal to the
  * production rate.</p>
  */
-public class ImageReader implements AutoCloseable {
-
-    /**
-     * Returned by nativeImageSetup when acquiring the image was successful.
-     */
-    private static final int ACQUIRE_SUCCESS = 0;
-    /**
-     * Returned by nativeImageSetup when we couldn't acquire the buffer,
-     * because there were no buffers available to acquire.
-     */
-    private static final int ACQUIRE_NO_BUFS = 1;
-    /**
-     * Returned by nativeImageSetup when we couldn't acquire the buffer
-     * because the consumer has already acquired {@maxImages} and cannot
-     * acquire more than that.
-     */
-    private static final int ACQUIRE_MAX_IMAGES = 2;
+public final class ImageReader implements AutoCloseable {
 
     /**
      * <p>Create a new reader for images of the desired size and format.</p>
      *
-     * <p>The {@code maxImages} parameter determines the maximum number of {@link Image}
-     * objects that can be be acquired from the {@code ImageReader}
+     * <p>The maxImages parameter determines the maximum number of {@link Image}
+     * objects that can be be acquired from the ImageReader
      * simultaneously. Requesting more buffers will use up more memory, so it is
      * important to use only the minimum number necessary for the use case.</p>
      *
      * <p>The valid sizes and formats depend on the source of the image
      * data.</p>
      *
-     * @param width
-     *            The width in pixels of the Images that this reader will produce.
-     * @param height
-     *            The height in pixels of the Images that this reader will produce.
-     * @param format
-     *            The format of the Image that this reader will produce. This
-     *            must be one of the {@link android.graphics.ImageFormat} or
-     *            {@link android.graphics.PixelFormat} constants.
-     * @param maxImages
-     *            The maximum number of images the user will want to
-     *            access simultaneously. This should be as small as possible to limit
-     *            memory use. Once maxImages Images are obtained by the user, one of them
-     *            has to be released before a new Image will become available for access
-     *            through {@link #acquireLatestImage()} or {@link #acquireNextImage()}.
-     *            Must be greater than 0.
+     * @param width the width in pixels of the Images that this reader will
+     * produce.
+     * @param height the height in pixels of the Images that this reader will
+     * produce.
+     * @param format the format of the Image that this reader will produce. This
+     * must be one of the {@link android.graphics.ImageFormat} or
+     * {@link android.graphics.PixelFormat} constants.
+     * @param maxImages the maximum number of images the user will want to
+     * access simultaneously. This should be as small as possible to limit
+     * memory use. Once maxImages Images are obtained by the user, one of them
+     * has to be released before a new Image will become available for access
+     * through getNextImage(). Must be greater than 0.
      *
      * @see Image
      */
-    public static ImageReader newInstance(int width, int height, int format, int maxImages) {
-        return new ImageReader(width, height, format, maxImages);
-    }
-
-    /**
-     * @hide
-     */
-    protected ImageReader(int width, int height, int format, int maxImages) {
+    public ImageReader(int width, int height, int format, int maxImages) {
         mWidth = width;
         mHeight = height;
         mFormat = format;
@@ -123,79 +96,33 @@
         mSurface = nativeGetSurface();
     }
 
-    /**
-     * The width of each {@link Image}, in pixels.
-     *
-     * <p>ImageReader guarantees that all Images acquired from ImageReader (for example, with
-     * {@link #acquireNextImage}) will have the same dimensions as specified in
-     * {@link #newInstance}.</p>
-     *
-     * @return the width of an Image
-     */
     public int getWidth() {
         return mWidth;
     }
 
-    /**
-     * The height of each {@link Image}, in pixels.
-     *
-     * <p>ImageReader guarantees that all Images acquired from ImageReader (for example, with
-     * {@link #acquireNextImage}) will have the same dimensions as specified in
-     * {@link #newInstance}.</p>
-     *
-     * @return the height of an Image
-     */
     public int getHeight() {
         return mHeight;
     }
 
-    /**
-     * The {@link ImageFormat image format} of each Image.
-     *
-     * <p>ImageReader guarantees that all {@link Image Images} acquired from ImageReader
-     *  (for example, with {@link #acquireNextImage}) will have the same format as specified in
-     * {@link #newInstance}.</p>
-     *
-     * @return the format of an Image
-     *
-     * @see ImageFormat
-     */
     public int getImageFormat() {
         return mFormat;
     }
 
-    /**
-     * Maximum number of images that can be acquired from the ImageReader by any time (for example,
-     * with {@link #acquireNextImage}).
-     *
-     * <p>An image is considered acquired after it's returned by a function from ImageReader, and
-     * until the Image is {@link Image#close closed} to release the image back to the ImageReader.
-     * </p>
-     *
-     * <p>Attempting to acquire more than {@code maxImages} concurrently will result in the
-     * acquire function throwing a {@link IllegalStateException}. Furthermore,
-     * while the max number of images have been acquired by the ImageReader user, the producer
-     * enqueueing additional images may stall until at least one image has been released. </p>
-     *
-     * @return Maximum number of images for this ImageReader.
-     *
-     * @see Image#close
-     */
     public int getMaxImages() {
         return mMaxImages;
     }
 
     /**
-     * <p>Get a {@link Surface} that can be used to produce {@link Image Images} for this
-     * {@code ImageReader}.</p>
+     * <p>Get a Surface that can be used to produce Images for this
+     * ImageReader.</p>
      *
-     * <p>Until valid image data is rendered into this {@link Surface}, the
-     * {@link #acquireNextImage} method will return {@code null}. Only one source
+     * <p>Until valid image data is rendered into this Surface, the
+     * {@link #getNextImage} method will return {@code null}. Only one source
      * can be producing data into this Surface at the same time, although the
-     * same {@link Surface} can be reused with a different API once the first source is
-     * disconnected from the {@link Surface}.</p>
+     * same Surface can be reused with a different API once the first source is
+     * disconnected from the Surface.</p>
      *
-     * @return A {@link Surface} to use for a drawing target for various APIs.
+     * @return A Surface to use for a drawing target for various APIs.
      */
     public Surface getSurface() {
         return mSurface;
@@ -203,154 +130,41 @@
 
     /**
      * <p>
-     * Acquire the latest {@link Image} from the ImageReader's queue, dropping older
-     * {@link Image images}. Returns {@code null} if no new image is available.
-     * </p>
-     * <p>
-     * This operation will acquire all the images possible from the ImageReader,
-     * but {@link #close} all images that aren't the latest. This function is
-     * recommended to use over {@link #acquireNextImage} for most use-cases, as it's
-     * more suited for real-time processing.
-     * </p>
-     * <p>
-     * Note that {@link #getMaxImages maxImages} should be at least 2 for
-     * {@link #acquireLatestImage} to be any different than {@link #acquireNextImage} -
-     * discarding all-but-the-newest {@link Image} requires temporarily acquiring two
-     * {@link Image Images} at once. Or more generally, calling {@link #acquireLatestImage}
-     * with less than two images of margin, that is
-     * {@code (maxImages - currentAcquiredImages < 2)} will not discard as expected.
-     * </p>
-     * <p>
-     * This operation will fail by throwing an {@link IllegalStateException} if
-     * {@code maxImages} have been acquired with {@link #acquireLatestImage} or
-     * {@link #acquireNextImage}. In particular a sequence of {@link #acquireLatestImage}
-     * calls greater than {@link #getMaxImages} without calling {@link Image#close} in-between
-     * will exhaust the underlying queue. At such a time, {@link IllegalStateException}
-     * will be thrown until more images are
-     * released with {@link Image#close}.
-     * </p>
-     *
-     * @return latest frame of image data, or {@code null} if no image data is available.
-     * @throws IllegalStateException if too many images are currently acquired
-     */
-    public Image acquireLatestImage() {
-        Image image = acquireNextImage();
-        if (image == null) {
-            return null;
-        }
-        try {
-            for (;;) {
-                Image next = acquireNextImageNoThrowISE();
-                if (next == null) {
-                    Image result = image;
-                    image = null;
-                    return result;
-                }
-                image.close();
-                image = next;
-            }
-        } finally {
-            if (image != null) {
-                image.close();
-            }
-        }
-    }
-
-    /**
-     * Don't throw IllegalStateException if there are too many images acquired.
-     *
-     * @return Image if acquiring succeeded, or null otherwise.
-     *
-     * @hide
-     */
-    public Image acquireNextImageNoThrowISE() {
-        SurfaceImage si = new SurfaceImage();
-        return acquireNextSurfaceImage(si) == ACQUIRE_SUCCESS ? si : null;
-    }
-
-    /**
-     * Attempts to acquire the next image from the underlying native implementation.
-     *
-     * <p>
-     * Note that unexpected failures will throw at the JNI level.
-     * </p>
-     *
-     * @param si A blank SurfaceImage.
-     * @return One of the {@code ACQUIRE_*} codes that determine success or failure.
-     *
-     * @see #ACQUIRE_MAX_IMAGES
-     * @see #ACQUIRE_NO_BUFS
-     * @see #ACQUIRE_SUCCESS
-     */
-    private int acquireNextSurfaceImage(SurfaceImage si) {
-
-        int status = nativeImageSetup(si);
-
-        switch (status) {
-            case ACQUIRE_SUCCESS:
-                si.createSurfacePlanes();
-                si.setImageValid(true);
-            case ACQUIRE_NO_BUFS:
-            case ACQUIRE_MAX_IMAGES:
-                break;
-            default:
-                throw new AssertionError("Unknown nativeImageSetup return code " + status);
-        }
-
-        return status;
-    }
-
-    /**
-     * <p>
-     * Acquire the next Image from the ImageReader's queue. Returns {@code null} if
+     * Get the next Image from the ImageReader's queue. Returns {@code null} if
      * no new image is available.
      * </p>
-     *
-     * <p><i>Warning:</i> Consider using {@link #acquireLatestImage()} instead, as it will
-     * automatically release older images, and allow slower-running processing routines to catch
-     * up to the newest frame. Usage of {@link #acquireNextImage} is recommended for
-     * batch/background processing. Incorrectly using this function can cause images to appear
-     * with an ever-increasing delay, followed by a complete stall where no new images seem to
-     * appear.
-     * </p>
-     *
      * <p>
-     * This operation will fail by throwing an {@link IllegalStateException} if
-     * {@code maxImages} have been acquired with {@link #acquireNextImage} or
-     * {@link #acquireLatestImage}. In particular a sequence of {@link #acquireNextImage} or
-     * {@link #acquireLatestImage} calls greater than {@link #getMaxImages maxImages} without
-     * calling {@link Image#close} in-between will exhaust the underlying queue. At such a time,
-     * {@link IllegalStateException} will be thrown until more images are released with
-     * {@link Image#close}.
+     * This operation will fail by throwing an
+     * {@link Surface.OutOfResourcesException OutOfResourcesException} if too
+     * many images have been acquired with {@link #getNextImage}. In particular
+     * a sequence of {@link #getNextImage} calls greater than {@link #getMaxImages}
+     * without calling {@link Image#close} or {@link #releaseImage} in-between
+     * will exhaust the underlying queue. At such a time,
+     * {@link Surface.OutOfResourcesException OutOfResourcesException} will be
+     * thrown until more images are released with {@link Image#close} or
+     * {@link #releaseImage}.
      * </p>
      *
-     * @return a new frame of image data, or {@code null} if no image data is available.
-     * @throws IllegalStateException if {@code maxImages} images are currently acquired
-     * @see #acquireLatestImage
+     * @return a new frame of image data, or {@code null} if no image data is
+     *         available.
+     * @throws Surface.OutOfResourcesException if too many images are currently
+     *         acquired
      */
-    public Image acquireNextImage() {
+    public Image getNextImage() {
         SurfaceImage si = new SurfaceImage();
-        int status = acquireNextSurfaceImage(si);
-
-        switch (status) {
-            case ACQUIRE_SUCCESS:
-                return si;
-            case ACQUIRE_NO_BUFS:
-                return null;
-            case ACQUIRE_MAX_IMAGES:
-                throw new IllegalStateException(
-                        String.format(
-                                "maxImages (%d) has already been acquired, " +
-                                "call #close before acquiring more.", mMaxImages));
-            default:
-                throw new AssertionError("Unknown nativeImageSetup return code " + status);
+        if (nativeImageSetup(si)) {
+            // create SurfacePlane objects
+            si.createSurfacePlanes();
+            si.setImageValid(true);
+            return si;
         }
+        return null;
     }
 
     /**
      * <p>Return the frame to the ImageReader for reuse.</p>
      */
-    private void releaseImage(Image i) {
+    public void releaseImage(Image i) {
         if (! (i instanceof SurfaceImage) ) {
             throw new IllegalArgumentException(
                 "This image was not produced by an ImageReader");
@@ -369,46 +183,35 @@
     /**
      * Register a listener to be invoked when a new image becomes available
      * from the ImageReader.
+     * @param listener the listener that will be run
+     * @param handler The handler on which the listener should be invoked, or null
+     * if the listener should be invoked on the calling thread's looper.
      *
-     * @param listener
-     *            The listener that will be run.
-     * @param handler
-     *            The handler on which the listener should be invoked, or null
-     *            if the listener should be invoked on the calling thread's looper.
-     * @throws IllegalArgumentException
-     *            If no handler specified and the calling thread has no looper.
+     * @throws IllegalArgumentException if no handler specified and the calling thread has no looper
      */
-    public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
-        synchronized (mListenerLock) {
-            if (listener != null) {
-                Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
-                if (looper == null) {
-                    throw new IllegalArgumentException(
-                            "handler is null but the current thread is not a looper");
-                }
-                if (mListenerHandler == null || mListenerHandler.getLooper() != looper) {
-                    mListenerHandler = new ListenerHandler(looper);
-                }
-                mListener = listener;
+   public void setImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
+        mImageListener = listener;
+
+        Looper looper;
+        mHandler = handler;
+        if (listener != null && mHandler == null) {
+            if ((looper = Looper.myLooper()) != null) {
+                mHandler = new Handler();
             } else {
-                mListener = null;
-                mListenerHandler = null;
+                throw new IllegalArgumentException(
+                        "Looper doesn't exist in the calling thread");
             }
         }
     }
 
     /**
      * Callback interface for being notified that a new image is available.
-     *
-     * <p>
      * The onImageAvailable is called per image basis, that is, callback fires for every new frame
      * available from ImageReader.
-     * </p>
      */
     public interface OnImageAvailableListener {
         /**
          * Callback that is called when a new image is available from ImageReader.
-         *
          * @param reader the ImageReader the callback is associated with.
          * @see ImageReader
          * @see Image
@@ -417,21 +220,15 @@
     }
 
     /**
-     * Free up all the resources associated with this ImageReader.
-     *
-     * <p>
-     * After calling this method, this ImageReader can not be used. Calling
-     * any methods on this ImageReader and Images previously provided by
-     * {@link #acquireNextImage} or {@link #acquireLatestImage}
-     * will result in an {@link IllegalStateException}, and attempting to read from
-     * {@link ByteBuffer ByteBuffers} returned by an earlier
-     * {@link Image.Plane#getBuffer Plane#getBuffer} call will
+     * Free up all the resources associated with this ImageReader. After
+     * Calling this method, this ImageReader can not be used. calling
+     * any methods on this ImageReader and Images previously provided by {@link #getNextImage}
+     * will result in an IllegalStateException, and attempting to read from
+     * ByteBuffers returned by an earlier {@code Plane#getBuffer} call will
      * have undefined behavior.
-     * </p>
      */
     @Override
     public void close() {
-        setOnImageAvailableListener(null, null);
         nativeClose();
     }
 
@@ -445,14 +242,11 @@
     }
 
     /**
-     * Only a subset of the formats defined in
-     * {@link android.graphics.ImageFormat ImageFormat} and
-     * {@link android.graphics.PixelFormat PixelFormat} are supported by
-     * ImageReader. When reading RGB data from a surface, the formats defined in
-     * {@link android.graphics.PixelFormat PixelFormat} can be used, when
-     * reading YUV, JPEG or raw sensor data (for example, from camera or video
-     * decoder), formats from {@link android.graphics.ImageFormat ImageFormat}
-     * are used.
+     * Only a subset of the formats defined in {@link android.graphics.ImageFormat} and
+     * {@link android.graphics.PixelFormat} are supported by ImageReader. When reading RGB
+     * data from a surface, the formats defined in {@link android.graphics.PixelFormat}
+     * can be used, when reading YUV, JPEG or raw sensor data ( for example, from camera
+     *  or video decoder), formats from {@link android.graphics.ImageFormat} are used.
      */
     private int getNumPlanesFromFormat() {
         switch (mFormat) {
@@ -480,9 +274,6 @@
 
     /**
      * Called from Native code when an Event happens.
-     *
-     * This may be called from an arbitrary Binder thread, so access to the ImageReader must be
-     * synchronized appropriately.
      */
     private static void postEventFromNative(Object selfRef) {
         @SuppressWarnings("unchecked")
@@ -492,16 +283,16 @@
             return;
         }
 
-        final Handler handler;
-        synchronized (ir.mListenerLock) {
-            handler = ir.mListenerHandler;
-        }
-        if (handler != null) {
-            handler.sendEmptyMessage(0);
+        if (ir.mHandler != null && ir.mImageListener != null) {
+            ir.mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    ir.mImageListener.onImageAvailable(ir);
+                }
+              });
         }
     }
 
-
     private final int mWidth;
     private final int mHeight;
     private final int mFormat;
@@ -509,36 +300,15 @@
     private final int mNumPlanes;
     private final Surface mSurface;
 
-    private final Object mListenerLock = new Object();
-    private OnImageAvailableListener mListener;
-    private ListenerHandler mListenerHandler;
+    private Handler mHandler;
+    private OnImageAvailableListener mImageListener;
 
     /**
      * This field is used by native code, do not access or modify.
      */
     private long mNativeContext;
 
-    /**
-     * This custom handler runs asynchronously so callbacks don't get queued behind UI messages.
-     */
-    private final class ListenerHandler extends Handler {
-        public ListenerHandler(Looper looper) {
-            super(looper, null, true /*async*/);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            OnImageAvailableListener listener;
-            synchronized (mListenerLock) {
-                listener = mListener;
-            }
-            if (listener != null) {
-                listener.onImageAvailable(ImageReader.this);
-            }
-        }
-    }
-
-    private class SurfaceImage extends android.media.Image {
+    private class SurfaceImage implements android.media.Image {
         public SurfaceImage() {
             mIsImageValid = false;
         }
@@ -634,7 +404,7 @@
                 mPlanes[i] = nativeCreatePlane(i);
             }
         }
-        private class SurfacePlane extends android.media.Image.Plane {
+        private class SurfacePlane implements android.media.Image.Plane {
             // SurfacePlane instance is created by native code when a new SurfaceImage is created
             private SurfacePlane(int index, int rowStride, int pixelStride) {
                 mIndex = index;
@@ -709,17 +479,9 @@
     private synchronized native void nativeClose();
     private synchronized native void nativeReleaseImage(Image i);
     private synchronized native Surface nativeGetSurface();
+    private synchronized native boolean nativeImageSetup(Image i);
 
-    /**
-     * @return A return code {@code ACQUIRE_*}
-     *
-     * @see #ACQUIRE_SUCCESS
-     * @see #ACQUIRE_NO_BUFS
-     * @see #ACQUIRE_MAX_IMAGES
-     */
-    private synchronized native int nativeImageSetup(Image i);
-
-    /**
+    /*
      * We use a class initializer to allow the native code to cache some
      * field offsets.
      */
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index a03dbf3..94f20bc 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -43,14 +43,11 @@
 
 using namespace android;
 
-enum {
-    IMAGE_READER_MAX_NUM_PLANES = 3,
-};
+static const char* const OutOfResourcesException =
+    "android/view/Surface$OutOfResourcesException";
 
 enum {
-    ACQUIRE_SUCCESS = 0,
-    ACQUIRE_NO_BUFFERS = 1,
-    ACQUIRE_MAX_IMAGES = 2,
+    IMAGE_READER_MAX_NUM_PLANES = 3,
 };
 
 static struct {
@@ -688,14 +685,14 @@
     ctx->returnLockedBuffer(buffer);
 }
 
-static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz,
+static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz,
                                              jobject image)
 {
     ALOGV("%s:", __FUNCTION__);
     JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
     if (ctx == NULL) {
         jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
-        return -1;
+        return false;
     }
 
     CpuConsumer* consumer = ctx->getCpuConsumer();
@@ -703,22 +700,27 @@
     if (buffer == NULL) {
         ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
             " maxImages buffers");
-        return ACQUIRE_MAX_IMAGES;
+        jniThrowException(env, OutOfResourcesException,
+                  "Too many outstanding images, close existing images"
+                  " to be able to acquire more.");
+        return false;
     }
     status_t res = consumer->lockNextBuffer(buffer);
     if (res != NO_ERROR) {
         if (res != BAD_VALUE /*no buffers*/) {
             if (res == NOT_ENOUGH_DATA) {
-                return ACQUIRE_MAX_IMAGES;
+                jniThrowException(env, OutOfResourcesException,
+                          "Too many outstanding images, close existing images"
+                          " to be able to acquire more.");
             } else {
                 ALOGE("%s Fail to lockNextBuffer with error: %d ",
                       __FUNCTION__, res);
-                jniThrowExceptionFmt(env, "java/lang/AssertionError",
+                jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
                           "Unknown error (%d) when we tried to lock buffer.",
                           res);
             }
         }
-        return ACQUIRE_NO_BUFFERS;
+        return false;
     }
 
     // Check if the left-top corner of the crop rect is origin, we currently assume this point is
@@ -728,7 +730,7 @@
         ALOGE("crop left: %d, top = %d", lt.x, lt.y);
         jniThrowException(env, "java/lang/UnsupportedOperationException",
                           "crop left top corner need to at origin");
-        return -1;
+        return false;
     }
 
     // Check if the producer buffer configurations match what ImageReader configured.
@@ -737,9 +739,11 @@
     int outputHeight = buffer->height;
 
     // Correct width/height when crop is set.
-    if (!buffer->crop.isEmpty()) {
-        outputWidth = buffer->crop.getWidth();
-        outputHeight = buffer->crop.getHeight();
+    if (buffer->crop.getWidth() > 0) {
+        outputWidth = buffer->crop.getWidth() + 1;
+    }
+    if (buffer->crop.getHeight() > 0) {
+        outputHeight = buffer->crop.getHeight() + 1;
     }
 
     int imageReaderWidth = ctx->getBufferWidth();
@@ -757,7 +761,6 @@
         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
                 "Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
                 outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
-        return -1;
     }
 
     if (ctx->getBufferFormat() != buffer->format) {
@@ -774,14 +777,14 @@
                 buffer->format, ctx->getBufferFormat());
         jniThrowException(env, "java/lang/UnsupportedOperationException",
                 msg.string());
-        return -1;
+        return false;
     }
     // Set SurfaceImage instance member variables
     Image_setBuffer(env, image, buffer);
     env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
             static_cast<jlong>(buffer->timestamp));
 
-    return ACQUIRE_SUCCESS;
+    return true;
 }
 
 static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz)
@@ -852,7 +855,7 @@
     {"nativeInit",             "(Ljava/lang/Object;IIII)V",  (void*)ImageReader_init },
     {"nativeClose",            "()V",                        (void*)ImageReader_close },
     {"nativeReleaseImage",     "(Landroid/media/Image;)V",   (void*)ImageReader_imageRelease },
-    {"nativeImageSetup",       "(Landroid/media/Image;)I",    (void*)ImageReader_imageSetup },
+    {"nativeImageSetup",       "(Landroid/media/Image;)Z",    (void*)ImageReader_imageSetup },
     {"nativeGetSurface",       "()Landroid/view/Surface;",   (void*)ImageReader_getSurface },
 };
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
index 64b12b7..ecdc287 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
@@ -49,7 +49,6 @@
         addMediaPlayerStateUnitTests(suite);
         addMediaScannerUnitTests(suite);
         addCameraUnitTests(suite);
-        addImageReaderTests(suite);
         return suite;
     }
 
@@ -66,10 +65,6 @@
         suite.addTestSuite(CameraMetadataTest.class);
     }
 
-    private void addImageReaderTests(TestSuite suite) {
-        suite.addTestSuite(ImageReaderTest.class);
-    }
-
     // Running all unit tests checking the state machine may be time-consuming.
     private void addMediaMetadataRetrieverStateUnitTests(TestSuite suite) {
         suite.addTestSuite(MediaMetadataRetrieverTest.class);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java
deleted file mode 100644
index f6cd990..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2013 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 com.android.mediaframeworktest.unit;
-
-import static org.mockito.Mockito.*;
-
-import android.graphics.ImageFormat;
-import android.media.Image;
-import android.media.Image.Plane;
-import android.media.ImageReader;
-import android.media.ImageReader.OnImageAvailableListener;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-public class ImageReaderTest extends AndroidTestCase {
-
-    private static final String TAG = "ImageReaderTest-unit";
-
-    private static final int DEFAULT_WIDTH = 640;
-    private static final int DEFAULT_HEIGHT = 480;
-    private static final int DEFAULT_FORMAT = ImageFormat.YUV_420_888;
-    private static final int DEFAULT_MAX_IMAGES = 3;
-
-    private ImageReader mReader;
-    private Image mImage1;
-    private Image mImage2;
-    private Image mImage3;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        /**
-         * Workaround for mockito and JB-MR2 incompatibility
-         *
-         * Avoid java.lang.IllegalArgumentException: dexcache == null
-         * https://code.google.com/p/dexmaker/issues/detail?id=2
-         */
-        System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
-
-        // TODO: refactor above into one of the test runners
-
-        mReader = spy(ImageReader.newInstance(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                DEFAULT_MAX_IMAGES));
-        mImage1 = mock(Image.class);
-        mImage2 = mock(Image.class);
-        mImage3 = mock(Image.class);
-
-        /**
-         * Ensure rest of classes are mockable
-         */
-        {
-            mock(Plane.class);
-            mock(OnImageAvailableListener.class);
-        }
-
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mReader.close();
-
-        super.tearDown();
-    }
-
-    /**
-     * Return null when there is nothing in the image queue.
-     */
-    @SmallTest
-    public void testGetLatestImageEmpty() {
-        when(mReader.acquireNextImage()).thenReturn(null);
-        when(mReader.acquireNextImageNoThrowISE()).thenReturn(null);
-        assertEquals(null, mReader.acquireLatestImage());
-    }
-
-    /**
-     * Return the last image from the image queue, close up the rest.
-     */
-    @SmallTest
-    public void testGetLatestImage1() {
-        when(mReader.acquireNextImage()).thenReturn(mImage1);
-        when(mReader.acquireNextImageNoThrowISE()).thenReturn(null);
-        assertEquals(mImage1, mReader.acquireLatestImage());
-        verify(mImage1, never()).close();
-    }
-
-    /**
-     * Return the last image from the image queue, close up the rest.
-     */
-    @SmallTest
-    public void testGetLatestImage2() {
-        when(mReader.acquireNextImage()).thenReturn(mImage1);
-        when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).thenReturn(null);
-        assertEquals(mImage2, mReader.acquireLatestImage());
-        verify(mImage1, atLeastOnce()).close();
-        verify(mImage2, never()).close();
-    }
-
-    /**
-     * Return the last image from the image queue, close up the rest.
-     */
-    @SmallTest
-    public void testGetLatestImage3() {
-        when(mReader.acquireNextImage()).thenReturn(mImage1);
-        when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
-                                                   thenReturn(mImage3).
-                                                   thenReturn(null);
-        assertEquals(mImage3, mReader.acquireLatestImage());
-        verify(mImage1, atLeastOnce()).close();
-        verify(mImage2, atLeastOnce()).close();
-        verify(mImage3, never()).close();
-    }
-
-    /**
-     * Return null if get a IllegalStateException with no images in the queue.
-     */
-    @SmallTest
-    public void testGetLatestImageTooManyBuffersAcquiredEmpty()  {
-        when(mReader.acquireNextImage()).thenThrow(new IllegalStateException());
-        try {
-            mReader.acquireLatestImage();
-            fail("Expected IllegalStateException to be thrown");
-        } catch(IllegalStateException e) {
-        }
-    }
-
-    /**
-     * All images are cleaned up when we get an unexpected Error.
-     */
-    @SmallTest
-    public void testGetLatestImageExceptionalError() {
-        when(mReader.acquireNextImage()).thenReturn(mImage1);
-        when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
-                                                   thenReturn(mImage3).
-                                                   thenThrow(new OutOfMemoryError());
-        try {
-            mReader.acquireLatestImage();
-            fail("Impossible");
-        } catch(OutOfMemoryError e) {
-        }
-
-        verify(mImage1, atLeastOnce()).close();
-        verify(mImage2, atLeastOnce()).close();
-        verify(mImage3, atLeastOnce()).close();
-    }
-
-    /**
-     * All images are cleaned up when we get an unexpected RuntimeException.
-     */
-    @SmallTest
-    public void testGetLatestImageExceptionalRuntime() {
-
-        when(mReader.acquireNextImage()).thenReturn(mImage1);
-        when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
-                                                   thenReturn(mImage3).
-                                                   thenThrow(new RuntimeException());
-        try {
-            mReader.acquireLatestImage();
-            fail("Impossible");
-        } catch(RuntimeException e) {
-        }
-
-        verify(mImage1, atLeastOnce()).close();
-        verify(mImage2, atLeastOnce()).close();
-        verify(mImage3, atLeastOnce()).close();
-    }
-}