diff --git a/api/current.txt b/api/current.txt index 12fb56cc21815..7bdff3f7c7942 100644 --- a/api/current.txt +++ b/api/current.txt @@ -14511,18 +14511,18 @@ package android.graphics.drawable { ctor public AnimatedImageDrawable(); method public void clearAnimationCallbacks(); method public void draw(android.graphics.Canvas); - method public int getLoopCount(); method public int getOpacity(); + method public int getRepeatCount(); method public final boolean isAutoMirrored(); method public boolean isRunning(); method public void registerAnimationCallback(android.graphics.drawable.Animatable2.AnimationCallback); method public void setAlpha(int); method public void setColorFilter(android.graphics.ColorFilter); - method public void setLoopCount(int); + method public void setRepeatCount(int); method public void start(); method public void stop(); method public boolean unregisterAnimationCallback(android.graphics.drawable.Animatable2.AnimationCallback); - field public static final int LOOP_INFINITE = -1; // 0xffffffff + field public static final int REPEAT_INFINITE = -1; // 0xffffffff } public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable { diff --git a/api/removed.txt b/api/removed.txt index 79c54fde54774..b8e2b98572cf1 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -173,6 +173,16 @@ package android.graphics { } +package android.graphics.drawable { + + public class AnimatedImageDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 { + method public deprecated int getLoopCount(int); + method public deprecated void setLoopCount(int); + field public static final deprecated int LOOP_INFINITE = -1; // 0xffffffff + } + +} + package android.hardware { public final class HardwareBuffer implements java.lang.AutoCloseable android.os.Parcelable { diff --git a/core/jni/android/graphics/AnimatedImageDrawable.cpp b/core/jni/android/graphics/AnimatedImageDrawable.cpp index 6fd4abf27baa3..d5cad029a934d 100644 --- a/core/jni/android/graphics/AnimatedImageDrawable.cpp +++ b/core/jni/android/graphics/AnimatedImageDrawable.cpp @@ -132,13 +132,13 @@ static jboolean AnimatedImageDrawable_nStop(JNIEnv* env, jobject /*clazz*/, jlon // Java's LOOP_INFINITE relies on this being the same. static_assert(SkCodec::kRepetitionCountInfinite == -1); -static jint AnimatedImageDrawable_nGetLoopCount(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) { +static jint AnimatedImageDrawable_nGetRepeatCount(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) { auto* drawable = reinterpret_cast(nativePtr); return drawable->getRepetitionCount(); } -static void AnimatedImageDrawable_nSetLoopCount(JNIEnv* env, jobject /*clazz*/, jlong nativePtr, - jint loopCount) { +static void AnimatedImageDrawable_nSetRepeatCount(JNIEnv* env, jobject /*clazz*/, jlong nativePtr, + jint loopCount) { auto* drawable = reinterpret_cast(nativePtr); drawable->setRepetitionCount(loopCount); } @@ -223,8 +223,8 @@ static const JNINativeMethod gAnimatedImageDrawableMethods[] = { { "nIsRunning", "(J)Z", (void*) AnimatedImageDrawable_nIsRunning }, { "nStart", "(J)Z", (void*) AnimatedImageDrawable_nStart }, { "nStop", "(J)Z", (void*) AnimatedImageDrawable_nStop }, - { "nGetLoopCount", "(J)I", (void*) AnimatedImageDrawable_nGetLoopCount }, - { "nSetLoopCount", "(JI)V", (void*) AnimatedImageDrawable_nSetLoopCount }, + { "nGetRepeatCount", "(J)I", (void*) AnimatedImageDrawable_nGetRepeatCount }, + { "nSetRepeatCount", "(JI)V", (void*) AnimatedImageDrawable_nSetRepeatCount }, { "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener }, { "nNativeByteSize", "(J)J", (void*) AnimatedImageDrawable_nNativeByteSize }, { "nMarkInvisible", "(J)V", (void*) AnimatedImageDrawable_nMarkInvisible }, diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index ffabdab41fad7..796030e6a418c 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -5954,6 +5954,11 @@ + + diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java index f70d6e1223dfd..2ea745c6f49e6 100644 --- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java @@ -77,6 +77,7 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { int[] mThemeAttrs = null; boolean mAutoMirrored = false; + int mRepeatCount = REPEAT_UNDEFINED; } private State mState; @@ -86,33 +87,87 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { private ColorFilter mColorFilter; /** - * Pass this to {@link #setLoopCount} to loop infinitely. + * Pass this to {@link #setRepeatCount} to repeat infinitely. * *

{@link Animatable2.AnimationCallback#onAnimationEnd} will never be * called unless there is an error.

*/ - public static final int LOOP_INFINITE = -1; + public static final int REPEAT_INFINITE = -1; + + /** @removed + * @deprecated Replaced with REPEAT_INFINITE to match other APIs. + */ + @java.lang.Deprecated + public static final int LOOP_INFINITE = REPEAT_INFINITE; + + private static final int REPEAT_UNDEFINED = -2; /** - * Specify the number of times to loop the animation. + * Specify the number of times to repeat the animation. * - *

By default, the loop count in the encoded data is respected.

+ *

By default, the repeat count in the encoded data is respected. If set + * to {@link #REPEAT_INFINITE}, the animation will repeat as long as it is + * displayed. If the value is {@code 0}, the animation will play once.

+ * + *

This call replaces the current repeat count. If the encoded data + * specified a repeat count of {@code 2} (meaning that + * {@link #getRepeatCount()} returns {@code 2}, the animation will play + * three times. Calling {@code setRepeatCount(1)} will result in playing only + * twice and {@link #getRepeatCount()} returning {@code 1}.

+ * + *

If the animation is already playing, the iterations that have already + * occurred count towards the new count. If the animation has already + * repeated the appropriate number of times (or more), it will finish its + * current iteration and then stop.

*/ - public void setLoopCount(int loopCount) { - if (mState.mNativePtr == 0) { - throw new IllegalStateException("called setLoopCount on empty AnimatedImageDrawable"); + public void setRepeatCount(@IntRange(from = REPEAT_INFINITE) int repeatCount) { + if (repeatCount < REPEAT_INFINITE) { + throw new IllegalArgumentException("invalid value passed to setRepeatCount" + + repeatCount); } - nSetLoopCount(mState.mNativePtr, loopCount); + if (mState.mRepeatCount != repeatCount) { + mState.mRepeatCount = repeatCount; + if (mState.mNativePtr != 0) { + nSetRepeatCount(mState.mNativePtr, repeatCount); + } + } + } + + /** @removed + * @deprecated Replaced with setRepeatCount to match other APIs. + */ + @java.lang.Deprecated + public void setLoopCount(int loopCount) { + setRepeatCount(loopCount); } /** - * Retrieve the number of times the animation will loop. + * Retrieve the number of times the animation will repeat. + * + *

By default, the repeat count in the encoded data is respected. If the + * value is {@link #REPEAT_INFINITE}, the animation will repeat as long as + * it is displayed. If the value is {@code 0}, it will play once.

+ * + *

Calling {@link #setRepeatCount} will make future calls to this method + * return the value passed to {@link #setRepeatCount}.

*/ - public int getLoopCount() { + public int getRepeatCount() { if (mState.mNativePtr == 0) { - throw new IllegalStateException("called getLoopCount on empty AnimatedImageDrawable"); + throw new IllegalStateException("called getRepeatCount on empty AnimatedImageDrawable"); } - return nGetLoopCount(mState.mNativePtr); + if (mState.mRepeatCount == REPEAT_UNDEFINED) { + mState.mRepeatCount = nGetRepeatCount(mState.mNativePtr); + + } + return mState.mRepeatCount; + } + + /** @removed + * @deprecated Replaced with getRepeatCount to match other APIs. + */ + @java.lang.Deprecated + public int getLoopCount(int loopCount) { + return getRepeatCount(); } /** @@ -176,12 +231,18 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { ": did not decode animated"); } + // This may have previously been set without a src if we were waiting for a + // theme. + final int repeatCount = mState.mRepeatCount; // Transfer the state of other to this one. other will be discarded. AnimatedImageDrawable other = (AnimatedImageDrawable) drawable; mState = other.mState; other.mState = null; mIntrinsicWidth = other.mIntrinsicWidth; mIntrinsicHeight = other.mIntrinsicHeight; + if (repeatCount != REPEAT_UNDEFINED) { + this.setRepeatCount(repeatCount); + } } mState.mThemeAttrs = a.extractThemeAttrs(); @@ -193,6 +254,12 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { mState.mAutoMirrored = a.getBoolean( R.styleable.AnimatedImageDrawable_autoMirrored, oldState.mAutoMirrored); + + int repeatCount = a.getInt( + R.styleable.AnimatedImageDrawable_repeatCount, REPEAT_UNDEFINED); + if (repeatCount != REPEAT_UNDEFINED) { + this.setRepeatCount(repeatCount); + } } /** @@ -271,7 +338,7 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { } @Override - public void setAlpha(@IntRange(from=0,to=255) int alpha) { + public void setAlpha(@IntRange(from = 0, to = 255) int alpha) { if (alpha < 0 || alpha > 255) { throw new IllegalArgumentException("Alpha must be between 0 and" + " 255! provided " + alpha); @@ -508,9 +575,9 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { @FastNative private static native boolean nStop(long nativePtr); @FastNative - private static native int nGetLoopCount(long nativePtr); + private static native int nGetRepeatCount(long nativePtr); @FastNative - private static native void nSetLoopCount(long nativePtr, int loopCount); + private static native void nSetRepeatCount(long nativePtr, int repeatCount); // Pass the drawable down to native so it can call onAnimationEnd. private static native void nSetOnAnimationEndListener(long nativePtr, @Nullable AnimatedImageDrawable drawable);