Merge changes from topics 'hw_prohibit_copy_buffer', 'hw_create_immutable_bitmap', 'recycled_getConfig'

* changes:
  Prohibit copyPixelsToBuffer & copyPixelsFromBuffer
  HardwareBitmaps: support createBitmap methods that return immutable bitmap
  Fix getConfig on recycled bitmap
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 8f74bf8..59cbc93 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -52,6 +52,7 @@
         mAllocationSize = mBitmap->getAllocationByteCount();
         mRowBytes = mBitmap->rowBytes();
         mGenerationId = mBitmap->getGenerationID();
+        mIsHardware = mBitmap->isHardware();
         mBitmap.reset();
     }
 
@@ -118,6 +119,13 @@
         return mGenerationId;
     }
 
+    bool isHardware() {
+        if (mBitmap) {
+            return mBitmap->isHardware();
+        }
+        return mIsHardware;
+    }
+
     ~BitmapWrapper() { }
 
 private:
@@ -127,6 +135,7 @@
     size_t mAllocationSize;
     size_t mRowBytes;
     uint32_t mGenerationId;
+    bool mIsHardware;
 };
 
 // Convenience class that does not take a global ref on the pixels, relying
@@ -775,7 +784,7 @@
 
 static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
     LocalScopedBitmap bitmap(bitmapHandle);
-    if (bitmap->bitmap().isHardware()) {
+    if (bitmap->isHardware()) {
         return GraphicsJNI::hardwareLegacyBitmapConfig();
     }
     return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType());
@@ -1208,7 +1217,7 @@
     // Paying the price for making Hardware Bitmap as Config:
     // later check for colorType will pass successfully,
     // because Hardware Config internally may be RGBA8888 or smth like that.
-    if (bitmap0->bitmap().isHardware() != bitmap1->bitmap().isHardware()) {
+    if (bitmap0->isHardware() != bitmap1->isHardware()) {
         return JNI_FALSE;
     }
 
@@ -1282,6 +1291,23 @@
     return static_cast<jint>(bitmapHandle->getAllocationByteCount());
 }
 
+static jobject Bitmap_nativeCopyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) {
+    LocalScopedBitmap bitmapHandle(bitmapPtr);
+    LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
+            "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig");
+    Bitmap& hwuiBitmap = bitmapHandle->bitmap();
+    SkBitmap src;
+    hwuiBitmap.getSkBitmap(&src);
+
+    SkBitmap result;
+    HeapAllocator allocator;
+    if (!src.copyTo(&result, hwuiBitmap.info().colorType(), &allocator)) {
+        doThrowRE(env, "Could not copy a hardware bitmap.");
+        return NULL;
+    }
+    return createBitmap(env, allocator.getStorageObjAndReset(), kBitmapCreateFlag_None);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 static jclass make_globalref(JNIEnv* env, const char classname[])
 {
@@ -1340,6 +1366,8 @@
     {   "nativeSameAs",             "(JJ)Z", (void*)Bitmap_sameAs },
     {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
     {   "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
+    {   "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;",
+        (void*)Bitmap_nativeCopyPreserveInternalConfig },
 };
 
 int register_android_graphics_Bitmap(JNIEnv* env)
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index b6db327..a259937 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -372,6 +372,16 @@
     }
 
     /**
+     * This is called by methods that want to throw an exception if the bitmap
+     * is {@link Config#HARDWARE}.
+     */
+    private void checkHardware(String errorMessage) {
+        if (getConfig() == Config.HARDWARE) {
+            throw new IllegalStateException(errorMessage);
+        }
+    }
+
+    /**
      * Common code for checking that x and y are >= 0
      *
      * @param x x coordinate to ensure is >= 0
@@ -512,8 +522,11 @@
      * <p>After this method returns, the current position of the buffer is
      * updated: the position is incremented by the number of elements written
      * in the buffer.</p>
+     * @throws IllegalStateException if the bitmap's config is {@link Config#HARDWARE}
      */
     public void copyPixelsToBuffer(Buffer dst) {
+        checkHardware("unable to copyPixelsToBuffer, "
+                + "pixel access is not supported on Config#HARDWARE bitmaps");
         int elements = dst.remaining();
         int shift;
         if (dst instanceof ByteBuffer) {
@@ -550,9 +563,11 @@
      * updated: the position is incremented by the number of elements read from
      * the buffer. If you need to read the bitmap from the buffer again you must
      * first rewind the buffer.</p>
+     * @throws IllegalStateException if the bitmap's config is {@link Config#HARDWARE}
      */
     public void copyPixelsFromBuffer(Buffer src) {
         checkRecycled("copyPixelsFromBuffer called on recycled bitmap");
+        checkHardware("unable to copyPixelsFromBuffer, Config#HARDWARE bitmaps are immutable");
 
         int elements = src.remaining();
         int shift;
@@ -753,6 +768,11 @@
             return source;
         }
 
+        boolean isHardware = source.getConfig() == Config.HARDWARE;
+        if (isHardware) {
+            source = nativeCopyPreserveInternalConfig(source.mNativePtr);
+        }
+
         int neww = width;
         int newh = height;
         Canvas canvas = new Canvas();
@@ -824,7 +844,9 @@
         canvas.setBitmap(bitmap);
         canvas.drawBitmap(source, srcR, dstR, paint);
         canvas.setBitmap(null);
-
+        if (isHardware) {
+            return bitmap.copy(Config.HARDWARE, false);
+        }
         return bitmap;
     }
 
@@ -1428,9 +1450,8 @@
     @ColorInt
     public int getPixel(int x, int y) {
         checkRecycled("Can't call getPixel() on a recycled bitmap");
-        if (getConfig() == Config.HARDWARE) {
-            throw new IllegalStateException("Can't access pixels in hardware Bitmaps");
-        }
+        checkHardware("unable to getPixel(), "
+                + "pixel access is not supported on Config#HARDWARE bitmaps");
         checkPixelAccess(x, y);
         return nativeGetPixel(mNativePtr, x, y);
     }
@@ -1462,9 +1483,8 @@
     public void getPixels(@ColorInt int[] pixels, int offset, int stride,
                           int x, int y, int width, int height) {
         checkRecycled("Can't call getPixels() on a recycled bitmap");
-        if (getConfig() == Config.HARDWARE) {
-            throw new IllegalStateException("Can't access pixels in hardware Bitmaps");
-        }
+        checkHardware("unable to getPixels(), "
+                + "pixel access is not supported on Config#HARDWARE bitmaps");
         if (width == 0 || height == 0) {
             return; // nothing to do
         }
@@ -1773,4 +1793,5 @@
     private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
     private static native void nativePrepareToDraw(long nativeBitmap);
     private static native int nativeGetAllocationByteCount(long nativeBitmap);
+    private static native Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap);
 }