diff options
Diffstat (limited to 'graphics')
3 files changed, 201 insertions, 15 deletions
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 7b2d9d7..baa9d62 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -423,6 +423,13 @@ public abstract class Drawable { } /** + * If this Drawable does transition animations between states, ask that + * it immediately jump to the current state and skip any active animations. + */ + public void jumpToCurrentState() { + } + + /** * @return The current drawable that will be used by this drawable. For simple drawables, this * is just the drawable itself. For drawables that change state like * {@link StateListDrawable} and {@link LevelListDrawable} this will be the child drawable diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 124d907..e55a746 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -21,6 +21,7 @@ import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.os.SystemClock; /** * A helper class that contains several {@link Drawable}s and selects which one to use. @@ -28,6 +29,8 @@ import android.graphics.Rect; * You can subclass it to create your own DrawableContainers or directly use one its child classes. */ public class DrawableContainer extends Drawable implements Drawable.Callback { + private static final boolean DEBUG = false; + private static final String TAG = "DrawableContainer"; /** * To be proper, we should have a getter for dither (and alpha, etc.) @@ -48,6 +51,12 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { private int mCurIndex = -1; private boolean mMutated; + // Animations. + private Runnable mAnimationRunnable; + private long mEnterAnimationEnd; + private long mExitAnimationEnd; + private Drawable mLastDrawable; + // overrides from Drawable @Override @@ -55,6 +64,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (mCurrDrawable != null) { mCurrDrawable.draw(canvas); } + if (mLastDrawable != null) { + mLastDrawable.draw(canvas); + } } @Override @@ -83,7 +95,11 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (mAlpha != alpha) { mAlpha = alpha; if (mCurrDrawable != null) { - mCurrDrawable.setAlpha(alpha); + if (mEnterAnimationEnd == 0) { + mCurrDrawable.setAlpha(alpha); + } else { + animate(false); + } } } } @@ -108,8 +124,29 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } } + /** + * Change the global fade duration when a new drawable is entering + * the scene. + * @param ms The amount of time to fade in milliseconds. + */ + public void setEnterFadeDuration(int ms) { + mDrawableContainerState.mEnterFadeDuration = ms; + } + + /** + * Change the global fade duration when a new drawable is leaving + * the scene. + * @param ms The amount of time to fade in milliseconds. + */ + public void setExitFadeDuration(int ms) { + mDrawableContainerState.mExitFadeDuration = ms; + } + @Override protected void onBoundsChange(Rect bounds) { + if (mLastDrawable != null) { + mLastDrawable.setBounds(bounds); + } if (mCurrDrawable != null) { mCurrDrawable.setBounds(bounds); } @@ -121,7 +158,34 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } @Override + public void jumpToCurrentState() { + boolean changed = false; + if (mLastDrawable != null) { + mLastDrawable.jumpToCurrentState(); + mLastDrawable = null; + changed = true; + } + if (mCurrDrawable != null) { + mCurrDrawable.jumpToCurrentState(); + } + if (mExitAnimationEnd != 0) { + mExitAnimationEnd = 0; + changed = true; + } + if (mEnterAnimationEnd != 0) { + mEnterAnimationEnd = 0; + changed = true; + } + if (changed) { + invalidateSelf(); + } + } + + @Override protected boolean onStateChange(int[] state) { + if (mLastDrawable != null) { + return mLastDrawable.setState(state); + } if (mCurrDrawable != null) { return mCurrDrawable.setState(state); } @@ -130,6 +194,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { @Override protected boolean onLevelChange(int level) { + if (mLastDrawable != null) { + return mLastDrawable.setLevel(level); + } if (mCurrDrawable != null) { return mCurrDrawable.setLevel(level); } @@ -168,22 +235,19 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return mCurrDrawable != null ? mCurrDrawable.getMinimumHeight() : 0; } - public void invalidateDrawable(Drawable who) - { + public void invalidateDrawable(Drawable who) { if (who == mCurrDrawable && mCallback != null) { mCallback.invalidateDrawable(this); } } - public void scheduleDrawable(Drawable who, Runnable what, long when) - { + public void scheduleDrawable(Drawable who, Runnable what, long when) { if (who == mCurrDrawable && mCallback != null) { mCallback.scheduleDrawable(this, what, when); } } - public void unscheduleDrawable(Drawable who, Runnable what) - { + public void unscheduleDrawable(Drawable who, Runnable what) { if (who == mCurrDrawable && mCallback != null) { mCallback.unscheduleDrawable(this, what); } @@ -192,6 +256,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { @Override public boolean setVisible(boolean visible, boolean restart) { boolean changed = super.setVisible(visible, restart); + if (mLastDrawable != null) { + mLastDrawable.setVisible(visible, restart); + } if (mCurrDrawable != null) { mCurrDrawable.setVisible(visible, restart); } @@ -208,16 +275,39 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (idx == mCurIndex) { return false; } - if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) { - Drawable d = mDrawableContainerState.mDrawables[idx]; + + final long now = SystemClock.uptimeMillis(); + + if (DEBUG) android.util.Log.i(TAG, toString() + " from " + mCurIndex + " to " + idx + + ": exit=" + mDrawableContainerState.mExitFadeDuration + + " enter=" + mDrawableContainerState.mEnterFadeDuration); + + if (mDrawableContainerState.mExitFadeDuration > 0) { + if (mLastDrawable != null) { + mLastDrawable.setVisible(false, false); + } if (mCurrDrawable != null) { - mCurrDrawable.setVisible(false, false); + mLastDrawable = mCurrDrawable; + mExitAnimationEnd = now + mDrawableContainerState.mExitFadeDuration; + } else { + mLastDrawable = null; + mExitAnimationEnd = 0; } + } else if (mCurrDrawable != null) { + mCurrDrawable.setVisible(false, false); + } + + if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) { + Drawable d = mDrawableContainerState.mDrawables[idx]; mCurrDrawable = d; mCurIndex = idx; if (d != null) { + if (mDrawableContainerState.mEnterFadeDuration > 0) { + mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration; + } else { + d.setAlpha(mAlpha); + } d.setVisible(isVisible(), true); - d.setAlpha(mAlpha); d.setDither(mDrawableContainerState.mDither); d.setColorFilter(mColorFilter); d.setState(getState()); @@ -225,16 +315,72 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { d.setBounds(getBounds()); } } else { - if (mCurrDrawable != null) { - mCurrDrawable.setVisible(false, false); - } mCurrDrawable = null; mCurIndex = -1; } + + if (mEnterAnimationEnd != 0 || mExitAnimationEnd != 0) { + if (mAnimationRunnable == null) { + mAnimationRunnable = new Runnable() { + @Override public void run() { + animate(true); + invalidateSelf(); + } + }; + } else { + unscheduleSelf(mAnimationRunnable); + } + // Compute first frame and schedule next animation. + animate(true); + } + invalidateSelf(); + return true; } + void animate(boolean schedule) { + final long now = SystemClock.uptimeMillis(); + boolean animating = false; + if (mCurrDrawable != null) { + if (mEnterAnimationEnd != 0) { + if (mEnterAnimationEnd <= now) { + mCurrDrawable.setAlpha(mAlpha); + mEnterAnimationEnd = 0; + } else { + int animAlpha = (int)((mEnterAnimationEnd-now)*255) + / mDrawableContainerState.mEnterFadeDuration; + if (DEBUG) android.util.Log.i(TAG, toString() + " cur alpha " + animAlpha); + mCurrDrawable.setAlpha(((255-animAlpha)*mAlpha)/255); + animating = true; + } + } + } else { + mEnterAnimationEnd = 0; + } + if (mLastDrawable != null) { + if (mExitAnimationEnd != 0) { + if (mExitAnimationEnd <= now) { + mLastDrawable.setVisible(false, false); + mLastDrawable = null; + mExitAnimationEnd = 0; + } else { + int animAlpha = (int)((mExitAnimationEnd-now)*255) + / mDrawableContainerState.mExitFadeDuration; + if (DEBUG) android.util.Log.i(TAG, toString() + " last alpha " + animAlpha); + mLastDrawable.setAlpha((animAlpha*mAlpha)/255); + animating = true; + } + } + } else { + mExitAnimationEnd = 0; + } + + if (schedule && animating) { + scheduleSelf(mAnimationRunnable, now + 1000/60); + } + } + @Override public Drawable getCurrent() { return mCurrDrawable; @@ -300,6 +446,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { boolean mDither = DEFAULT_DITHER; + int mEnterFadeDuration; + int mExitFadeDuration; + DrawableContainerState(DrawableContainerState orig, DrawableContainer owner, Resources res) { mOwner = owner; @@ -340,6 +489,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mDither = orig.mDither; + mEnterFadeDuration = orig.mEnterFadeDuration; + mExitFadeDuration = orig.mExitFadeDuration; + } else { mDrawables = new Drawable[10]; mNumChildren = 0; @@ -476,6 +628,22 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } } + public final void setEnterFadeDuration(int duration) { + mEnterFadeDuration = duration; + } + + public final int getEnterFadeDuration() { + return mEnterFadeDuration; + } + + public final void setExitFadeDuration(int duration) { + mExitFadeDuration = duration; + } + + public final int getExitFadeDuration() { + return mExitFadeDuration; + } + public final int getOpacity() { if (mHaveOpacity) { return mOpacity; diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index 239be40..384ca81 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -20,6 +20,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.util.Arrays; import android.content.res.Resources; import android.content.res.TypedArray; @@ -44,6 +45,7 @@ import android.util.StateSet; * @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 @@ -52,6 +54,9 @@ import android.util.StateSet; * @attr ref android.R.styleable#DrawableStates_state_pressed */ public class StateListDrawable extends DrawableContainer { + private static final boolean DEBUG = false; + private static final String TAG = "StateListDrawable"; + /** * To be proper, we should have a getter for dither (and alpha, etc.) * so that proxy classes like this can save/restore their delegates' @@ -93,6 +98,8 @@ public class StateListDrawable extends DrawableContainer { @Override protected boolean onStateChange(int[] stateSet) { int idx = mStateListState.indexOfStateSet(stateSet); + if (DEBUG) android.util.Log.i(TAG, "onStateChange " + this + " states " + + Arrays.toString(stateSet) + " found " + idx); if (idx < 0) { idx = mStateListState.indexOfStateSet(StateSet.WILD_CARD); } @@ -117,6 +124,10 @@ public class StateListDrawable extends DrawableContainer { com.android.internal.R.styleable.StateListDrawable_variablePadding, false)); mStateListState.setConstantSize(a.getBoolean( com.android.internal.R.styleable.StateListDrawable_constantSize, false)); + mStateListState.setEnterFadeDuration(a.getInt( + com.android.internal.R.styleable.StateListDrawable_enterFadeDuration, 0)); + mStateListState.setExitFadeDuration(a.getInt( + com.android.internal.R.styleable.StateListDrawable_exitFadeDuration, 0)); setDither(a.getBoolean(com.android.internal.R.styleable.StateListDrawable_dither, DEFAULT_DITHER)); @@ -251,7 +262,7 @@ public class StateListDrawable extends DrawableContainer { } static final class StateListState extends DrawableContainerState { - private int[][] mStateSets; + int[][] mStateSets; StateListState(StateListState orig, StateListDrawable owner, Resources res) { super(orig, owner, res); |