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