Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / android_webview / java / src / org / chromium / android_webview / OverScrollGlow.java
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.android_webview;
6
7 import android.content.Context;
8 import android.graphics.Canvas;
9 import android.view.View;
10 import android.widget.EdgeEffect;
11
12 /**
13  * This class manages the edge glow effect when a WebView is flung or pulled beyond the edges.
14  */
15 class OverScrollGlow {
16     private View mHostView;
17
18     private EdgeEffect mEdgeGlowTop;
19     private EdgeEffect mEdgeGlowBottom;
20     private EdgeEffect mEdgeGlowLeft;
21     private EdgeEffect mEdgeGlowRight;
22
23     private int mOverScrollDeltaX;
24     private int mOverScrollDeltaY;
25
26     private boolean mShouldPull;
27
28     public OverScrollGlow(Context context, View host) {
29         mHostView = host;
30         mEdgeGlowTop = new EdgeEffect(context);
31         mEdgeGlowBottom = new EdgeEffect(context);
32         mEdgeGlowLeft = new EdgeEffect(context);
33         mEdgeGlowRight = new EdgeEffect(context);
34     }
35
36     public void setShouldPull(boolean shouldPull) {
37         mShouldPull = shouldPull;
38     }
39
40     /**
41      * Pull leftover touch scroll distance into one of the edge glows as appropriate.
42      *
43      * @param x Current X scroll offset
44      * @param y Current Y scroll offset
45      * @param oldX Old X scroll offset
46      * @param oldY Old Y scroll offset
47      * @param maxX Maximum range for horizontal scrolling
48      * @param maxY Maximum range for vertical scrolling
49      */
50     public void pullGlow(int x, int y, int oldX, int oldY, int maxX, int maxY) {
51         if (!mShouldPull) return;
52         // Only show overscroll bars if there was no movement in any direction
53         // as a result of scrolling.
54         if (oldX == mHostView.getScrollX() && oldY == mHostView.getScrollY()) {
55             // Don't show left/right glows if we fit the whole content.
56             // Also don't show if there was vertical movement.
57             if (maxX > 0) {
58                 final int pulledToX = oldX + mOverScrollDeltaX;
59                 if (pulledToX < 0) {
60                     mEdgeGlowLeft.onPull((float) mOverScrollDeltaX / mHostView.getWidth());
61                     if (!mEdgeGlowRight.isFinished()) {
62                         mEdgeGlowRight.onRelease();
63                     }
64                 } else if (pulledToX > maxX) {
65                     mEdgeGlowRight.onPull((float) mOverScrollDeltaX / mHostView.getWidth());
66                     if (!mEdgeGlowLeft.isFinished()) {
67                         mEdgeGlowLeft.onRelease();
68                     }
69                 }
70                 mOverScrollDeltaX = 0;
71             }
72
73             if (maxY > 0 || mHostView.getOverScrollMode() == View.OVER_SCROLL_ALWAYS) {
74                 final int pulledToY = oldY + mOverScrollDeltaY;
75                 if (pulledToY < 0) {
76                     mEdgeGlowTop.onPull((float) mOverScrollDeltaY / mHostView.getHeight());
77                     if (!mEdgeGlowBottom.isFinished()) {
78                         mEdgeGlowBottom.onRelease();
79                     }
80                 } else if (pulledToY > maxY) {
81                     mEdgeGlowBottom.onPull((float) mOverScrollDeltaY / mHostView.getHeight());
82                     if (!mEdgeGlowTop.isFinished()) {
83                         mEdgeGlowTop.onRelease();
84                     }
85                 }
86                 mOverScrollDeltaY = 0;
87             }
88         }
89     }
90
91     /**
92      * Absorb leftover fling velocity into one of the edge glows as appropriate.
93      *
94      * @param x Current X scroll offset
95      * @param y Current Y scroll offset
96      * @param oldX Old X scroll offset
97      * @param oldY Old Y scroll offset
98      * @param rangeX Maximum range for horizontal scrolling
99      * @param rangeY Maximum range for vertical scrolling
100      * @param currentFlingVelocity Current fling velocity
101      */
102     public void absorbGlow(int x, int y, int oldX, int oldY, int rangeX, int rangeY,
103             float currentFlingVelocity) {
104         if (rangeY > 0 || mHostView.getOverScrollMode() == View.OVER_SCROLL_ALWAYS) {
105             if (y < 0 && oldY >= 0) {
106                 mEdgeGlowTop.onAbsorb((int) currentFlingVelocity);
107                 if (!mEdgeGlowBottom.isFinished()) {
108                     mEdgeGlowBottom.onRelease();
109                 }
110             } else if (y > rangeY && oldY <= rangeY) {
111                 mEdgeGlowBottom.onAbsorb((int) currentFlingVelocity);
112                 if (!mEdgeGlowTop.isFinished()) {
113                     mEdgeGlowTop.onRelease();
114                 }
115             }
116         }
117
118         if (rangeX > 0) {
119             if (x < 0 && oldX >= 0) {
120                 mEdgeGlowLeft.onAbsorb((int) currentFlingVelocity);
121                 if (!mEdgeGlowRight.isFinished()) {
122                     mEdgeGlowRight.onRelease();
123                 }
124             } else if (x > rangeX && oldX <= rangeX) {
125                 mEdgeGlowRight.onAbsorb((int) currentFlingVelocity);
126                 if (!mEdgeGlowLeft.isFinished()) {
127                     mEdgeGlowLeft.onRelease();
128                 }
129             }
130         }
131     }
132
133     /**
134      * Set touch delta values indicating the current amount of overscroll.
135      *
136      * @param deltaX
137      * @param deltaY
138      */
139     public void setOverScrollDeltas(int deltaX, int deltaY) {
140         mOverScrollDeltaX += deltaX;
141         mOverScrollDeltaY += deltaY;
142     }
143
144     /**
145      * Draw the glow effect along the sides of the widget.
146      *
147      * @param canvas Canvas to draw into, transformed into view coordinates.
148      * @param maxScrollX maximum horizontal scroll offset
149      * @param maxScrollY maximum vertical scroll offset
150      * @return true if glow effects are still animating and the view should invalidate again.
151      */
152     public boolean drawEdgeGlows(Canvas canvas, int maxScrollX, int maxScrollY) {
153         final int scrollX = mHostView.getScrollX();
154         final int scrollY = mHostView.getScrollY();
155         final int width = mHostView.getWidth();
156         int height = mHostView.getHeight();
157
158         boolean invalidateForGlow = false;
159         if (!mEdgeGlowTop.isFinished()) {
160             final int restoreCount = canvas.save();
161
162             canvas.translate(scrollX, Math.min(0, scrollY));
163             mEdgeGlowTop.setSize(width, height);
164             invalidateForGlow |= mEdgeGlowTop.draw(canvas);
165             canvas.restoreToCount(restoreCount);
166         }
167         if (!mEdgeGlowBottom.isFinished()) {
168             final int restoreCount = canvas.save();
169
170             canvas.translate(-width + scrollX, Math.max(maxScrollY, scrollY) + height);
171             canvas.rotate(180, width, 0);
172             mEdgeGlowBottom.setSize(width, height);
173             invalidateForGlow |= mEdgeGlowBottom.draw(canvas);
174             canvas.restoreToCount(restoreCount);
175         }
176         if (!mEdgeGlowLeft.isFinished()) {
177             final int restoreCount = canvas.save();
178
179             canvas.rotate(270);
180             canvas.translate(-height - scrollY, Math.min(0, scrollX));
181             mEdgeGlowLeft.setSize(height, width);
182             invalidateForGlow |= mEdgeGlowLeft.draw(canvas);
183             canvas.restoreToCount(restoreCount);
184         }
185         if (!mEdgeGlowRight.isFinished()) {
186             final int restoreCount = canvas.save();
187
188             canvas.rotate(90);
189             canvas.translate(scrollY, -(Math.max(scrollX, maxScrollX) + width));
190             mEdgeGlowRight.setSize(height, width);
191             invalidateForGlow |= mEdgeGlowRight.draw(canvas);
192             canvas.restoreToCount(restoreCount);
193         }
194         return invalidateForGlow;
195     }
196
197     /**
198      * @return True if any glow is still animating
199      */
200     public boolean isAnimating() {
201         return (!mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished()
202                 || !mEdgeGlowLeft.isFinished() || !mEdgeGlowRight.isFinished());
203     }
204
205     /**
206      * Release all glows from any touch pulls in progress.
207      */
208     public void releaseAll() {
209         mEdgeGlowTop.onRelease();
210         mEdgeGlowBottom.onRelease();
211         mEdgeGlowLeft.onRelease();
212         mEdgeGlowRight.onRelease();
213     }
214 }