resolved conflicts for merge of 9c9958ca to mnc-dev-plus-aosp

Change-Id: Id3203fa190b351074a56195b8dfea4f6cee9a767
diff --git a/framesequence/jni/FrameSequence_gif.cpp b/framesequence/jni/FrameSequence_gif.cpp
index 2188c53..f8d37f4 100644
--- a/framesequence/jni/FrameSequence_gif.cpp
+++ b/framesequence/jni/FrameSequence_gif.cpp
@@ -23,11 +23,6 @@
 
 #define GIF_DEBUG 0
 
-// These constants are chosen to imitate common browser behavior
-// Note that 0 delay is undefined behavior in the gif standard
-static const long MIN_DELAY_MS = 20;
-static const long DEFAULT_DELAY_MS = 100;
-
 static int streamReader(GifFileType* fileType, GifByteType* out, int size) {
     Stream* stream = (Stream*) fileType->UserData;
     return (int) stream->read(out, size);
@@ -38,11 +33,7 @@
 }
 
 static long getDelayMs(GraphicsControlBlock& gcb) {
-    long delayMs = gcb.DelayTime * 10;
-    if (delayMs < MIN_DELAY_MS) {
-        return DEFAULT_DELAY_MS;
-    }
-    return delayMs;
+    return gcb.DelayTime * 10;
 }
 
 static bool willBeCleared(const GraphicsControlBlock& gcb) {
diff --git a/framesequence/src/android/support/rastermill/FrameSequenceDrawable.java b/framesequence/src/android/support/rastermill/FrameSequenceDrawable.java
index 2228b1d..c4ce0ce 100644
--- a/framesequence/src/android/support/rastermill/FrameSequenceDrawable.java
+++ b/framesequence/src/android/support/rastermill/FrameSequenceDrawable.java
@@ -17,11 +17,14 @@
 package android.support.rastermill;
 
 import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
@@ -30,6 +33,15 @@
 import android.os.SystemClock;
 
 public class FrameSequenceDrawable extends Drawable implements Animatable, Runnable {
+    /**
+     * These constants are chosen to imitate common browser behavior for WebP/GIF.
+     * If other decoders are added, this behavior should be moved into the WebP/GIF decoders.
+     *
+     * Note that 0 delay is undefined behavior in the GIF standard.
+     */
+    private static final long MIN_DELAY_MS = 20;
+    private static final long DEFAULT_DELAY_MS = 100;
+
     private static final Object sLock = new Object();
     private static HandlerThread sDecodingThread;
     private static Handler sDecodingThreadHandler;
@@ -116,7 +128,10 @@
     private final FrameSequence.State mFrameSequenceState;
 
     private final Paint mPaint;
-    private final Rect mSrcRect;
+    private BitmapShader mFrontBitmapShader;
+    private BitmapShader mBackBitmapShader;
+     private final Rect mSrcRect;
+    private boolean mCircleMaskEnabled;
 
     //Protects the fields below
     private final Object mLock = new Object();
@@ -161,6 +176,10 @@
             int lastFrame = nextFrame - 2;
             long invalidateTimeMs = mFrameSequenceState.getFrame(nextFrame, bitmap, lastFrame);
 
+            if (invalidateTimeMs < MIN_DELAY_MS) {
+                invalidateTimeMs = DEFAULT_DELAY_MS;
+            }
+
             boolean schedule = false;
             Bitmap bitmapToRelease = null;
             synchronized (mLock) {
@@ -225,6 +244,11 @@
         mPaint = new Paint();
         mPaint.setFilterBitmap(true);
 
+        mFrontBitmapShader
+            = new BitmapShader(mFrontBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+        mBackBitmapShader
+            = new BitmapShader(mBackBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+
         mLastSwap = 0;
 
         mNextFrameToDecode = -1;
@@ -232,6 +256,18 @@
         initializeDecodingThread();
     }
 
+    /**
+     * Pass true to mask the shape of the animated drawing content to a circle.
+     *
+     * <p> The masking circle will be the largest circle contained in the Drawable's bounds.
+     * Masking is done with BitmapShader, incurring minimal additional draw cost.
+     */
+    public final void setCircleMaskEnabled(boolean circleMaskEnabled) {
+        mCircleMaskEnabled = circleMaskEnabled;
+        // Anti alias only necessary when using circular mask
+        mPaint.setAntiAlias(circleMaskEnabled);
+    }
+
     private void checkDestroyedLocked() {
         if (mDestroyed) {
             throw new IllegalStateException("Cannot perform operation on recycled drawable");
@@ -306,6 +342,10 @@
                 mBackBitmap = mFrontBitmap;
                 mFrontBitmap = tmp;
 
+                BitmapShader tmpShader = mBackBitmapShader;
+                mBackBitmapShader = mFrontBitmapShader;
+                mFrontBitmapShader = tmpShader;
+
                 mLastSwap = SystemClock.uptimeMillis();
 
                 boolean continueLooping = true;
@@ -325,7 +365,17 @@
             }
         }
 
-        canvas.drawBitmap(mFrontBitmap, mSrcRect, getBounds(), mPaint);
+        if (mCircleMaskEnabled) {
+            Rect bounds = getBounds();
+            mPaint.setShader(mFrontBitmapShader);
+            float width = bounds.width();
+            float height = bounds.height();
+            float circleRadius = (Math.min(width, height)) / 2f;
+            canvas.drawCircle(width / 2f, height / 2f, circleRadius, mPaint);
+        } else {
+            mPaint.setShader(null);
+            canvas.drawBitmap(mFrontBitmap, mSrcRect, getBounds(), mPaint);
+        }
     }
 
     private void scheduleDecodeLocked() {
@@ -379,6 +429,7 @@
     public void unscheduleSelf(Runnable what) {
         synchronized (mLock) {
             mNextFrameToDecode = -1;
+            mState = 0;
         }
         super.unscheduleSelf(what);
     }