Merge "Fix screen pinning in seascape" into oc-dev
diff --git a/api/current.txt b/api/current.txt
index cfcdb7d..f47a478 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12821,7 +12821,6 @@
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace);
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
-    method public static android.graphics.ColorSpace.Renderer createRenderer();
     method public float[] fromXyz(float, float, float);
     method public abstract float[] fromXyz(float[]);
     method public static android.graphics.ColorSpace get(android.graphics.ColorSpace.Named);
@@ -12905,16 +12904,6 @@
     enum_constant public static final android.graphics.ColorSpace.RenderIntent SATURATION;
   }
 
-  public static class ColorSpace.Renderer {
-    method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, int);
-    method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, float, float, float, int);
-    method public android.graphics.ColorSpace.Renderer clip(boolean);
-    method public android.graphics.Bitmap render();
-    method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean);
-    method public android.graphics.ColorSpace.Renderer size(int);
-    method public android.graphics.ColorSpace.Renderer uniformChromaticityScale(boolean);
-  }
-
   public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
     ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
     ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
diff --git a/api/system-current.txt b/api/system-current.txt
index df8d49a..1a40d6a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -13584,7 +13584,6 @@
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace);
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
-    method public static android.graphics.ColorSpace.Renderer createRenderer();
     method public float[] fromXyz(float, float, float);
     method public abstract float[] fromXyz(float[]);
     method public static android.graphics.ColorSpace get(android.graphics.ColorSpace.Named);
@@ -13668,16 +13667,6 @@
     enum_constant public static final android.graphics.ColorSpace.RenderIntent SATURATION;
   }
 
-  public static class ColorSpace.Renderer {
-    method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, int);
-    method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, float, float, float, int);
-    method public android.graphics.ColorSpace.Renderer clip(boolean);
-    method public android.graphics.Bitmap render();
-    method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean);
-    method public android.graphics.ColorSpace.Renderer size(int);
-    method public android.graphics.ColorSpace.Renderer uniformChromaticityScale(boolean);
-  }
-
   public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
     ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
     ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
diff --git a/api/test-current.txt b/api/test-current.txt
index a8060d8..42e3bd6 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -12871,7 +12871,6 @@
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace);
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
-    method public static android.graphics.ColorSpace.Renderer createRenderer();
     method public float[] fromXyz(float, float, float);
     method public abstract float[] fromXyz(float[]);
     method public static android.graphics.ColorSpace get(android.graphics.ColorSpace.Named);
@@ -12955,16 +12954,6 @@
     enum_constant public static final android.graphics.ColorSpace.RenderIntent SATURATION;
   }
 
-  public static class ColorSpace.Renderer {
-    method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, int);
-    method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, float, float, float, int);
-    method public android.graphics.ColorSpace.Renderer clip(boolean);
-    method public android.graphics.Bitmap render();
-    method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean);
-    method public android.graphics.ColorSpace.Renderer size(int);
-    method public android.graphics.ColorSpace.Renderer uniformChromaticityScale(boolean);
-  }
-
   public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
     ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
     ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 75de4da..0821674 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3628,7 +3628,7 @@
     <string name="data_usage_3g_limit_title">2G-3G data limit reached</string>
     <!-- Notification title when 4G data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
     <string name="data_usage_4g_limit_title">4G data limit reached</string>
-    <!-- Notification title when mobile data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
+    <!-- Notification title when mobile data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=50] -->
     <string name="data_usage_mobile_limit_title">Mobile data limit reached</string>
     <!-- Notification title when Wi-Fi data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
     <string name="data_usage_wifi_limit_title">Wi-Fi data limit reached</string>
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index e61d467..4fc63ea 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -123,39 +123,11 @@
  * and {@link #connect(ColorSpace, ColorSpace)}, are also guaranteed to be
  * thread-safe.</p>
  *
- * <h3>Visualization and debugging</h3>
- *
- * <p>To visualize and debug color spaces, you can call {@link #createRenderer()}.
- * The {@link Renderer} created by calling this method can be used to compare
- * color spaces and locate specific colors on a CIE 1931 or CIE 1976 UCS
- * chromaticity diagram.</p>
- *
- * <p>The following code snippet shows how to render a bitmap that compares
- * the color gamuts and white points of {@link Named#DCI_P3} and
- * {@link Named#PRO_PHOTO_RGB}:</p>
- *
- * <pre class="prettyprint">
- * Bitmap bitmap = ColorSpace.createRenderer()
- *     .size(768)
- *     .clip(true)
- *     .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845)
- *     .add(ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB), 0xff097ae9)
- *     .render();
- * </pre>
- * <p>
- *     <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_renderer.png" />
- *     <figcaption style="text-align: center;">DCI-P3 vs ProPhoto RGB</figcaption>
- * </p>
- *
- * <p>Please refer to the documentation of the {@link Renderer} class for more
- * information about its options and capabilities.</p>
- *
  * @see #get(Named)
  * @see Named
  * @see Model
  * @see Connector
  * @see Adaptation
- * @see Renderer
  */
 @AnyThread
 @SuppressWarnings("StaticInitializerReferencesSubClass")
@@ -1417,6 +1389,8 @@
      * @return A new non-null {@link Renderer} instance
      *
      * @see Renderer
+     *
+     * @hide
      */
     @NonNull
     public static Renderer createRenderer() {
@@ -3712,6 +3686,8 @@
      * See {@link #add(ColorSpace, float, float, float, int)} for more information.</p>
      *
      * @see ColorSpace#createRenderer()
+     *
+     * @hide
      */
     public static class Renderer {
         private static final int NATIVE_SIZE = 1440;
@@ -4054,7 +4030,7 @@
          */
         @NonNull
         @Size(6)
-        private static float[] getPrimaries(@NonNull Rgb rgb,
+        private static void getPrimaries(@NonNull Rgb rgb,
                 @NonNull @Size(6) float[] primaries, boolean asUcs) {
             // TODO: We should find a better way to handle these cases
             if (rgb.equals(ColorSpace.get(Named.EXTENDED_SRGB)) ||
@@ -4069,7 +4045,6 @@
                 rgb.getPrimaries(primaries);
             }
             if (asUcs) xyYToUv(primaries);
-            return primaries;
         }
 
         /**
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index ed71849..06555c1 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -17,6 +17,8 @@
 package android.media;
 
 import android.graphics.ImageFormat;
+import android.graphics.PixelFormat;
+import android.hardware.HardwareBuffer;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -72,6 +74,12 @@
     private static final int ACQUIRE_MAX_IMAGES = 2;
 
     /**
+     * Invalid consumer buffer usage flag. This usage flag will be ignored
+     * by the {@code ImageReader} instance is constructed with this value.
+     */
+    private static final long BUFFER_USAGE_UNKNOWN = 0;
+
+    /**
      * <p>
      * Create a new reader for images of the desired size and format.
      * </p>
@@ -121,13 +129,104 @@
      * @see Image
      */
     public static ImageReader newInstance(int width, int height, int format, int maxImages) {
-        return new ImageReader(width, height, format, maxImages);
+        return new ImageReader(width, height, format, maxImages, BUFFER_USAGE_UNKNOWN);
+    }
+
+    /**
+     * <p>
+     * Create a new reader for images of the desired size, format and consumer usage flag.
+     * </p>
+     * <p>
+     * The {@code maxImages} parameter determines the maximum number of {@link Image} objects that
+     * can be be acquired from the {@code 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>
+     * <p>
+     * The format and usage flag combination describes how the buffer will be used by
+     * consumer end-points. For example, if the application intends to send the images to
+     * {@link android.media.MediaCodec} or {@link android.media.MediaRecorder} for hardware video
+     * encoding, the format and usage flag combination needs to be
+     * {@link ImageFormat#PRIVATE PRIVATE} and {@link HardwareBuffer#USAGE0_VIDEO_ENCODE}. When an
+     * {@link ImageReader} object is created with a valid size and such format/usage flag
+     * combination, the application can send the {@link Image images} to an {@link ImageWriter} that
+     * is created with the input {@link android.view.Surface} provided by the
+     * {@link android.media.MediaCodec} or {@link android.media.MediaRecorder}.
+     * </p>
+     * <p>
+     * If the {@code format} is {@link ImageFormat#PRIVATE PRIVATE}, the created {@link ImageReader}
+     * will produce images that are not directly accessible by the application. The application can
+     * still acquire images from this {@link ImageReader}, and send them to the
+     * {@link android.hardware.camera2.CameraDevice camera} for reprocessing, or to the
+     * {@link android.media.MediaCodec} / {@link android.media.MediaRecorder} for hardware video
+     * encoding via {@link ImageWriter} interface. However, the {@link Image#getPlanes()
+     * getPlanes()} will return an empty array for {@link ImageFormat#PRIVATE PRIVATE} format
+     * images. The application can check if an existing reader's format by calling
+     * {@link #getImageFormat()}.
+     * </p>
+     * <p>
+     * {@link ImageFormat#PRIVATE PRIVATE} format {@link ImageReader ImageReaders} are more
+     * efficient to use when application access to image data is not necessary, compared to
+     * ImageReaders using other format such as {@link ImageFormat#YUV_420_888 YUV_420_888}.
+     * </p>
+     * <p>
+     * Note that not all format and usage flag combination is supported by the
+     * {@link ImageReader}. Below are the supported combinations by the {@link ImageReader}
+     * (assuming the consumer end-points support the such image consumption, e.g., hardware video
+     * encoding).
+     * <table>
+     * <tr>
+     *   <th>Format</th>
+     *   <th>Compatible usage flags</th>
+     * </tr>
+     * <tr>
+     *   <td>non-{@link android.graphics.ImageFormat#PRIVATE PRIVATE} formats defined by
+     *   {@link android.graphics.ImageFormat ImageFormat} or
+     *   {@link android.graphics.PixelFormat PixelFormat}</td>
+     *   <td>{@link HardwareBuffer#USAGE0_CPU_READ} or
+     *   {@link HardwareBuffer#USAGE0_CPU_READ_OFTEN}</td>
+     * </tr>
+     * <tr>
+     *   <td>{@link android.graphics.ImageFormat#PRIVATE}</td>
+     *   <td>{@link HardwareBuffer#USAGE0_VIDEO_ENCODE} or
+     *   {@link HardwareBuffer#USAGE0_GPU_SAMPLED_IMAGE}, or combined</td>
+     * </tr>
+     * </table>
+     * Using other combinations may result in {@link IllegalArgumentException}.
+     * </p>
+     * @param width The default width in pixels of the Images that this reader will produce.
+     * @param height The default 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. Note that not all formats are supported, like ImageFormat.NV21.
+     * @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 usage The intended usage of the images produced by this ImageReader. It needs
+     *            to be one of the Usage0 defined by {@link HardwareBuffer}, or an
+     *            {@link IllegalArgumentException} will be thrown.
+     * @see Image
+     * @see HardwareBuffer
+     * @hide
+     */
+    public static ImageReader newInstance(int width, int height, int format, int maxImages,
+            long usage) {
+        if (!isFormatUsageCombinationAllowed(format, usage)) {
+            throw new IllegalArgumentException("Format usage combination is not supported:"
+                    + " format = " + format + ", usage = " + usage);
+        }
+        return new ImageReader(width, height, format, maxImages, usage);
     }
 
     /**
      * @hide
      */
-    protected ImageReader(int width, int height, int format, int maxImages) {
+    protected ImageReader(int width, int height, int format, int maxImages, long usage) {
         mWidth = width;
         mHeight = height;
         mFormat = format;
@@ -149,7 +248,7 @@
 
         mNumPlanes = ImageUtils.getNumPlanesForFormat(mFormat);
 
-        nativeInit(new WeakReference<ImageReader>(this), width, height, format, maxImages);
+        nativeInit(new WeakReference<>(this), width, height, format, maxImages, usage);
 
         mSurface = nativeGetSurface();
 
@@ -617,6 +716,30 @@
         return si.getReader() == this;
     }
 
+    private static boolean isFormatUsageCombinationAllowed(int format, long usage) {
+        if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
+            return false;
+        }
+
+        // Valid usage needs to be provided.
+        if (usage == BUFFER_USAGE_UNKNOWN) {
+            return false;
+        }
+
+        if (format == ImageFormat.PRIVATE) {
+            // Usage need to be either USAGE0_GPU_SAMPLED_IMAGE or USAGE0_VIDEO_ENCODE or combined.
+            boolean isAllowed = (usage == HardwareBuffer.USAGE0_GPU_SAMPLED_IMAGE);
+            isAllowed = isAllowed || (usage == HardwareBuffer.USAGE0_VIDEO_ENCODE);
+            isAllowed = isAllowed || (usage ==
+                    (HardwareBuffer.USAGE0_VIDEO_ENCODE | HardwareBuffer.USAGE0_GPU_SAMPLED_IMAGE));
+            return isAllowed;
+        } else {
+            // Usage need to make the buffer CPU readable for explicit format.
+            return ((usage == HardwareBuffer.USAGE0_CPU_READ) ||
+                    (usage == HardwareBuffer.USAGE0_CPU_READ_OFTEN));
+        }
+    }
+
     /**
      * Called from Native code when an Event happens.
      *
@@ -655,7 +778,7 @@
     private ListenerHandler mListenerHandler;
     // Keep track of the successfully acquired Images. This need to be thread safe as the images
     // could be closed by different threads (e.g., application thread and GC thread).
-    private List<Image> mAcquiredImages = new CopyOnWriteArrayList<Image>();
+    private List<Image> mAcquiredImages = new CopyOnWriteArrayList<>();
 
     /**
      * This field is used by native code, do not access or modify.
@@ -896,7 +1019,7 @@
     }
 
     private synchronized native void nativeInit(Object weakSelf, int w, int h,
-                                                    int fmt, int maxImgs);
+                                                    int fmt, int maxImgs, long consumerUsage);
     private synchronized native void nativeClose();
     private synchronized native void nativeReleaseImage(Image i);
     private synchronized native Surface nativeGetSurface();
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index b142ddd..349c9cb 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.graphics.ImageFormat;
+import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.hardware.camera2.utils.SurfaceUtils;
 import android.os.Handler;
@@ -89,7 +90,7 @@
     private final int mMaxImages;
     // Keep track of the currently dequeued Image. This need to be thread safe as the images
     // could be closed by different threads (e.g., application thread and GC thread).
-    private List<Image> mDequeuedImages = new CopyOnWriteArrayList<Image>();
+    private List<Image> mDequeuedImages = new CopyOnWriteArrayList<>();
     private int mEstimatedNativeAllocBytes;
 
     /**
@@ -118,22 +119,75 @@
      * @return a new ImageWriter instance.
      */
     public static ImageWriter newInstance(Surface surface, int maxImages) {
-        return new ImageWriter(surface, maxImages);
+        return new ImageWriter(surface, maxImages, ImageFormat.UNKNOWN);
+    }
+
+    /**
+     * <p>
+     * Create a new ImageWriter with given number of max Images and format.
+     * </p>
+     * <p>
+     * The {@code maxImages} parameter determines the maximum number of
+     * {@link Image} objects that can be be dequeued from the
+     * {@code ImageWriter} simultaneously. Requesting more buffers will use up
+     * more memory, so it is important to use only the minimum number necessary.
+     * </p>
+     * <p>
+     * The format specifies the image format of this ImageWriter. The format
+     * from the {@code surface} will be overridden with this format. For example,
+     * if the surface is obtained from a {@link android.graphics.SurfaceTexture}, the default
+     * format may be {@link PixelFormat#RGBA_8888}. If the application creates an ImageWriter
+     * with this surface and {@link ImageFormat#PRIVATE}, this ImageWriter will be able to operate
+     * with {@link ImageFormat#PRIVATE} Images.
+     * </p>
+     * <p>
+     * Note that the consumer end-point may or may not be able to support Images with different
+     * format, for such case, the application should only use this method if the consumer is able
+     * to consume such images.
+     * </p>
+     * <p>
+     * The input Image size depends on the Surface that is provided by
+     * the downstream consumer end-point.
+     * </p>
+     *
+     * @param surface The destination Surface this writer produces Image data
+     *            into.
+     * @param maxImages The maximum number of Images the user will want to
+     *            access simultaneously for producing Image data. This should be
+     *            as small as possible to limit memory use. Once maxImages
+     *            Images are dequeued by the user, one of them has to be queued
+     *            back before a new Image can be dequeued for access via
+     *            {@link #dequeueInputImage()}.
+     * @param format The format of this ImageWriter. It can be any valid format specified by
+     *            {@link ImageFormat} or {@link PixelFormat}.
+     *
+     * @return a new ImageWriter instance.
+     * @hide
+     */
+    public static ImageWriter newInstance(Surface surface, int maxImages, int format) {
+        if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
+            throw new IllegalArgumentException("Invalid format is specified: " + format);
+        }
+        return new ImageWriter(surface, maxImages, format);
     }
 
     /**
      * @hide
      */
-    protected ImageWriter(Surface surface, int maxImages) {
+    protected ImageWriter(Surface surface, int maxImages, int format) {
         if (surface == null || maxImages < 1) {
             throw new IllegalArgumentException("Illegal input argument: surface " + surface
                     + ", maxImages: " + maxImages);
         }
 
         mMaxImages = maxImages;
+
+        if (format == ImageFormat.UNKNOWN) {
+            format = SurfaceUtils.getSurfaceFormat(surface);
+        }
         // Note that the underlying BufferQueue is working in synchronous mode
         // to avoid dropping any buffers.
-        mNativeContext = nativeInit(new WeakReference<ImageWriter>(this), surface, maxImages);
+        mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, format);
 
         // Estimate the native buffer allocation size and register it so it gets accounted for
         // during GC. Note that this doesn't include the buffers required by the buffer queue
@@ -142,7 +196,6 @@
         // complex, and 1 buffer is enough for the VM to treat the ImageWriter as being of some
         // size.
         Size surfSize = SurfaceUtils.getSurfaceSize(surface);
-        int format = SurfaceUtils.getSurfaceFormat(surface);
         mEstimatedNativeAllocBytes =
                 ImageUtils.getEstimatedNativeAllocBytes(surfSize.getWidth(),surfSize.getHeight(),
                         format, /*buffer count*/ 1);
@@ -809,7 +862,8 @@
     }
 
     // Native implemented ImageWriter methods.
-    private synchronized native long nativeInit(Object weakSelf, Surface surface, int maxImgs);
+    private synchronized native long nativeInit(Object weakSelf, Surface surface, int maxImgs,
+            int format);
 
     private synchronized native void nativeClose(long nativeCtx);
 
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 431d5d8..c2ed8cf 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -51,6 +51,7 @@
     libandroidfw
 
 LOCAL_STATIC_LIBRARIES := \
+    libgrallocusage \
 
 LOCAL_C_INCLUDES += \
     external/libexif/ \
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index f5e19f9..163c4b0 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -31,6 +31,8 @@
 
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
+#include <android_runtime/android_hardware_HardwareBuffer.h>
+#include <grallocusage/GrallocUsageConversion.h>
 
 #include <jni.h>
 #include <JNIHelp.h>
@@ -42,6 +44,7 @@
 #define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID   "mNativeBuffer"
 #define ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID       "mTimestamp"
 
+#define CONSUMER_BUFFER_USAGE_UNKNOWN              0;
 // ----------------------------------------------------------------------------
 
 using namespace android;
@@ -327,8 +330,8 @@
             "Can not find SurfacePlane constructor");
 }
 
-static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz,
-                             jint width, jint height, jint format, jint maxImages)
+static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint width, jint height,
+                             jint format, jint maxImages, jlong ndkUsage)
 {
     status_t res;
     int nativeFormat;
@@ -358,17 +361,29 @@
             width, height, format, maxImages, getpid(),
             createProcessUniqueId());
     uint32_t consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
+    bool needUsageOverride = ndkUsage != CONSUMER_BUFFER_USAGE_UNKNOWN;
+    uint64_t outProducerUsage = 0;
+    uint64_t outConsumerUsage = 0;
+    android_hardware_HardwareBuffer_convertToGrallocUsageBits(&outProducerUsage, &outConsumerUsage,
+            ndkUsage, 0);
 
     if (isFormatOpaque(nativeFormat)) {
         // Use the SW_READ_NEVER usage to tell producer that this format is not for preview or video
         // encoding. The only possibility will be ZSL output.
         consumerUsage = GRALLOC_USAGE_SW_READ_NEVER;
+        if (needUsageOverride) {
+            consumerUsage = android_convertGralloc1To0Usage(0, outConsumerUsage);
+        }
+    } else if (needUsageOverride) {
+        ALOGW("Consumer usage override for non-opaque format is not implemented yet, "
+                "ignore the provided usage from the application");
     }
     bufferConsumer = new BufferItemConsumer(gbConsumer, consumerUsage, maxImages,
             /*controlledByApp*/true);
     if (bufferConsumer == nullptr) {
         jniThrowExceptionFmt(env, "java/lang/RuntimeException",
-                "Failed to allocate native buffer consumer for format 0x%x", nativeFormat);
+                "Failed to allocate native buffer consumer for format 0x%x and usage 0x%x",
+                nativeFormat, consumerUsage);
         return;
     }
     ctx->setBufferConsumer(bufferConsumer);
@@ -788,7 +803,7 @@
 
 static const JNINativeMethod gImageReaderMethods[] = {
     {"nativeClassInit",        "()V",                        (void*)ImageReader_classInit },
-    {"nativeInit",             "(Ljava/lang/Object;IIII)V",  (void*)ImageReader_init },
+    {"nativeInit",             "(Ljava/lang/Object;IIIIJ)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 },
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 0149d76..ed5fbcf 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -33,7 +33,7 @@
 #include <inttypes.h>
 
 #define IMAGE_BUFFER_JNI_ID           "mNativeBuffer"
-
+#define IMAGE_FORMAT_UNKNOWN          0 // This is the same value as ImageFormat#UNKNOWN.
 // ----------------------------------------------------------------------------
 
 using namespace android;
@@ -222,7 +222,7 @@
 }
 
 static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobject jsurface,
-        jint maxImages) {
+        jint maxImages, jint userFormat) {
     status_t res;
 
     ALOGV("%s: maxImages:%d", __FUNCTION__, maxImages);
@@ -255,7 +255,7 @@
 
     // Get the dimension and format of the producer.
     sp<ANativeWindow> anw = producer;
-    int32_t width, height, format;
+    int32_t width, height, surfaceFormat;
     if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) {
         ALOGE("%s: Query Surface width failed: %s (%d)", __FUNCTION__, strerror(-res), res);
         jniThrowRuntimeException(env, "Failed to query Surface width");
@@ -270,21 +270,27 @@
     }
     ctx->setBufferHeight(height);
 
-    if ((res = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &format)) != OK) {
-        ALOGE("%s: Query Surface format failed: %s (%d)", __FUNCTION__, strerror(-res), res);
-        jniThrowRuntimeException(env, "Failed to query Surface format");
-        return 0;
+    // Query surface format if no valid user format is specified, otherwise, override surface format
+    // with user format.
+    if (userFormat == IMAGE_FORMAT_UNKNOWN) {
+        if ((res = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &surfaceFormat)) != OK) {
+            ALOGE("%s: Query Surface format failed: %s (%d)", __FUNCTION__, strerror(-res), res);
+            jniThrowRuntimeException(env, "Failed to query Surface format");
+            return 0;
+        }
+    } else {
+        surfaceFormat = userFormat;
     }
-    ctx->setBufferFormat(format);
-    env->SetIntField(thiz, gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(format));
+    ctx->setBufferFormat(surfaceFormat);
+    env->SetIntField(thiz,
+            gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(surfaceFormat));
 
-
-    if (!isFormatOpaque(format)) {
+    if (!isFormatOpaque(surfaceFormat)) {
         res = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
         if (res != OK) {
             ALOGE("%s: Configure usage %08x for format %08x failed: %s (%d)",
                   __FUNCTION__, static_cast<unsigned int>(GRALLOC_USAGE_SW_WRITE_OFTEN),
-                  format, strerror(-res), res);
+                  surfaceFormat, strerror(-res), res);
             jniThrowRuntimeException(env, "Failed to SW_WRITE_OFTEN configure usage");
             return 0;
         }
@@ -784,7 +790,7 @@
 
 static JNINativeMethod gImageWriterMethods[] = {
     {"nativeClassInit",         "()V",                        (void*)ImageWriter_classInit },
-    {"nativeInit",              "(Ljava/lang/Object;Landroid/view/Surface;I)J",
+    {"nativeInit",              "(Ljava/lang/Object;Landroid/view/Surface;II)J",
                                                               (void*)ImageWriter_init },
     {"nativeClose",              "(J)V",                      (void*)ImageWriter_close },
     {"nativeAttachAndQueueImage", "(JJIJIIII)I",          (void*)ImageWriter_attachAndQueueImage },
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index ff310cc..34f2822 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -423,7 +423,7 @@
     <string name="wifi_display_certification">Wireless display certification</string>
     <!-- Setting Checkbox title whether to enable WiFi Verbose Logging. [CHAR LIMIT=40] -->
     <string name="wifi_verbose_logging">Enable Wi\u2011Fi Verbose Logging</string>
-    <!-- Setting Checkbox title whether to enable WiFi Aggressive Handover. [CHAR LIMIT=40] -->
+    <!-- Setting Checkbox title whether to enable WiFi Aggressive Handover (more actively switch from wifi to mobile data). [CHAR LIMIT=40] -->
     <string name="wifi_aggressive_handover">Aggressive Wi\u2011Fi to mobile handover</string>
     <!-- Setting Checkbox title whether to enable WiFi Scanning in the presence of traffic. [CHAR LIMIT=80] -->
     <string name="wifi_allow_scan_with_traffic">Always allow Wi\u2011Fi Roam Scans</string>
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 64ee1e9..c1ffce3 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1421,6 +1421,11 @@
         return INotificationManager.Stub.asInterface(mService);
     }
 
+    @VisibleForTesting
+    NotificationManagerInternal getInternalService() {
+        return mInternalService;
+    }
+
     private final IBinder mService = new INotificationManager.Stub() {
         // Toasts
         // ============================================================================
@@ -2984,25 +2989,27 @@
                 int userId) {
             checkCallerIsSystem();
             synchronized (mNotificationLock) {
-                NotificationRecord r = findNotificationByListLocked(mNotificationList, pkg, null,
-                        notificationId, userId);
-                if (r == null) {
-                    Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
-                            + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
-                    return;
-                }
-                StatusBarNotification sbn = r.sbn;
-                // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
-                // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
-                // we have to revert to the flags we received initially *and* force remove
-                // FLAG_FOREGROUND_SERVICE.
-                sbn.getNotification().flags =
-                        (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
-                mRankingHelper.sort(mNotificationList);
-                mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
+                        NotificationRecord r =
+                                findNotificationLocked(pkg, null, notificationId, userId);
+                        if (r == null) {
+                            Log.d(TAG,
+                                    "stripForegroundServiceFlag: Could not find notification with "
+                                    + "pkg=" + pkg + " / id=" + notificationId
+                                    + " / userId=" + userId);
+                            return;
+                        }
+                        StatusBarNotification sbn = r.sbn;
+                        // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
+                        // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
+                        // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
+                        // initially *and* force remove FLAG_FOREGROUND_SERVICE.
+                        sbn.getNotification().flags =
+                                (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
+                        mRankingHelper.sort(mNotificationList);
+                        mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
                         mGroupHelper.onNotificationPosted(sbn);
                     }
                 });
@@ -4425,16 +4432,16 @@
         }
     }
 
-    protected static boolean isUidSystem(int uid) {
+    protected boolean isUidSystem(int uid) {
         final int appid = UserHandle.getAppId(uid);
         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
     }
 
-    private static boolean isCallerSystem() {
+    private boolean isCallerSystem() {
         return isUidSystem(Binder.getCallingUid());
     }
 
-    private static void checkCallerIsSystem() {
+    protected void checkCallerIsSystem() {
         if (isCallerSystem()) {
             return;
         }
diff --git a/services/tests/notification/Android.mk b/services/tests/notification/Android.mk
index a5d5570..940db79 100644
--- a/services/tests/notification/Android.mk
+++ b/services/tests/notification/Android.mk
@@ -23,7 +23,8 @@
     guava \
     android-support-test \
     mockito-target-minus-junit4 \
-    platform-test-annotations
+    platform-test-annotations \
+    testables
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 4c23d79..d9214fa 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -47,6 +47,7 @@
 import android.service.notification.StatusBarNotification;
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.InstrumentationRegistry;
+import android.testing.TestableLooper;
 
 import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
@@ -64,20 +65,29 @@
     private final int uid = Binder.getCallingUid();
     private NotificationManagerService mNotificationManagerService;
     private INotificationManager mBinderService;
+    private NotificationManagerInternal mInternalService;
     private IPackageManager mPackageManager = mock(IPackageManager.class);
     private final PackageManager mPackageManagerClient = mock(PackageManager.class);
     private Context mContext = InstrumentationRegistry.getTargetContext();
     private final String PKG = mContext.getPackageName();
-    private HandlerThread mThread;
+    private TestableLooper mTestableLooper;
     private final RankingHelper mRankingHelper = mock(RankingHelper.class);
     private NotificationChannel mTestNotificationChannel = new NotificationChannel(
             TEST_CHANNEL_ID, TEST_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT);
 
+    // Use a Testable subclass so we can simulate calls from the system without failing.
+    private static class TestableNotificationManagerService extends NotificationManagerService {
+        public TestableNotificationManagerService(Context context) { super(context); }
+
+        @Override
+        protected void checkCallerIsSystem() {}
+    }
+
     @Before
     @Test
     @UiThreadTest
     public void setUp() throws Exception {
-        mNotificationManagerService = new NotificationManagerService(mContext);
+        mNotificationManagerService = new TestableNotificationManagerService(mContext);
 
         // MockPackageManager - default returns ApplicationInfo with matching calling UID
         final ApplicationInfo applicationInfo = new ApplicationInfo();
@@ -88,9 +98,8 @@
                 .thenReturn(applicationInfo);
         final LightsManager mockLightsManager = mock(LightsManager.class);
         when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
-        // Use a separate thread for service looper.
-        mThread = new HandlerThread("TestThread");
-        mThread.start();
+        // Use this testable looper.
+        mTestableLooper = new TestableLooper(false);
         // Mock NotificationListeners to bypass security checks.
         final NotificationManagerService.NotificationListeners mockNotificationListeners =
                 mock(NotificationManagerService.NotificationListeners.class);
@@ -98,32 +107,19 @@
                 mockNotificationListeners.new ManagedServiceInfo(null,
                         new ComponentName(PKG, "test_class"), uid, true, null, 0));
 
-        mNotificationManagerService.init(mThread.getLooper(), mPackageManager,
+        mNotificationManagerService.init(mTestableLooper.getLooper(), mPackageManager,
                 mPackageManagerClient, mockLightsManager, mockNotificationListeners);
 
         // Tests call directly into the Binder.
         mBinderService = mNotificationManagerService.getBinderService();
+        mInternalService = mNotificationManagerService.getInternalService();
 
         mBinderService.createNotificationChannels(
                 PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
     }
 
     public void waitForIdle() throws Exception {
-        MessageQueue queue = mThread.getLooper().getQueue();
-        if (queue.isIdle()) {
-            return;
-        }
-        CountDownLatch latch = new CountDownLatch(1);
-        queue.addIdleHandler(new MessageQueue.IdleHandler() {
-                @Override public boolean queueIdle() {
-                    latch.countDown();
-                    return false;
-                }
-        });
-        // Timeout is valid in the cases where the queue goes idle before the IdleHandler
-        // is added.
-        latch.await(WAIT_FOR_IDLE_TIMEOUT, TimeUnit.SECONDS);
-        waitForIdle();
+        mTestableLooper.processAllMessages();
     }
 
     private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
@@ -260,7 +256,6 @@
 
     @Test
     @UiThreadTest
-    @Ignore("Flaky")
     public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
         mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
                 generateNotificationRecord(null).getNotification(), new int[1], 0);
@@ -380,6 +375,21 @@
 
     @Test
     @UiThreadTest
+    public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
+        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
+        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+                sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
+        mInternalService.removeForegroundServiceFlagFromNotification(PKG, sbn.getId(),
+                sbn.getUserId());
+        waitForIdle();
+        StatusBarNotification[] notifs =
+                mBinderService.getActiveNotifications(sbn.getPackageName());
+        assertEquals(0, notifs[0].getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE);
+    }
+
+    @Test
+    @UiThreadTest
     public void testTvExtenderChannelOverride_onTv() throws Exception {
         mNotificationManagerService.setIsTelevision(true);
         mNotificationManagerService.setRankingHelper(mRankingHelper);