1637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell/* 2637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * Copyright (C) 2010 The Android Open Source Project 3637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * 4637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * Licensed under the Apache License, Version 2.0 (the "License"); 5637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * you may not use this file except in compliance with the License. 6637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * You may obtain a copy of the License at 7637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * 8637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * http://www.apache.org/licenses/LICENSE-2.0 9637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * 10637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * Unless required by applicable law or agreed to in writing, software 11637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * distributed under the License is distributed on an "AS IS" BASIS, 12637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * See the License for the specific language governing permissions and 14637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * limitations under the License. 15637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell */ 16637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 17637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powellpackage android.widget; 18637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 199d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guyimport android.graphics.Rect; 2089935e41c593a599e8955388b27fb926e60e5e94Adam Powellimport com.android.internal.R; 2189935e41c593a599e8955388b27fb926e60e5e94Adam Powell 224e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereiraimport android.content.Context; 2389935e41c593a599e8955388b27fb926e60e5e94Adam Powellimport android.content.res.Resources; 24637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powellimport android.graphics.Canvas; 25637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powellimport android.graphics.drawable.Drawable; 26637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powellimport android.view.animation.AnimationUtils; 27637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powellimport android.view.animation.DecelerateInterpolator; 28637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powellimport android.view.animation.Interpolator; 29637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 30637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell/** 3189935e41c593a599e8955388b27fb926e60e5e94Adam Powell * This class performs the graphical effect used at the edges of scrollable widgets 3289935e41c593a599e8955388b27fb926e60e5e94Adam Powell * when the user scrolls beyond the content bounds in 2D space. 3389935e41c593a599e8955388b27fb926e60e5e94Adam Powell * 3489935e41c593a599e8955388b27fb926e60e5e94Adam Powell * <p>EdgeEffect is stateful. Custom widgets using EdgeEffect should create an 3589935e41c593a599e8955388b27fb926e60e5e94Adam Powell * instance for each edge that should show the effect, feed it input data using 3689935e41c593a599e8955388b27fb926e60e5e94Adam Powell * the methods {@link #onAbsorb(int)}, {@link #onPull(float)}, and {@link #onRelease()}, 3789935e41c593a599e8955388b27fb926e60e5e94Adam Powell * and draw the effect using {@link #draw(Canvas)} in the widget's overridden 3889935e41c593a599e8955388b27fb926e60e5e94Adam Powell * {@link android.view.View#draw(Canvas)} method. If {@link #isFinished()} returns 3989935e41c593a599e8955388b27fb926e60e5e94Adam Powell * false after drawing, the edge effect's animation is not yet complete and the widget 4089935e41c593a599e8955388b27fb926e60e5e94Adam Powell * should schedule another drawing pass to continue the animation.</p> 4189935e41c593a599e8955388b27fb926e60e5e94Adam Powell * 4289935e41c593a599e8955388b27fb926e60e5e94Adam Powell * <p>When drawing, widgets should draw their main content and child views first, 4389935e41c593a599e8955388b27fb926e60e5e94Adam Powell * usually by invoking <code>super.draw(canvas)</code> from an overridden <code>draw</code> 4489935e41c593a599e8955388b27fb926e60e5e94Adam Powell * method. (This will invoke onDraw and dispatch drawing to child views as needed.) 4589935e41c593a599e8955388b27fb926e60e5e94Adam Powell * The edge effect may then be drawn on top of the view's content using the 4689935e41c593a599e8955388b27fb926e60e5e94Adam Powell * {@link #draw(Canvas)} method.</p> 47637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell */ 4889935e41c593a599e8955388b27fb926e60e5e94Adam Powellpublic class EdgeEffect { 499d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy @SuppressWarnings("UnusedDeclaration") 5089935e41c593a599e8955388b27fb926e60e5e94Adam Powell private static final String TAG = "EdgeEffect"; 51637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 52637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // Time it will take the effect to fully recede in ms 53637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static final int RECEDE_TIME = 1000; 54637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 5589935e41c593a599e8955388b27fb926e60e5e94Adam Powell // Time it will take before a pulled glow begins receding in ms 56637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static final int PULL_TIME = 167; 57637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 5889935e41c593a599e8955388b27fb926e60e5e94Adam Powell // Time it will take in ms for a pulled glow to decay to partial strength before release 59637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static final int PULL_DECAY_TIME = 1000; 60637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 61539ee8716b4f81260bab2e9f3dc5d88d81c99985Adam Powell private static final float MAX_ALPHA = 1.f; 62637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static final float HELD_EDGE_SCALE_Y = 0.5f; 63637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 644e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira private static final float MAX_GLOW_HEIGHT = 4.f; 65637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 66637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static final float PULL_GLOW_BEGIN = 1.f; 67637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static final float PULL_EDGE_BEGIN = 0.6f; 68637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 69637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // Minimum velocity that will be absorbed 70637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static final int MIN_VELOCITY = 100; 712d1acfc9f7e1502a5dbb8cab54289d6fbb880467Christian Robertson // Maximum velocity, clamps at this value 722d1acfc9f7e1502a5dbb8cab54289d6fbb880467Christian Robertson private static final int MAX_VELOCITY = 10000; 73637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 74637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static final float EPSILON = 0.001f; 75637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 76637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private final Drawable mEdge; 77637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private final Drawable mGlow; 78637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private int mWidth; 79637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private int mHeight; 809d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy private int mX; 819d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy private int mY; 829d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy private static final int MIN_WIDTH = 300; 834e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira private final int mMinWidth; 84637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 85637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private float mEdgeAlpha; 86637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private float mEdgeScaleY; 87637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private float mGlowAlpha; 88637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private float mGlowScaleY; 89637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 90637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private float mEdgeAlphaStart; 91637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private float mEdgeAlphaFinish; 92637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private float mEdgeScaleYStart; 93637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private float mEdgeScaleYFinish; 94637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private float mGlowAlphaStart; 95637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private float mGlowAlphaFinish; 96637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private float mGlowScaleYStart; 97637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private float mGlowScaleYFinish; 98637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 99637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private long mStartTime; 100637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private float mDuration; 101637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 102637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private final Interpolator mInterpolator; 103637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 104637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static final int STATE_IDLE = 0; 105637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static final int STATE_PULL = 1; 106637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static final int STATE_ABSORB = 2; 107637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static final int STATE_RECEDE = 3; 108637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static final int STATE_PULL_DECAY = 4; 109637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 110637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // How much dragging should effect the height of the edge image. 111637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // Number determined by user testing. 1124e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira private static final int PULL_DISTANCE_EDGE_FACTOR = 7; 113637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 114637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // How much dragging should effect the height of the glow image. 115637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // Number determined by user testing. 1164e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira private static final int PULL_DISTANCE_GLOW_FACTOR = 7; 1174e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 1.1f; 118637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 119637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static final int VELOCITY_EDGE_FACTOR = 8; 1202d1acfc9f7e1502a5dbb8cab54289d6fbb880467Christian Robertson private static final int VELOCITY_GLOW_FACTOR = 12; 121637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 122637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private int mState = STATE_IDLE; 123637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 124637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private float mPullDistance; 1259d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy 1269d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy private final Rect mBounds = new Rect(); 127637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 128a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy private final int mEdgeHeight; 129a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy private final int mGlowHeight; 130a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy private final int mGlowWidth; 131a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy private final int mMaxEffectHeight; 132a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy 13389935e41c593a599e8955388b27fb926e60e5e94Adam Powell /** 13489935e41c593a599e8955388b27fb926e60e5e94Adam Powell * Construct a new EdgeEffect with a theme appropriate for the provided context. 13589935e41c593a599e8955388b27fb926e60e5e94Adam Powell * @param context Context used to provide theming and resource information for the EdgeEffect 13689935e41c593a599e8955388b27fb926e60e5e94Adam Powell */ 13789935e41c593a599e8955388b27fb926e60e5e94Adam Powell public EdgeEffect(Context context) { 13889935e41c593a599e8955388b27fb926e60e5e94Adam Powell final Resources res = context.getResources(); 13989935e41c593a599e8955388b27fb926e60e5e94Adam Powell mEdge = res.getDrawable(R.drawable.overscroll_edge); 14089935e41c593a599e8955388b27fb926e60e5e94Adam Powell mGlow = res.getDrawable(R.drawable.overscroll_glow); 141637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 142a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy mEdgeHeight = mEdge.getIntrinsicHeight(); 143a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy mGlowHeight = mGlow.getIntrinsicHeight(); 144a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy mGlowWidth = mGlow.getIntrinsicWidth(); 145a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy 146a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy mMaxEffectHeight = (int) (Math.min( 147a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy mGlowHeight * MAX_GLOW_HEIGHT * mGlowHeight / mGlowWidth * 0.6f, 148a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy mGlowHeight * MAX_GLOW_HEIGHT) + 0.5f); 149a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy 1501373a8eb581fe3c8e9a036e69042015f98a7e346Christopher Tate mMinWidth = (int) (res.getDisplayMetrics().density * MIN_WIDTH + 0.5f); 151637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mInterpolator = new DecelerateInterpolator(); 152637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 153637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 15489935e41c593a599e8955388b27fb926e60e5e94Adam Powell /** 15589935e41c593a599e8955388b27fb926e60e5e94Adam Powell * Set the size of this edge effect in pixels. 15689935e41c593a599e8955388b27fb926e60e5e94Adam Powell * 15789935e41c593a599e8955388b27fb926e60e5e94Adam Powell * @param width Effect width in pixels 15889935e41c593a599e8955388b27fb926e60e5e94Adam Powell * @param height Effect height in pixels 15989935e41c593a599e8955388b27fb926e60e5e94Adam Powell */ 160637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell public void setSize(int width, int height) { 161637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mWidth = width; 162637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mHeight = height; 163637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 164637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 16589935e41c593a599e8955388b27fb926e60e5e94Adam Powell /** 1669d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy * Set the position of this edge effect in pixels. This position is 167a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy * only used by {@link #getBounds(boolean)}. 1689d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy * 1699d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy * @param x The position of the edge effect on the X axis 1709d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy * @param y The position of the edge effect on the Y axis 1719d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy */ 1729d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy void setPosition(int x, int y) { 1739d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy mX = x; 1749d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy mY = y; 1759d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy } 1769d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy 1779d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy /** 17889935e41c593a599e8955388b27fb926e60e5e94Adam Powell * Reports if this EdgeEffect's animation is finished. If this method returns false 17989935e41c593a599e8955388b27fb926e60e5e94Adam Powell * after a call to {@link #draw(Canvas)} the host widget should schedule another 18089935e41c593a599e8955388b27fb926e60e5e94Adam Powell * drawing pass to continue the animation. 18189935e41c593a599e8955388b27fb926e60e5e94Adam Powell * 18289935e41c593a599e8955388b27fb926e60e5e94Adam Powell * @return true if animation is finished, false if drawing should continue on the next frame. 18389935e41c593a599e8955388b27fb926e60e5e94Adam Powell */ 184637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell public boolean isFinished() { 185637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell return mState == STATE_IDLE; 186637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 187637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 18889935e41c593a599e8955388b27fb926e60e5e94Adam Powell /** 18989935e41c593a599e8955388b27fb926e60e5e94Adam Powell * Immediately finish the current animation. 19089935e41c593a599e8955388b27fb926e60e5e94Adam Powell * After this call {@link #isFinished()} will return true. 19189935e41c593a599e8955388b27fb926e60e5e94Adam Powell */ 192637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell public void finish() { 193637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mState = STATE_IDLE; 194637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 195637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 196637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell /** 19789935e41c593a599e8955388b27fb926e60e5e94Adam Powell * A view should call this when content is pulled away from an edge by the user. 19889935e41c593a599e8955388b27fb926e60e5e94Adam Powell * This will update the state of the current visual effect and its associated animation. 19989935e41c593a599e8955388b27fb926e60e5e94Adam Powell * The host view should always {@link android.view.View#invalidate()} after this 20089935e41c593a599e8955388b27fb926e60e5e94Adam Powell * and draw the results accordingly. 201637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * 20289935e41c593a599e8955388b27fb926e60e5e94Adam Powell * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to 20389935e41c593a599e8955388b27fb926e60e5e94Adam Powell * 1.f (full length of the view) or negative values to express change 20489935e41c593a599e8955388b27fb926e60e5e94Adam Powell * back toward the edge reached to initiate the effect. 205637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell */ 206637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell public void onPull(float deltaDistance) { 207637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell final long now = AnimationUtils.currentAnimationTimeMillis(); 208637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) { 209637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell return; 210637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 211637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell if (mState != STATE_PULL) { 212637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowScaleY = PULL_GLOW_BEGIN; 213637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 214637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mState = STATE_PULL; 215637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 216637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mStartTime = now; 217637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mDuration = PULL_TIME; 218637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 219637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mPullDistance += deltaDistance; 220637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell float distance = Math.abs(mPullDistance); 221637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 222637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeAlpha = mEdgeAlphaStart = Math.max(PULL_EDGE_BEGIN, Math.min(distance, MAX_ALPHA)); 223637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeScaleY = mEdgeScaleYStart = Math.max( 224637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell HELD_EDGE_SCALE_Y, Math.min(distance * PULL_DISTANCE_EDGE_FACTOR, 1.f)); 225637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 226637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA, 227637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowAlpha + 228637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell (Math.abs(deltaDistance) * PULL_DISTANCE_ALPHA_GLOW_FACTOR)); 229637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 230637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell float glowChange = Math.abs(deltaDistance); 231637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell if (deltaDistance > 0 && mPullDistance < 0) { 232637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell glowChange = -glowChange; 233637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 234637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell if (mPullDistance == 0) { 235637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowScaleY = 0; 236637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 237637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 238637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // Do not allow glow to get larger than MAX_GLOW_HEIGHT. 239637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowScaleY = mGlowScaleYStart = Math.min(MAX_GLOW_HEIGHT, Math.max( 240637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 0, mGlowScaleY + glowChange * PULL_DISTANCE_GLOW_FACTOR)); 241637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 242637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeAlphaFinish = mEdgeAlpha; 243637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeScaleYFinish = mEdgeScaleY; 244637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowAlphaFinish = mGlowAlpha; 245637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowScaleYFinish = mGlowScaleY; 246637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 247637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 248637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell /** 249637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * Call when the object is released after being pulled. 25089935e41c593a599e8955388b27fb926e60e5e94Adam Powell * This will begin the "decay" phase of the effect. After calling this method 25189935e41c593a599e8955388b27fb926e60e5e94Adam Powell * the host view should {@link android.view.View#invalidate()} and thereby 25289935e41c593a599e8955388b27fb926e60e5e94Adam Powell * draw the results accordingly. 253637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell */ 254637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell public void onRelease() { 255637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mPullDistance = 0; 256637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 257637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell if (mState != STATE_PULL && mState != STATE_PULL_DECAY) { 258637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell return; 259637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 260637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 261637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mState = STATE_RECEDE; 262637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeAlphaStart = mEdgeAlpha; 263637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeScaleYStart = mEdgeScaleY; 264637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowAlphaStart = mGlowAlpha; 265637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowScaleYStart = mGlowScaleY; 266637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 267637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeAlphaFinish = 0.f; 268637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeScaleYFinish = 0.f; 269637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowAlphaFinish = 0.f; 270637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowScaleYFinish = 0.f; 271637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 272637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mStartTime = AnimationUtils.currentAnimationTimeMillis(); 273637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mDuration = RECEDE_TIME; 274637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 275637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 276637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell /** 277637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * Call when the effect absorbs an impact at the given velocity. 27889935e41c593a599e8955388b27fb926e60e5e94Adam Powell * Used when a fling reaches the scroll boundary. 27989935e41c593a599e8955388b27fb926e60e5e94Adam Powell * 28089935e41c593a599e8955388b27fb926e60e5e94Adam Powell * <p>When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller}, 28189935e41c593a599e8955388b27fb926e60e5e94Adam Powell * the method <code>getCurrVelocity</code> will provide a reasonable approximation 28289935e41c593a599e8955388b27fb926e60e5e94Adam Powell * to use here.</p> 283637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * 284637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * @param velocity Velocity at impact in pixels per second. 285637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell */ 286637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell public void onAbsorb(int velocity) { 287637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mState = STATE_ABSORB; 2882d1acfc9f7e1502a5dbb8cab54289d6fbb880467Christian Robertson velocity = Math.min(Math.max(MIN_VELOCITY, Math.abs(velocity)), MAX_VELOCITY); 289637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 290637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mStartTime = AnimationUtils.currentAnimationTimeMillis(); 2912d1acfc9f7e1502a5dbb8cab54289d6fbb880467Christian Robertson mDuration = 0.15f + (velocity * 0.02f); 292637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 293637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // The edge should always be at least partially visible, regardless 294637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // of velocity. 295637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeAlphaStart = 0.f; 296637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeScaleY = mEdgeScaleYStart = 0.f; 297637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // The glow depends more on the velocity, and therefore starts out 298637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // nearly invisible. 2992d1acfc9f7e1502a5dbb8cab54289d6fbb880467Christian Robertson mGlowAlphaStart = 0.3f; 300637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowScaleYStart = 0.f; 301637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 302637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // Factor the velocity by 8. Testing on device shows this works best to 303637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // reflect the strength of the user's scrolling. 304637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeAlphaFinish = Math.max(0, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1)); 305637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // Edge should never get larger than the size of its asset. 306637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeScaleYFinish = Math.max( 307637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell HELD_EDGE_SCALE_Y, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1.f)); 308637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 309637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // Growth for the size of the glow should be quadratic to properly 310637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // respond 311637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // to a user's scrolling speed. The faster the scrolling speed, the more 312637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // intense the effect should be for both the size and the saturation. 313637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f); 314637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // Alpha should change for the glow as well as size. 315637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowAlphaFinish = Math.max( 316637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA)); 317637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 318637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 319637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 320637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell /** 321637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * Draw into the provided canvas. Assumes that the canvas has been rotated 322637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * accordingly and the size has been set. The effect will be drawn the full 32389935e41c593a599e8955388b27fb926e60e5e94Adam Powell * width of X=0 to X=width, beginning from Y=0 and extending to some factor < 324637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * 1.f of height. 325637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * 326637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * @param canvas Canvas to draw into 327637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * @return true if drawing should continue beyond this frame to continue the 328637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * animation 329637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell */ 330637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell public boolean draw(Canvas canvas) { 331637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell update(); 332637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 333637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlow.setAlpha((int) (Math.max(0, Math.min(mGlowAlpha, 1)) * 255)); 334a5531d784b9b79fe3bf9b30d99e9c99ea3947c6dMindy Pereira 3354e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira int glowBottom = (int) Math.min( 336a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy mGlowHeight * mGlowScaleY * mGlowHeight / mGlowWidth * 0.6f, 337a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy mGlowHeight * MAX_GLOW_HEIGHT); 3384e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira if (mWidth < mMinWidth) { 3394e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira // Center the glow and clip it. 340ffc4196c46419469f088ca23a0d0e31cf7979e30Jim Miller int glowLeft = (mWidth - mMinWidth)/2; 3414e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira mGlow.setBounds(glowLeft, 0, mWidth - glowLeft, glowBottom); 3424e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira } else { 3434e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira // Stretch the glow to fit. 3444e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira mGlow.setBounds(0, 0, mWidth, glowBottom); 3454e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira } 3464e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira 347637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlow.draw(canvas); 348637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 349637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdge.setAlpha((int) (Math.max(0, Math.min(mEdgeAlpha, 1)) * 255)); 350a5531d784b9b79fe3bf9b30d99e9c99ea3947c6dMindy Pereira 351a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy int edgeBottom = (int) (mEdgeHeight * mEdgeScaleY); 3524e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira if (mWidth < mMinWidth) { 3534e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira // Center the edge and clip it. 354ffc4196c46419469f088ca23a0d0e31cf7979e30Jim Miller int edgeLeft = (mWidth - mMinWidth)/2; 3554e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira mEdge.setBounds(edgeLeft, 0, mWidth - edgeLeft, edgeBottom); 3564e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira } else { 3574e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira // Stretch the edge to fit. 3584e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira mEdge.setBounds(0, 0, mWidth, edgeBottom); 3594e30d89ceda832300f80bf73f4f58cd2b51bf112Mindy Pereira } 360637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdge.draw(canvas); 361637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 3629d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy if (mState == STATE_RECEDE && glowBottom == 0 && edgeBottom == 0) { 3639d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy mState = STATE_IDLE; 3649d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy } 3659d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy 366637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell return mState != STATE_IDLE; 367637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 368637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 3699d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy /** 3709d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy * Returns the bounds of the edge effect. 371a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy * 372a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy * @hide 3739d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy */ 374a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy public Rect getBounds(boolean reverse) { 375a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy mBounds.set(0, 0, mWidth, mMaxEffectHeight); 376a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy mBounds.offset(mX, mY - (reverse ? mMaxEffectHeight : 0)); 377a8bfeaf4f49fa33e96f37302f9c9b99c94aa1581Romain Guy 3789d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy return mBounds; 3799d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy } 3809d849a2f6351caed83105b90cab79223ec2bfbd3Romain Guy 381637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private void update() { 382637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell final long time = AnimationUtils.currentAnimationTimeMillis(); 383637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell final float t = Math.min((time - mStartTime) / mDuration, 1.f); 384637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 385637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell final float interp = mInterpolator.getInterpolation(t); 386637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 387637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeAlpha = mEdgeAlphaStart + (mEdgeAlphaFinish - mEdgeAlphaStart) * interp; 388637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeScaleY = mEdgeScaleYStart + (mEdgeScaleYFinish - mEdgeScaleYStart) * interp; 389637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp; 390637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp; 391637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 392637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell if (t >= 1.f - EPSILON) { 393637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell switch (mState) { 394637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell case STATE_ABSORB: 395637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mState = STATE_RECEDE; 396637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mStartTime = AnimationUtils.currentAnimationTimeMillis(); 397637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mDuration = RECEDE_TIME; 398637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 399637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeAlphaStart = mEdgeAlpha; 400637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeScaleYStart = mEdgeScaleY; 401637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowAlphaStart = mGlowAlpha; 402637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowScaleYStart = mGlowScaleY; 403637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 404637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // After absorb, the glow and edge should fade to nothing. 405637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeAlphaFinish = 0.f; 406637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeScaleYFinish = 0.f; 407637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowAlphaFinish = 0.f; 408637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowScaleYFinish = 0.f; 409637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell break; 410637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell case STATE_PULL: 411637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mState = STATE_PULL_DECAY; 412637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mStartTime = AnimationUtils.currentAnimationTimeMillis(); 413637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mDuration = PULL_DECAY_TIME; 414637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 415637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeAlphaStart = mEdgeAlpha; 416637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeScaleYStart = mEdgeScaleY; 417637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowAlphaStart = mGlowAlpha; 418637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowScaleYStart = mGlowScaleY; 419637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 420637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // After pull, the glow and edge should fade to nothing. 421637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeAlphaFinish = 0.f; 422637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeScaleYFinish = 0.f; 423637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowAlphaFinish = 0.f; 424637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mGlowScaleYFinish = 0.f; 425637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell break; 426637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell case STATE_PULL_DECAY: 427637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // When receding, we want edge to decrease more slowly 428637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // than the glow. 429637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell float factor = mGlowScaleYFinish != 0 ? 1 430637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell / (mGlowScaleYFinish * mGlowScaleYFinish) 431637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell : Float.MAX_VALUE; 432637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mEdgeScaleY = mEdgeScaleYStart + 433637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell (mEdgeScaleYFinish - mEdgeScaleYStart) * 434637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell interp * factor; 4350b1ab3a2776a1fff5b2abbddd3bc256e355e30efDaniel Mladenovic mState = STATE_RECEDE; 436637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell break; 437637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell case STATE_RECEDE: 438637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mState = STATE_IDLE; 439637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell break; 440637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 441637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 442637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell } 443637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell} 444