summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Viverette <alanv@google.com>2014-07-03 19:03:21 -0700
committerAlan Viverette <alanv@google.com>2014-07-03 19:03:21 -0700
commitf456b1f078639a422f966ef2e9376cbd5ae3d274 (patch)
treea1848ffd77785c40daeb286232ea12ba5f1d18e3
parent40d43b27b4f5fba75b040c24f95a170959811fd8 (diff)
downloadframeworks_base-f456b1f078639a422f966ef2e9376cbd5ae3d274.zip
frameworks_base-f456b1f078639a422f966ef2e9376cbd5ae3d274.tar.gz
frameworks_base-f456b1f078639a422f966ef2e9376cbd5ae3d274.tar.bz2
Update AnimatedStateListDrawable to work with Animatable drawables
BUG: 16016730 Change-Id: I6d02a1235c0aecd7e62f12226f3689372d043ddd
-rw-r--r--api/current.txt2
-rw-r--r--graphics/java/android/graphics/drawable/Animatable.java2
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java122
-rw-r--r--tests/VectorDrawableTest/AndroidManifest.xml9
-rw-r--r--tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable.xml47
-rw-r--r--tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedStateVectorDrawableTest.java52
6 files changed, 187 insertions, 47 deletions
diff --git a/api/current.txt b/api/current.txt
index fb598fd..3451f70 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11284,7 +11284,7 @@ package android.graphics.drawable {
public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
ctor public AnimatedStateListDrawable();
method public void addState(int[], android.graphics.drawable.Drawable, int);
- method public void addTransition(int, int, android.graphics.drawable.AnimationDrawable, boolean);
+ method public void addTransition(int, int, android.graphics.drawable.Drawable, boolean);
}
public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable {
diff --git a/graphics/java/android/graphics/drawable/Animatable.java b/graphics/java/android/graphics/drawable/Animatable.java
index 4edfad4..983d650 100644
--- a/graphics/java/android/graphics/drawable/Animatable.java
+++ b/graphics/java/android/graphics/drawable/Animatable.java
@@ -17,7 +17,7 @@
package android.graphics.drawable;
/**
- * Interface that drawables suporting animations should implement.
+ * Interface that drawables supporting animations should implement.
*/
public interface Animatable {
/**
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index e1dec9d..8483820 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -20,6 +20,8 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
@@ -82,17 +84,23 @@ public class AnimatedStateListDrawable extends StateListDrawable {
@Override
public boolean setVisible(boolean visible, boolean restart) {
+ // If we're relying on an Animatable transition, the super method
+ // will handle visibility changes.
final boolean changed = super.setVisible(visible, restart);
+
if (mAnim != null) {
if (visible) {
- if (changed || restart) {
- // TODO: Should this support restart?
- mAnim.end();
+ if (restart) {
+ mAnim.cancel();
+ mAnim.start();
+ } else if (changed && mAnim.isPaused()) {
+ mAnim.resume();
}
- } else {
- mAnim.end();
+ } else if (mAnim.isRunning()) {
+ mAnim.pause();
}
}
+
return changed;
}
@@ -100,14 +108,16 @@ public class AnimatedStateListDrawable extends StateListDrawable {
* Add a new drawable to the set of keyframes.
*
* @param stateSet An array of resource IDs to associate with the keyframe
- * @param drawable The drawable to show when in the specified state
+ * @param drawable The drawable to show when in the specified state, may not be null
* @param id The unique identifier for the keyframe
*/
- public void addState(int[] stateSet, Drawable drawable, int id) {
- if (drawable != null) {
- mState.addStateSet(stateSet, drawable, id);
- onStateChange(getState());
+ public void addState(@NonNull int[] stateSet, @NonNull Drawable drawable, int id) {
+ if (drawable == null) {
+ throw new IllegalArgumentException("Drawable must not be null");
}
+
+ mState.addStateSet(stateSet, drawable, id);
+ onStateChange(getState());
}
/**
@@ -115,11 +125,16 @@ public class AnimatedStateListDrawable extends StateListDrawable {
*
* @param fromId Unique identifier of the starting keyframe
* @param toId Unique identifier of the ending keyframe
- * @param anim An AnimationDrawable to use as a transition
+ * @param transition An animatable drawable to use as a transition, may not be null
* @param reversible Whether the transition can be reversed
*/
- public void addTransition(int fromId, int toId, AnimationDrawable anim, boolean reversible) {
- mState.addTransition(fromId, toId, anim, reversible);
+ public void addTransition(int fromId, int toId, @NonNull Drawable transition,
+ boolean reversible) {
+ if (transition == null) {
+ throw new IllegalArgumentException("Transition drawable must not be null");
+ }
+
+ mState.addTransition(fromId, toId, transition, reversible);
}
@Override
@@ -131,13 +146,16 @@ public class AnimatedStateListDrawable extends StateListDrawable {
protected boolean onStateChange(int[] stateSet) {
final int keyframeIndex = mState.indexOfKeyframe(stateSet);
if (keyframeIndex == getCurrentIndex()) {
+ // No transition needed.
return false;
}
+ // Attempt to find a valid transition to the keyframe.
if (selectTransition(keyframeIndex)) {
return true;
}
+ // No valid transition, attempt to jump directly to the keyframe.
if (selectDrawable(keyframeIndex)) {
return true;
}
@@ -146,9 +164,13 @@ public class AnimatedStateListDrawable extends StateListDrawable {
}
private boolean selectTransition(int toIndex) {
+ if (toIndex == mAnimToIndex) {
+ // Already animating to that keyframe.
+ return true;
+ }
+
if (mAnim != null) {
if (toIndex == mAnimToIndex) {
- // Already animating to that keyframe.
return true;
} else if (toIndex == mAnimFromIndex) {
// Reverse the current animation.
@@ -159,9 +181,14 @@ public class AnimatedStateListDrawable extends StateListDrawable {
}
// Changing animation, end the current animation.
- mAnim.end();
+ mAnim.cancel();
+ mAnim = null;
}
+ // Reset state.
+ mAnimFromIndex = -1;
+ mAnimToIndex = -1;
+
final AnimatedStateListState state = mState;
final int fromIndex = getCurrentIndex();
final int fromId = state.getKeyframeIdAt(fromIndex);
@@ -179,42 +206,54 @@ public class AnimatedStateListDrawable extends StateListDrawable {
}
final Drawable d = getCurrent();
- if (!(d instanceof AnimationDrawable)) {
- // Transition isn't an animation.
+ if (d instanceof AnimationDrawable) {
+ // We can support reverse() here.
+ final boolean reversed = mState.isTransitionReversed(fromId, toId);
+ mAnim = getAnimationDrawableAnimator((AnimationDrawable) d, reversed);
+ mAnim.start();
+ } else if (d instanceof Animatable) {
+ // Let the transition animate itself.
+ ((Animatable) d).start();
+ } else {
+ // We don't know how to animate this transition.
return false;
}
- final AnimationDrawable ad = (AnimationDrawable) d;
- final boolean reversed = mState.isTransitionReversed(fromId, toId);
+ mAnimFromIndex = fromIndex;
+ mAnimToIndex = toIndex;
+ return true;
+ }
+
+ private ObjectAnimator getAnimationDrawableAnimator(@NonNull AnimationDrawable ad,
+ boolean reversed) {
final int frameCount = ad.getNumberOfFrames();
final int fromFrame = reversed ? frameCount - 1 : 0;
final int toFrame = reversed ? 0 : frameCount - 1;
-
final FrameInterpolator interp = new FrameInterpolator(ad, reversed);
final ObjectAnimator anim = ObjectAnimator.ofInt(ad, "currentIndex", fromFrame, toFrame);
anim.setAutoCancel(true);
anim.setDuration(interp.getTotalDuration());
anim.addListener(mAnimListener);
anim.setInterpolator(interp);
- anim.start();
- mAnim = anim;
- mAnimFromIndex = fromIndex;
- mAnimToIndex = toIndex;
- return true;
+ return anim;
}
@Override
public void jumpToCurrentState() {
+ // If we're relying on an Animatable transition, the super method
+ // will handle jumping it to the current state.
super.jumpToCurrentState();
if (mAnim != null) {
mAnim.end();
+ mAnim = null;
}
}
@Override
- public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+ public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+ @NonNull AttributeSet attrs, @Nullable Theme theme)
throws XmlPullParserException, IOException {
final TypedArray a = r.obtainAttributes(attrs, R.styleable.AnimatedStateListDrawable);
@@ -260,7 +299,8 @@ public class AnimatedStateListDrawable extends StateListDrawable {
onStateChange(getState());
}
- private int parseTransition(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+ private int parseTransition(@NonNull Resources r, @NonNull XmlPullParser parser,
+ @NonNull AttributeSet attrs, @Nullable Theme theme)
throws XmlPullParserException, IOException {
int drawableRes = 0;
int fromId = 0;
@@ -304,19 +344,11 @@ public class AnimatedStateListDrawable extends StateListDrawable {
dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
}
- final AnimationDrawable anim;
- if (dr instanceof AnimationDrawable) {
- anim = (AnimationDrawable) dr;
- } else {
- throw new XmlPullParserException(parser.getPositionDescription()
- + ": <transition> tag requires a 'drawable' attribute or "
- + "child tag defining a drawable of type <animation>");
- }
-
- return mState.addTransition(fromId, toId, anim, reversible);
+ return mState.addTransition(fromId, toId, dr, reversible);
}
- private int parseItem(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+ private int parseItem(@NonNull Resources r, @NonNull XmlPullParser parser,
+ @NonNull AttributeSet attrs, @Nullable Theme theme)
throws XmlPullParserException, IOException {
int drawableRes = 0;
int keyframeId = 0;
@@ -390,8 +422,8 @@ public class AnimatedStateListDrawable extends StateListDrawable {
final LongSparseLongArray mTransitions;
final SparseIntArray mStateIds;
- AnimatedStateListState(AnimatedStateListState orig, AnimatedStateListDrawable owner,
- Resources res) {
+ AnimatedStateListState(@Nullable AnimatedStateListState orig,
+ @NonNull AnimatedStateListDrawable owner, @Nullable Resources res) {
super(orig, owner, res);
if (orig != null) {
@@ -403,7 +435,7 @@ public class AnimatedStateListDrawable extends StateListDrawable {
}
}
- int addTransition(int fromId, int toId, AnimationDrawable anim, boolean reversible) {
+ int addTransition(int fromId, int toId, @NonNull Drawable anim, boolean reversible) {
final int pos = super.addChild(anim);
final long keyFromTo = generateTransitionKey(fromId, toId);
mTransitions.append(keyFromTo, pos);
@@ -416,13 +448,13 @@ public class AnimatedStateListDrawable extends StateListDrawable {
return addChild(anim);
}
- int addStateSet(int[] stateSet, Drawable drawable, int id) {
+ int addStateSet(@NonNull int[] stateSet, @NonNull Drawable drawable, int id) {
final int index = super.addStateSet(stateSet, drawable);
mStateIds.put(index, id);
return index;
}
- int indexOfKeyframe(int[] stateSet) {
+ int indexOfKeyframe(@NonNull int[] stateSet) {
final int index = super.indexOfStateSet(stateSet);
if (index >= 0) {
return index;
@@ -460,13 +492,13 @@ public class AnimatedStateListDrawable extends StateListDrawable {
}
}
- void setConstantState(AnimatedStateListState state) {
+ void setConstantState(@NonNull AnimatedStateListState state) {
super.setConstantState(state);
mState = state;
}
- private AnimatedStateListDrawable(AnimatedStateListState state, Resources res) {
+ private AnimatedStateListDrawable(@Nullable AnimatedStateListState state, @Nullable Resources res) {
super(null);
final AnimatedStateListState newState = new AnimatedStateListState(state, this, res);
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
index 613660c13..56fa0a9 100644
--- a/tests/VectorDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -71,6 +71,15 @@
</intent-filter>
</activity>
<activity
+ android:name="AnimatedStateVectorDrawableTest"
+ android:label="AnimatedStateList and AnimatedVectorDrawable" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="com.android.test.dynamic.TEST" />
+ </intent-filter>
+ </activity>
+ <activity
android:name="VectorDrawable01"
android:label="VectorTest1" >
<intent-filter>
diff --git a/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable.xml b/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable.xml
new file mode 100644
index 0000000..30fb1b8
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable.xml
@@ -0,0 +1,47 @@
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/on" android:state_checked="true"
+ android:drawable="@drawable/vector_drawable12" />
+ <item android:id="@+id/off"
+ android:drawable="@drawable/vector_drawable12" />
+ <transition android:fromId="@+id/off" android:toId="@+id/on">
+ <animated-vector android:drawable="@drawable/vector_drawable12">
+ <target
+ android:name="pie1"
+ android:animation="@anim/trim_path_animation01" />
+ <target
+ android:name="v"
+ android:animation="@anim/trim_path_animation02" />
+ <target
+ android:name="v"
+ android:animation="@anim/trim_path_animation05" />
+ <target
+ android:name="rotationGroup"
+ android:animation="@anim/trim_path_animation03" />
+ <target
+ android:name="rotationGroup3"
+ android:animation="@anim/trim_path_animation03" />
+ <target
+ android:name="rotationGroupBlue"
+ android:animation="@anim/trim_path_animation03" />
+ <target
+ android:name="rotationGroup"
+ android:animation="@anim/trim_path_animation04" />
+ </animated-vector>
+ </transition>
+</animated-selector>
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedStateVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedStateVectorDrawableTest.java
new file mode 100644
index 0000000..0ae0136
--- /dev/null
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedStateVectorDrawableTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.test.dynamic;
+
+import android.app.Activity;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.GridLayout;
+import android.widget.ScrollView;
+
+public class AnimatedStateVectorDrawableTest extends Activity {
+ private static final String LOGCAT = "AnimatedStateVectorDrawableTest";
+
+ protected int[] icon = {
+ R.drawable.state_animation_vector_drawable
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ ScrollView scrollView = new ScrollView(this);
+ GridLayout container = new GridLayout(this);
+ scrollView.addView(container);
+ container.setColumnCount(1);
+
+ for (int i = 0; i < icon.length; i++) {
+ CheckBox button = new CheckBox(this);
+ button.setWidth(400);
+ button.setHeight(400);
+ button.setBackgroundResource(icon[i]);
+ container.addView(button);
+ }
+
+ setContentView(scrollView);
+ }
+}