diff --git a/api/current.txt b/api/current.txt index 957dcb4074ac6..94413d7b500a7 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1061,6 +1061,7 @@ package android { field public static final int startDelay = 16843746; // 0x10103e2 field public static final int startOffset = 16843198; // 0x10101be field public static final deprecated int startYear = 16843132; // 0x101017c + field public static final int stateListAnimator = 16843860; // 0x1010454 field public static final int stateNotNeeded = 16842774; // 0x1010016 field public static final int state_above_anchor = 16842922; // 0x10100aa field public static final int state_accelerated = 16843547; // 0x101031b @@ -2788,6 +2789,7 @@ package android.animation { public class AnimatorInflater { ctor public AnimatorInflater(); method public static android.animation.Animator loadAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException; + method public static android.animation.StateListAnimator loadStateListAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException; } public abstract class AnimatorListenerAdapter implements android.animation.Animator.AnimatorListener android.animation.Animator.AnimatorPauseListener { @@ -2984,6 +2986,12 @@ package android.animation { method public android.graphics.Rect evaluate(float, android.graphics.Rect, android.graphics.Rect); } + public class StateListAnimator { + ctor public StateListAnimator(); + method public void addState(int[], android.animation.Animator); + method public void jumpToCurrentState(); + } + public class TimeAnimator extends android.animation.ValueAnimator { ctor public TimeAnimator(); method public void setTimeListener(android.animation.TimeAnimator.TimeListener); @@ -30834,6 +30842,7 @@ package android.view { method public final int getScrollY(); method public java.lang.String getSharedElementName(); method public int getSolidColor(); + method public android.animation.StateListAnimator getStateListAnimator(); method protected int getSuggestedMinimumHeight(); method protected int getSuggestedMinimumWidth(); method public int getSystemUiVisibility(); @@ -31098,6 +31107,7 @@ package android.view { method public void setSelected(boolean); method public void setSharedElementName(java.lang.String); method public void setSoundEffectsEnabled(boolean); + method public void setStateListAnimator(android.animation.StateListAnimator); method public void setSystemUiVisibility(int); method public void setTag(java.lang.Object); method public void setTag(int, java.lang.Object); diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java index 20236aaaa674e..933135db37258 100644 --- a/core/java/android/animation/AnimatorInflater.java +++ b/core/java/android/animation/AnimatorInflater.java @@ -21,6 +21,7 @@ import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.content.res.Resources.NotFoundException; import android.util.AttributeSet; +import android.util.StateSet; import android.util.TypedValue; import android.util.Xml; import android.view.animation.AnimationUtils; @@ -87,9 +88,86 @@ public class AnimatorInflater { } } + public static StateListAnimator loadStateListAnimator(Context context, int id) + throws NotFoundException { + XmlResourceParser parser = null; + try { + parser = context.getResources().getAnimation(id); + return createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser)); + } catch (XmlPullParserException ex) { + Resources.NotFoundException rnf = + new Resources.NotFoundException( + "Can't load state list animator resource ID #0x" + + Integer.toHexString(id) + ); + rnf.initCause(ex); + throw rnf; + } catch (IOException ex) { + Resources.NotFoundException rnf = + new Resources.NotFoundException( + "Can't load state list animator resource ID #0x" + + Integer.toHexString(id) + ); + rnf.initCause(ex); + throw rnf; + } finally { + if (parser != null) { + parser.close(); + } + } + } + + private static StateListAnimator createStateListAnimatorFromXml(Context context, + XmlPullParser parser, AttributeSet attributeSet) + throws IOException, XmlPullParserException { + int type; + StateListAnimator stateListAnimator = new StateListAnimator(); + + while (true) { + type = parser.next(); + switch (type) { + case XmlPullParser.END_DOCUMENT: + case XmlPullParser.END_TAG: + return stateListAnimator; + + case XmlPullParser.START_TAG: + // parse item + Animator animator = null; + if ("item".equals(parser.getName())) { + int attributeCount = parser.getAttributeCount(); + int[] states = new int[attributeCount]; + int stateIndex = 0; + for (int i = 0; i < attributeCount; i++) { + int attrName = attributeSet.getAttributeNameResource(i); + if (attrName == com.android.internal.R.attr.animation) { + animator = loadAnimator(context, + attributeSet.getAttributeResourceValue(i, 0)); + } else { + states[stateIndex++] = + attributeSet.getAttributeBooleanValue(i, false) ? + attrName : -attrName; + } + + } + if (animator == null) { + animator = createAnimatorFromXml(context, parser); + } + + if (animator == null) { + throw new Resources.NotFoundException( + "animation state item must have a valid animation"); + } + stateListAnimator + .addState(StateSet.trimStateSet(states, stateIndex), animator); + + } + break; + } + } + } + private static Animator createAnimatorFromXml(Context c, XmlPullParser parser) throws XmlPullParserException, IOException { - return createAnimatorFromXml(c, parser, Xml.asAttributeSet(parser), null, 0); } diff --git a/core/java/android/animation/StateListAnimator.java b/core/java/android/animation/StateListAnimator.java new file mode 100644 index 0000000000000..bc4843d671b79 --- /dev/null +++ b/core/java/android/animation/StateListAnimator.java @@ -0,0 +1,209 @@ +/* + * 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 android.animation; + +import android.util.StateSet; +import android.view.View; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; + +/** + * Lets you define a number of Animators that will run on the attached View depending on the View's + * drawable state. + *
+ * It can be defined in an XML file with the
+ * This causes the animation to assign the end value(s) to the View.
+ */
+ public void jumpToCurrentState() {
+ if (mRunningAnimator != null) {
+ mRunningAnimator.end();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static class Tuple {
+
+ final int[] mSpecs;
+
+ final Animator mAnimator;
+
+ private Tuple(int[] specs, Animator animator) {
+ mSpecs = specs;
+ mAnimator = animator;
+ }
+
+ /**
+ * @hide
+ */
+ public int[] getSpecs() {
+ return mSpecs;
+ }
+
+ /**
+ * @hide
+ */
+ public Animator getAnimator() {
+ return mAnimator;
+ }
+ }
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d8fcfc516bf53..bef96b11d9b4a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,7 +16,9 @@
package android.view;
+import android.animation.AnimatorInflater;
import android.animation.RevealAnimator;
+import android.animation.StateListAnimator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -667,6 +669,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* @attr ref android.R.styleable#View_scrollbarTrackVertical
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
+ * @attr ref android.R.styleable#View_stateListAnimator
* @attr ref android.R.styleable#View_sharedElementName
* @attr ref android.R.styleable#View_soundEffectsEnabled
* @attr ref android.R.styleable#View_tag
@@ -3257,6 +3260,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
private Outline mOutline;
+ /**
+ * Animator that automatically runs based on state changes.
+ */
+ private StateListAnimator mStateListAnimator;
+
/**
* When this view has focus and the next focus is {@link #FOCUS_LEFT},
* the user may specify which view to go to next.
@@ -3995,6 +4003,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
case R.styleable.View_nestedScrollingEnabled:
setNestedScrollingEnabled(a.getBoolean(attr, false));
break;
+ case R.styleable.View_stateListAnimator:
+ setStateListAnimator(AnimatorInflater.loadStateListAnimator(context,
+ a.getResourceId(attr, 0)));
+ break;
}
}
@@ -10619,6 +10631,40 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
startRadius, endRadius, true);
}
+ /**
+ * Returns the current StateListAnimator if exists.
+ *
+ * @return StateListAnimator or null if it does not exists
+ * @see #setStateListAnimator(android.animation.StateListAnimator)
+ */
+ public StateListAnimator getStateListAnimator() {
+ return mStateListAnimator;
+ }
+
+ /**
+ * Attaches the provided StateListAnimator to this View.
+ *
+ * Any previously attached StateListAnimator will be detached.
+ *
+ * @param stateListAnimator The StateListAnimator to update the view
+ * @see {@link android.animation.StateListAnimator}
+ */
+ public void setStateListAnimator(StateListAnimator stateListAnimator) {
+ if (mStateListAnimator == stateListAnimator) {
+ return;
+ }
+ if (mStateListAnimator != null) {
+ mStateListAnimator.setTarget(null);
+ }
+ mStateListAnimator = stateListAnimator;
+ if (stateListAnimator != null) {
+ stateListAnimator.setTarget(this);
+ if (isAttachedToWindow()) {
+ stateListAnimator.setState(getDrawableState());
+ }
+ }
+ }
+
/**
* Sets the outline of the view, which defines the shape of the shadow it
* casts.
@@ -12835,7 +12881,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
destroyLayer(false);
cleanupDraw();
-
mCurrentAnimation = null;
}
@@ -15489,9 +15534,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* This function is called whenever the state of the view changes in such
* a way that it impacts the state of drawables being shown.
- *
- * Be sure to call through to the superclass when overriding this
- * function.
+ *
+ * If the View has a StateListAnimator, it will also be called to run necessary state
+ * change animations.
+ *
+ * Be sure to call through to the superclass when overriding this function.
*
* @see Drawable#setState(int[])
*/
@@ -15500,6 +15547,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (d != null && d.isStateful()) {
d.setState(getDrawableState());
}
+
+ if (mStateListAnimator != null) {
+ mStateListAnimator.setState(getDrawableState());
+ }
}
/**
@@ -15644,11 +15695,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()}
* on all Drawable objects associated with this view.
+ *
+ * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator
+ * attached to this view.
*/
public void jumpDrawablesToCurrentState() {
if (mBackground != null) {
mBackground.jumpToCurrentState();
}
+ if (mStateListAnimator != null) {
+ mStateListAnimator.jumpToCurrentState();
+ }
}
/**
diff --git a/core/res/res/anim/button_state_list_anim_quantum.xml b/core/res/res/anim/button_state_list_anim_quantum.xml
new file mode 100644
index 0000000000000..01989a4edaf16
--- /dev/null
+++ b/core/res/res/anim/button_state_list_anim_quantum.xml
@@ -0,0 +1,34 @@
+
+
+<selector> element.
+ * Each State Animator is defined in a nested <item> element.
+ *
+ * @attr ref android.R.styleable#DrawableStates_state_focused
+ * @attr ref android.R.styleable#DrawableStates_state_window_focused
+ * @attr ref android.R.styleable#DrawableStates_state_enabled
+ * @attr ref android.R.styleable#DrawableStates_state_checkable
+ * @attr ref android.R.styleable#DrawableStates_state_checked
+ * @attr ref android.R.styleable#DrawableStates_state_selected
+ * @attr ref android.R.styleable#DrawableStates_state_activated
+ * @attr ref android.R.styleable#DrawableStates_state_active
+ * @attr ref android.R.styleable#DrawableStates_state_single
+ * @attr ref android.R.styleable#DrawableStates_state_first
+ * @attr ref android.R.styleable#DrawableStates_state_middle
+ * @attr ref android.R.styleable#DrawableStates_state_last
+ * @attr ref android.R.styleable#DrawableStates_state_pressed
+ * @attr ref android.R.styleable#StateListAnimatorItem_animation
+ */
+public class StateListAnimator {
+
+ private final ArrayList