diff options
Diffstat (limited to 'src/org/cyanogenmod/theme/chooser/IconTransitionDrawable.java')
-rw-r--r-- | src/org/cyanogenmod/theme/chooser/IconTransitionDrawable.java | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/src/org/cyanogenmod/theme/chooser/IconTransitionDrawable.java b/src/org/cyanogenmod/theme/chooser/IconTransitionDrawable.java new file mode 100644 index 0000000..96547f3 --- /dev/null +++ b/src/org/cyanogenmod/theme/chooser/IconTransitionDrawable.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2016 Cyanogen, Inc. + * Copyright (C) 2016 The CyanogenMod 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 org.cyanogenmod.theme.chooser; + +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.os.SystemClock; + +/** + * An extension of LayerDrawables that is intended to cross-fade between + * the first and second layer. To start the transition, call {@link #startTransition(int)}. To + * display just the first layer, call {@link #resetTransition()}. + * <p> + * It can be defined in an XML file with the <code><transition></code> element. + * Each Drawable in the transition is defined in a nested <code><item></code>. For more + * information, see the guide to <a + * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> + * + * @attr ref android.R.styleable#LayerDrawableItem_left + * @attr ref android.R.styleable#LayerDrawableItem_top + * @attr ref android.R.styleable#LayerDrawableItem_right + * @attr ref android.R.styleable#LayerDrawableItem_bottom + * @attr ref android.R.styleable#LayerDrawableItem_drawable + * @attr ref android.R.styleable#LayerDrawableItem_id + * + */ +public class IconTransitionDrawable extends LayerDrawable { + + /** + * A transition is about to start. + */ + private static final int TRANSITION_STARTING = 0; + + /** + * The transition has started and the animation is in progress + */ + private static final int TRANSITION_RUNNING = 1; + + /** + * No transition will be applied + */ + private static final int TRANSITION_NONE = 2; + + /** + * The current state of the transition. One of {@link #TRANSITION_STARTING}, + * {@link #TRANSITION_RUNNING} and {@link #TRANSITION_NONE} + */ + private int mTransitionState = TRANSITION_NONE; + + private long mStartTimeMillis; + private int mFrom; + private int mTo; + private int mDuration; + private int mAlpha = 0; + private float mFromScale; + private float mToScale; + + /** + * Create a new transition drawable with the specified list of layers. At least + * 2 layers are required for this drawable to work properly. + */ + public IconTransitionDrawable(Drawable[] layers) { + super(layers); + } + + /** + * Begin the second layer on top of the first layer. + * + * @param durationMillis The length of the transition in milliseconds + */ + public void startTransition(int durationMillis) { + mFrom = 0; + mTo = 255; + mAlpha = 0; + mFromScale = 0f; + mToScale = 1.0f; + mDuration = durationMillis; + mTransitionState = TRANSITION_STARTING; + invalidateSelf(); + } + + /** + * Show only the first layer. + */ + public void resetTransition() { + mAlpha = 0; + mTransitionState = TRANSITION_NONE; + invalidateSelf(); + } + + @Override + public void draw(Canvas canvas) { + boolean done = true; + float scale = 0f; + + switch (mTransitionState) { + case TRANSITION_STARTING: + mStartTimeMillis = SystemClock.uptimeMillis(); + done = false; + mTransitionState = TRANSITION_RUNNING; + break; + + case TRANSITION_RUNNING: + if (mStartTimeMillis >= 0) { + float normalized = (float) + (SystemClock.uptimeMillis() - mStartTimeMillis) / mDuration; + done = normalized >= 1.0f; + normalized = Math.min(normalized, 1.0f); + mAlpha = (int) (mFrom + (mTo - mFrom) * normalized); + scale = mFromScale + (mToScale - mFromScale) * normalized; + } + break; + } + + final int alpha = mAlpha; + + if (done) { + // the setAlpha() calls below trigger invalidation and redraw. If we're done, just draw + // the appropriate drawable[s] and return + if (alpha == 0) { + getDrawable(0).draw(canvas); + } + if (alpha == 0xFF) { + getDrawable(1).draw(canvas); + + } + return; + } + + Drawable d; + d = getDrawable(0); + d.setAlpha(255 - alpha); + int cx = getIntrinsicWidth() / 2; + int cy = getIntrinsicHeight() / 2; + canvas.save(); + canvas.scale(1.0f - scale, 1.0f - scale, cx, cy); + d.draw(canvas); + canvas.restore(); + d.setAlpha(0xFF); + + if (alpha > 0) { + d = getDrawable(1); + d.setAlpha(alpha); + canvas.save(); + canvas.scale(scale, scale, cx, cy); + d.draw(canvas); + canvas.restore(); + d.setAlpha(0xFF); + } + + if (!done) { + invalidateSelf(); + } + } +} |