1532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang/* 2532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * Copyright (C) 2011 The Android Open Source Project 3532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * 4532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * Licensed under the Apache License, Version 2.0 (the "License"); 5532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * you may not use this file except in compliance with the License. 6532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * You may obtain a copy of the License at 7532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * 8532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * http://www.apache.org/licenses/LICENSE-2.0 9532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * 10532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * Unless required by applicable law or agreed to in writing, software 11532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * distributed under the License is distributed on an "AS IS" BASIS, 12532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * See the License for the specific language governing permissions and 14532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * limitations under the License. 15532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang */ 16532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 17532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Changpackage com.android.gallery3d.ui; 18532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 19532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Changimport com.android.gallery3d.R; 20532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 21532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Changimport android.content.Context; 22532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Changimport android.graphics.Rect; 23532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Changimport android.view.animation.AnimationUtils; 24532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Changimport android.view.animation.DecelerateInterpolator; 25532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Changimport android.view.animation.Interpolator; 26532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 27532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang// This is copied from android.widget.EdgeEffect with some small modifications: 28532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang// (1) Copy the images (overscroll_{edge|glow}.png) to local resources. 29532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang// (2) Use "GLCanvas" instead of "Canvas" for draw()'s parameter. 30532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang// (3) Use a private Drawable class (which inherits from ResourceTexture) 31532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang// instead of android.graphics.drawable.Drawable to hold the images. 32532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang// The private Drawable class is used to translate original Canvas calls to 33532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang// corresponding GLCanvas calls. 34532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 35532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang/** 36532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * This class performs the graphical effect used at the edges of scrollable widgets 37532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * when the user scrolls beyond the content bounds in 2D space. 38532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * 39532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * <p>EdgeEffect is stateful. Custom widgets using EdgeEffect should create an 40532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * instance for each edge that should show the effect, feed it input data using 41532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * the methods {@link #onAbsorb(int)}, {@link #onPull(float)}, and {@link #onRelease()}, 42532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * and draw the effect using {@link #draw(Canvas)} in the widget's overridden 43532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * {@link android.view.View#draw(Canvas)} method. If {@link #isFinished()} returns 44532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * false after drawing, the edge effect's animation is not yet complete and the widget 45532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * should schedule another drawing pass to continue the animation.</p> 46532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * 47532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * <p>When drawing, widgets should draw their main content and child views first, 48532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * usually by invoking <code>super.draw(canvas)</code> from an overridden <code>draw</code> 49532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * method. (This will invoke onDraw and dispatch drawing to child views as needed.) 50532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * The edge effect may then be drawn on top of the view's content using the 51532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * {@link #draw(Canvas)} method.</p> 52532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang */ 53532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Changpublic class EdgeEffect { 54532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final String TAG = "EdgeEffect"; 55532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 56532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Time it will take the effect to fully recede in ms 57532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final int RECEDE_TIME = 1000; 58532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 59532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Time it will take before a pulled glow begins receding in ms 60532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final int PULL_TIME = 167; 61532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 62532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Time it will take in ms for a pulled glow to decay to partial strength before release 63532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final int PULL_DECAY_TIME = 1000; 64532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 65532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final float MAX_ALPHA = 0.8f; 66532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final float HELD_EDGE_ALPHA = 0.7f; 67532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final float HELD_EDGE_SCALE_Y = 0.5f; 68532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final float HELD_GLOW_ALPHA = 0.5f; 69532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final float HELD_GLOW_SCALE_Y = 0.5f; 70532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 71532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final float MAX_GLOW_HEIGHT = 4.f; 72532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 73532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final float PULL_GLOW_BEGIN = 1.f; 74532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final float PULL_EDGE_BEGIN = 0.6f; 75532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 76532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Minimum velocity that will be absorbed 77532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final int MIN_VELOCITY = 100; 78532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 79532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final float EPSILON = 0.001f; 80532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 81532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private final Drawable mEdge; 82532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private final Drawable mGlow; 83532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private int mWidth; 84532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private int mHeight; 85532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private final int MIN_WIDTH = 300; 86532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private final int mMinWidth; 87532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 88532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private float mEdgeAlpha; 89532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private float mEdgeScaleY; 90532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private float mGlowAlpha; 91532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private float mGlowScaleY; 92532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 93532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private float mEdgeAlphaStart; 94532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private float mEdgeAlphaFinish; 95532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private float mEdgeScaleYStart; 96532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private float mEdgeScaleYFinish; 97532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private float mGlowAlphaStart; 98532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private float mGlowAlphaFinish; 99532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private float mGlowScaleYStart; 100532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private float mGlowScaleYFinish; 101532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 102532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private long mStartTime; 103532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private float mDuration; 104532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 105532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private final Interpolator mInterpolator; 106532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 107532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final int STATE_IDLE = 0; 108532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final int STATE_PULL = 1; 109532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final int STATE_ABSORB = 2; 110532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final int STATE_RECEDE = 3; 111532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final int STATE_PULL_DECAY = 4; 112532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 113532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // How much dragging should effect the height of the edge image. 114532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Number determined by user testing. 115532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final int PULL_DISTANCE_EDGE_FACTOR = 7; 116532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 117532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // How much dragging should effect the height of the glow image. 118532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Number determined by user testing. 119532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final int PULL_DISTANCE_GLOW_FACTOR = 7; 120532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 1.1f; 121532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 122532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final int VELOCITY_EDGE_FACTOR = 8; 123532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static final int VELOCITY_GLOW_FACTOR = 16; 124532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 125532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private int mState = STATE_IDLE; 126532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 127532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private float mPullDistance; 128532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 129532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang /** 130532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * Construct a new EdgeEffect with a theme appropriate for the provided context. 131532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * @param context Context used to provide theming and resource information for the EdgeEffect 132532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang */ 133532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang public EdgeEffect(Context context) { 134532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdge = new Drawable(context, R.drawable.overscroll_edge); 135532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlow = new Drawable(context, R.drawable.overscroll_glow); 136532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 137532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mMinWidth = (int) (context.getResources().getDisplayMetrics().density * MIN_WIDTH + 0.5f); 138532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mInterpolator = new DecelerateInterpolator(); 139532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 140532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 141532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang /** 142532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * Set the size of this edge effect in pixels. 143532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * 144532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * @param width Effect width in pixels 145532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * @param height Effect height in pixels 146532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang */ 147532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang public void setSize(int width, int height) { 148532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mWidth = width; 149532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mHeight = height; 150532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 151532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 152532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang /** 153532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * Reports if this EdgeEffect's animation is finished. If this method returns false 154532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * after a call to {@link #draw(Canvas)} the host widget should schedule another 155532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * drawing pass to continue the animation. 156532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * 157532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * @return true if animation is finished, false if drawing should continue on the next frame. 158532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang */ 159532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang public boolean isFinished() { 160532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang return mState == STATE_IDLE; 161532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 162532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 163532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang /** 164532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * Immediately finish the current animation. 165532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * After this call {@link #isFinished()} will return true. 166532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang */ 167532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang public void finish() { 168532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mState = STATE_IDLE; 169532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 170532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 171532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang /** 172532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * A view should call this when content is pulled away from an edge by the user. 173532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * This will update the state of the current visual effect and its associated animation. 174532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * The host view should always {@link android.view.View#invalidate()} after this 175532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * and draw the results accordingly. 176532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * 177532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to 178532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * 1.f (full length of the view) or negative values to express change 179532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * back toward the edge reached to initiate the effect. 180532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang */ 181532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang public void onPull(float deltaDistance) { 182532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang final long now = AnimationUtils.currentAnimationTimeMillis(); 183532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) { 184532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang return; 185532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 186532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang if (mState != STATE_PULL) { 187532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowScaleY = PULL_GLOW_BEGIN; 188532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 189532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mState = STATE_PULL; 190532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 191532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mStartTime = now; 192532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mDuration = PULL_TIME; 193532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 194532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mPullDistance += deltaDistance; 195532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang float distance = Math.abs(mPullDistance); 196532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 197532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeAlpha = mEdgeAlphaStart = Math.max(PULL_EDGE_BEGIN, Math.min(distance, MAX_ALPHA)); 198532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeScaleY = mEdgeScaleYStart = Math.max( 199532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang HELD_EDGE_SCALE_Y, Math.min(distance * PULL_DISTANCE_EDGE_FACTOR, 1.f)); 200532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 201532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA, 202532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowAlpha + 203532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang (Math.abs(deltaDistance) * PULL_DISTANCE_ALPHA_GLOW_FACTOR)); 204532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 205532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang float glowChange = Math.abs(deltaDistance); 206532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang if (deltaDistance > 0 && mPullDistance < 0) { 207532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang glowChange = -glowChange; 208532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 209532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang if (mPullDistance == 0) { 210532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowScaleY = 0; 211532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 212532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 213532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Do not allow glow to get larger than MAX_GLOW_HEIGHT. 214532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowScaleY = mGlowScaleYStart = Math.min(MAX_GLOW_HEIGHT, Math.max( 215532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 0, mGlowScaleY + glowChange * PULL_DISTANCE_GLOW_FACTOR)); 216532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 217532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeAlphaFinish = mEdgeAlpha; 218532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeScaleYFinish = mEdgeScaleY; 219532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowAlphaFinish = mGlowAlpha; 220532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowScaleYFinish = mGlowScaleY; 221532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 222532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 223532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang /** 224532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * Call when the object is released after being pulled. 225532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * This will begin the "decay" phase of the effect. After calling this method 226532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * the host view should {@link android.view.View#invalidate()} and thereby 227532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * draw the results accordingly. 228532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang */ 229532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang public void onRelease() { 230532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mPullDistance = 0; 231532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 232532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang if (mState != STATE_PULL && mState != STATE_PULL_DECAY) { 233532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang return; 234532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 235532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 236532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mState = STATE_RECEDE; 237532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeAlphaStart = mEdgeAlpha; 238532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeScaleYStart = mEdgeScaleY; 239532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowAlphaStart = mGlowAlpha; 240532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowScaleYStart = mGlowScaleY; 241532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 242532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeAlphaFinish = 0.f; 243532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeScaleYFinish = 0.f; 244532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowAlphaFinish = 0.f; 245532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowScaleYFinish = 0.f; 246532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 247532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mStartTime = AnimationUtils.currentAnimationTimeMillis(); 248532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mDuration = RECEDE_TIME; 249532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 250532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 251532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang /** 252532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * Call when the effect absorbs an impact at the given velocity. 253532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * Used when a fling reaches the scroll boundary. 254532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * 255532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * <p>When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller}, 256532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * the method <code>getCurrVelocity</code> will provide a reasonable approximation 257532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * to use here.</p> 258532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * 259532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * @param velocity Velocity at impact in pixels per second. 260532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang */ 261532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang public void onAbsorb(int velocity) { 262532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mState = STATE_ABSORB; 263532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang velocity = Math.max(MIN_VELOCITY, Math.abs(velocity)); 264532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 265532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mStartTime = AnimationUtils.currentAnimationTimeMillis(); 266532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mDuration = 0.1f + (velocity * 0.03f); 267532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 268532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // The edge should always be at least partially visible, regardless 269532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // of velocity. 270532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeAlphaStart = 0.f; 271532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeScaleY = mEdgeScaleYStart = 0.f; 272532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // The glow depends more on the velocity, and therefore starts out 273532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // nearly invisible. 274532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowAlphaStart = 0.5f; 275532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowScaleYStart = 0.f; 276532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 277532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Factor the velocity by 8. Testing on device shows this works best to 278532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // reflect the strength of the user's scrolling. 279532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeAlphaFinish = Math.max(0, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1)); 280532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Edge should never get larger than the size of its asset. 281532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeScaleYFinish = Math.max( 282532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang HELD_EDGE_SCALE_Y, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1.f)); 283532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 284532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Growth for the size of the glow should be quadratic to properly 285532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // respond 286532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // to a user's scrolling speed. The faster the scrolling speed, the more 287532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // intense the effect should be for both the size and the saturation. 288532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f); 289532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Alpha should change for the glow as well as size. 290532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowAlphaFinish = Math.max( 291532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA)); 292532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 293532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 294532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 295532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang /** 296532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * Draw into the provided canvas. Assumes that the canvas has been rotated 297532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * accordingly and the size has been set. The effect will be drawn the full 298532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * width of X=0 to X=width, beginning from Y=0 and extending to some factor < 299532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * 1.f of height. 300532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * 301532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * @param canvas Canvas to draw into 302532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * @return true if drawing should continue beyond this frame to continue the 303532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang * animation 304532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang */ 305532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang public boolean draw(GLCanvas canvas) { 306532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang update(); 307532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 308532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang final int edgeHeight = mEdge.getIntrinsicHeight(); 309532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang final int edgeWidth = mEdge.getIntrinsicWidth(); 310532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang final int glowHeight = mGlow.getIntrinsicHeight(); 311532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang final int glowWidth = mGlow.getIntrinsicWidth(); 312532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 313532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlow.setAlpha((int) (Math.max(0, Math.min(mGlowAlpha, 1)) * 255)); 314532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 315532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang int glowBottom = (int) Math.min( 316532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang glowHeight * mGlowScaleY * glowHeight/ glowWidth * 0.6f, 317532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang glowHeight * MAX_GLOW_HEIGHT); 318532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang if (mWidth < mMinWidth) { 319532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Center the glow and clip it. 320532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang int glowLeft = (mWidth - mMinWidth)/2; 321532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlow.setBounds(glowLeft, 0, mWidth - glowLeft, glowBottom); 322532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } else { 323532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Stretch the glow to fit. 324532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlow.setBounds(0, 0, mWidth, glowBottom); 325532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 326532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 327532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlow.draw(canvas); 328532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 329532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdge.setAlpha((int) (Math.max(0, Math.min(mEdgeAlpha, 1)) * 255)); 330532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 331532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang int edgeBottom = (int) (edgeHeight * mEdgeScaleY); 332532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang if (mWidth < mMinWidth) { 333532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Center the edge and clip it. 334532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang int edgeLeft = (mWidth - mMinWidth)/2; 335532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdge.setBounds(edgeLeft, 0, mWidth - edgeLeft, edgeBottom); 336532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } else { 337532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Stretch the edge to fit. 338532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdge.setBounds(0, 0, mWidth, edgeBottom); 339532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 340532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdge.draw(canvas); 341532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 342532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang return mState != STATE_IDLE; 343532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 344532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 345532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private void update() { 346532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang final long time = AnimationUtils.currentAnimationTimeMillis(); 347532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang final float t = Math.min((time - mStartTime) / mDuration, 1.f); 348532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 349532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang final float interp = mInterpolator.getInterpolation(t); 350532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 351532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeAlpha = mEdgeAlphaStart + (mEdgeAlphaFinish - mEdgeAlphaStart) * interp; 352532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeScaleY = mEdgeScaleYStart + (mEdgeScaleYFinish - mEdgeScaleYStart) * interp; 353532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp; 354532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp; 355532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 356532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang if (t >= 1.f - EPSILON) { 357532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang switch (mState) { 358532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang case STATE_ABSORB: 359532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mState = STATE_RECEDE; 360532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mStartTime = AnimationUtils.currentAnimationTimeMillis(); 361532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mDuration = RECEDE_TIME; 362532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 363532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeAlphaStart = mEdgeAlpha; 364532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeScaleYStart = mEdgeScaleY; 365532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowAlphaStart = mGlowAlpha; 366532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowScaleYStart = mGlowScaleY; 367532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 368532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // After absorb, the glow and edge should fade to nothing. 369532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeAlphaFinish = 0.f; 370532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeScaleYFinish = 0.f; 371532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowAlphaFinish = 0.f; 372532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowScaleYFinish = 0.f; 373532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang break; 374532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang case STATE_PULL: 375532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mState = STATE_PULL_DECAY; 376532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mStartTime = AnimationUtils.currentAnimationTimeMillis(); 377532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mDuration = PULL_DECAY_TIME; 378532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 379532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeAlphaStart = mEdgeAlpha; 380532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeScaleYStart = mEdgeScaleY; 381532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowAlphaStart = mGlowAlpha; 382532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowScaleYStart = mGlowScaleY; 383532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 384532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // After pull, the glow and edge should fade to nothing. 385532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeAlphaFinish = 0.f; 386532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeScaleYFinish = 0.f; 387532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowAlphaFinish = 0.f; 388532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mGlowScaleYFinish = 0.f; 389532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang break; 390532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang case STATE_PULL_DECAY: 391532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // When receding, we want edge to decrease more slowly 392532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // than the glow. 393532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang float factor = mGlowScaleYFinish != 0 ? 1 394532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang / (mGlowScaleYFinish * mGlowScaleYFinish) 395532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang : Float.MAX_VALUE; 396532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeScaleY = mEdgeScaleYStart + 397532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang (mEdgeScaleYFinish - mEdgeScaleYStart) * 398532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang interp * factor; 399532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mState = STATE_RECEDE; 400532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang break; 401532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang case STATE_RECEDE: 402532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mState = STATE_IDLE; 403532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang break; 404532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 405532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 406532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 407532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 408532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private static class Drawable extends ResourceTexture { 409532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private Rect mBounds = new Rect(); 410532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private int mAlpha = 255; 411532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 412532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang public Drawable(Context context, int resId) { 413532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang super(context, resId); 414532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 415532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 416532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang public int getIntrinsicWidth() { 417532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang return getWidth(); 418532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 419532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 420532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang public int getIntrinsicHeight() { 421532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang return getHeight(); 422532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 423532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 424532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang public void setBounds(int left, int top, int right, int bottom) { 425532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mBounds.set(left, top, right, bottom); 426532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 427532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 428532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang public void setAlpha(int alpha) { 429532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mAlpha = alpha; 430532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 431532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 432532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang public void draw(GLCanvas canvas) { 433532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang canvas.save(GLCanvas.SAVE_FLAG_ALPHA); 434532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang canvas.multiplyAlpha(mAlpha / 255.0f); 435532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang Rect b = mBounds; 436532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang draw(canvas, b.left, b.top, b.width(), b.height()); 437532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang canvas.restore(); 438532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 439532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 440532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang} 441