Catch exceptions during decode and abort.

bug:27561875

Change-Id: I461567316fcee2e425e040c8120dfc5f0c03fba9
diff --git a/framesequence/jni/FrameSequenceJNI.cpp b/framesequence/jni/FrameSequenceJNI.cpp
index dfc51ec..c701f03 100644
--- a/framesequence/jni/FrameSequenceJNI.cpp
+++ b/framesequence/jni/FrameSequenceJNI.cpp
@@ -108,6 +108,12 @@
     delete frameSequenceState;
 }
 
+void throwIae(JNIEnv* env, const char* message, int errorCode) {
+    char buf[256];
+    snprintf(buf, sizeof(buf), "%s, error %d", message, errorCode);
+    jniThrowException(env, ILLEGAL_STATE_EXEPTION, buf);
+}
+
 static jlong JNICALL nativeGetFrame(
         JNIEnv* env, jobject clazz, jlong frameSequenceStateLong, jint frameNr,
         jobject bitmap, jint previousFrameNr) {
@@ -116,16 +122,14 @@
     int ret;
     AndroidBitmapInfo info;
     void* pixels;
-    if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
 
-        jniThrowException(env, ILLEGAL_STATE_EXEPTION,
-                "Couldn't get info from Bitmap ");
+    if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
+        throwIae(env, "Couldn't get info from Bitmap", ret);
         return 0;
     }
 
     if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
-        jniThrowException(env, ILLEGAL_STATE_EXEPTION,
-                "Bitmap pixels couldn't be locked");
+        throwIae(env, "Bitmap pixels couldn't be locked", ret);
         return 0;
     }
 
diff --git a/framesequence/src/android/support/rastermill/FrameSequenceDrawable.java b/framesequence/src/android/support/rastermill/FrameSequenceDrawable.java
index c4ce0ce..a1b7020 100644
--- a/framesequence/src/android/support/rastermill/FrameSequenceDrawable.java
+++ b/framesequence/src/android/support/rastermill/FrameSequenceDrawable.java
@@ -31,8 +31,10 @@
 import android.os.HandlerThread;
 import android.os.Process;
 import android.os.SystemClock;
+import android.util.Log;
 
 public class FrameSequenceDrawable extends Drawable implements Animatable, Runnable {
+    private static final String TAG = "FrameSequence";
     /**
      * 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.
@@ -174,7 +176,15 @@
                 mState = STATE_DECODING;
             }
             int lastFrame = nextFrame - 2;
-            long invalidateTimeMs = mFrameSequenceState.getFrame(nextFrame, bitmap, lastFrame);
+            boolean exceptionDuringDecode = false;
+            long invalidateTimeMs = 0;
+            try {
+                invalidateTimeMs = mFrameSequenceState.getFrame(nextFrame, bitmap, lastFrame);
+            } catch(Exception e) {
+                // Exception during decode: continue, but delay next frame indefinitely.
+                Log.e(TAG, "exception during decode: " + e);
+                exceptionDuringDecode = true;
+            }
 
             if (invalidateTimeMs < MIN_DELAY_MS) {
                 invalidateTimeMs = DEFAULT_DELAY_MS;
@@ -188,7 +198,7 @@
                     mBackBitmap = null;
                 } else if (mNextFrameToDecode >= 0 && mState == STATE_DECODING) {
                     schedule = true;
-                    mNextSwap = invalidateTimeMs + mLastSwap;
+                    mNextSwap = exceptionDuringDecode ? Long.MAX_VALUE : invalidateTimeMs + mLastSwap;
                     mState = STATE_WAITING_TO_SWAP;
                 }
             }