Merge "Add BitmapFactory.Options.inMutable to load mutable bitmaps." into honeycomb
diff --git a/api/current.xml b/api/current.xml
index aa3c90b..d98fd04 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -77107,6 +77107,16 @@
  visibility="public"
 >
 </field>
+<field name="inMutable"
+ type="boolean"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="inPreferQualityOverSpeed"
  type="boolean"
  transient="false"
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index dac748d..e47d91c 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -23,6 +23,7 @@
 jfieldID gOptions_justBoundsFieldID;
 jfieldID gOptions_sampleSizeFieldID;
 jfieldID gOptions_configFieldID;
+jfieldID gOptions_mutableFieldID;
 jfieldID gOptions_ditherFieldID;
 jfieldID gOptions_purgeableFieldID;
 jfieldID gOptions_shareableFieldID;
@@ -179,6 +180,7 @@
     SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode;
     SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
     bool doDither = true;
+    bool isMutable = false;
     bool isPurgeable = forcePurgeable ||
                         (allowPurgeable && optionsPurgeable(env, options));
     bool preferQualityOverSpeed = false;
@@ -196,6 +198,7 @@
         
         jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
         prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
+        isMutable = env->GetBooleanField(options, gOptions_mutableFieldID);
         doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
         preferQualityOverSpeed = env->GetBooleanField(options,
                 gOptions_preferQualityOverSpeedFieldID);
@@ -306,15 +309,19 @@
         // already have a pixelref installed.
         pr = bitmap->pixelRef();
     }
-    // promise we will never change our pixels (great for sharing and pictures)
-    pr->setImmutable();
+
+    if (!isMutable) {
+        // promise we will never change our pixels (great for sharing and pictures)
+        pr->setImmutable();
+    }
 
     if (javaBitmap != NULL) {
         // If a java bitmap was passed in for reuse, pass it back
         return javaBitmap;
     }
     // now create the java bitmap
-    return GraphicsJNI::createBitmap(env, bitmap, javaAllocator.getStorageObj(), false, ninePatchChunk);
+    return GraphicsJNI::createBitmap(env, bitmap, javaAllocator.getStorageObj(),
+            isMutable, ninePatchChunk);
 }
 
 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz,
@@ -572,6 +579,7 @@
     gOptions_sampleSizeFieldID = getFieldIDCheck(env, gOptions_class, "inSampleSize", "I");
     gOptions_configFieldID = getFieldIDCheck(env, gOptions_class, "inPreferredConfig",
             "Landroid/graphics/Bitmap$Config;");
+    gOptions_mutableFieldID = getFieldIDCheck(env, gOptions_class, "inMutable", "Z");
     gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z");
     gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z");
     gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "Z");
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index a8efd00..e67ceed 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -53,6 +53,7 @@
      */
     public byte[] mBuffer;
 
+    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources
     private final BitmapFinalizer mFinalizer;
 
     private final boolean mIsMutable;
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 8309f7a..dd6bf19 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -64,6 +64,14 @@
         public Bitmap inBitmap;
 
         /**
+         * If set, decode methods will always return a mutable Bitmap instead of
+         * an immutable one. This can be used for instance to programmatically apply
+         * effects to a Bitmap loaded through BitmapFactory.
+         */
+        @SuppressWarnings({"UnusedDeclaration"}) // used in native code
+        public boolean inMutable;
+
+        /**
          * If set to true, the decoder will return null (no bitmap), but
          * the out... fields will still be set, allowing the caller to query
          * the bitmap without having to allocate the memory for its pixels.
@@ -523,7 +531,7 @@
             }
             bm.setDensity(targetDensity);
         }
-        
+
         return bm;
     }
     
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsActivity.java
index 4054353..607a173 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsActivity.java
@@ -25,6 +25,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
 import android.view.animation.Animation;
@@ -61,7 +62,15 @@
 
             mBitmap1 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
             mBitmap2 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset2);
+            
+            Log.d("Bitmap", "mBitmap1.isMutable() = " + mBitmap1.isMutable());
+            Log.d("Bitmap", "mBitmap2.isMutable() = " + mBitmap2.isMutable());
 
+            BitmapFactory.Options opts = new BitmapFactory.Options();
+            opts.inMutable = true;
+            Bitmap bitmap = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1, opts);
+            Log.d("Bitmap", "bitmap.isMutable() = " + bitmap.isMutable());
+            
             mBitmapPaint = new Paint();
             mDstIn = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
         }