• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.webkit;
17 
18 import com.android.internal.R;
19 
20 import android.content.Context;
21 import android.content.res.Resources;
22 import android.graphics.Canvas;
23 import android.graphics.drawable.Drawable;
24 import android.view.View;
25 import android.widget.EdgeEffect;
26 
27 /**
28  * This class manages the edge glow effect when a WebView is flung or pulled beyond the edges.
29  * @hide
30  */
31 public class OverScrollGlow {
32     private WebViewClassic mHostView;
33 
34     private EdgeEffect mEdgeGlowTop;
35     private EdgeEffect mEdgeGlowBottom;
36     private EdgeEffect mEdgeGlowLeft;
37     private EdgeEffect mEdgeGlowRight;
38 
39     private int mOverScrollDeltaX;
40     private int mOverScrollDeltaY;
41 
OverScrollGlow(WebViewClassic host)42     public OverScrollGlow(WebViewClassic host) {
43         mHostView = host;
44         Context context = host.getContext();
45         mEdgeGlowTop = new EdgeEffect(context);
46         mEdgeGlowBottom = new EdgeEffect(context);
47         mEdgeGlowLeft = new EdgeEffect(context);
48         mEdgeGlowRight = new EdgeEffect(context);
49     }
50 
51     /**
52      * Pull leftover touch scroll distance into one of the edge glows as appropriate.
53      *
54      * @param x Current X scroll offset
55      * @param y Current Y scroll offset
56      * @param oldX Old X scroll offset
57      * @param oldY Old Y scroll offset
58      * @param maxX Maximum range for horizontal scrolling
59      * @param maxY Maximum range for vertical scrolling
60      */
pullGlow(int x, int y, int oldX, int oldY, int maxX, int maxY)61     public void pullGlow(int x, int y, int oldX, int oldY, int maxX, int maxY) {
62         // Only show overscroll bars if there was no movement in any direction
63         // as a result of scrolling.
64         if (oldX == mHostView.getScrollX() && oldY == mHostView.getScrollY()) {
65             // Don't show left/right glows if we fit the whole content.
66             // Also don't show if there was vertical movement.
67             if (maxX > 0) {
68                 final int pulledToX = oldX + mOverScrollDeltaX;
69                 if (pulledToX < 0) {
70                     mEdgeGlowLeft.onPull((float) mOverScrollDeltaX / mHostView.getWidth());
71                     if (!mEdgeGlowRight.isFinished()) {
72                         mEdgeGlowRight.onRelease();
73                     }
74                 } else if (pulledToX > maxX) {
75                     mEdgeGlowRight.onPull((float) mOverScrollDeltaX / mHostView.getWidth());
76                     if (!mEdgeGlowLeft.isFinished()) {
77                         mEdgeGlowLeft.onRelease();
78                     }
79                 }
80                 mOverScrollDeltaX = 0;
81             }
82 
83             if (maxY > 0 || mHostView.getWebView().getOverScrollMode() == View.OVER_SCROLL_ALWAYS) {
84                 final int pulledToY = oldY + mOverScrollDeltaY;
85                 if (pulledToY < 0) {
86                     mEdgeGlowTop.onPull((float) mOverScrollDeltaY / mHostView.getHeight());
87                     if (!mEdgeGlowBottom.isFinished()) {
88                         mEdgeGlowBottom.onRelease();
89                     }
90                 } else if (pulledToY > maxY) {
91                     mEdgeGlowBottom.onPull((float) mOverScrollDeltaY / mHostView.getHeight());
92                     if (!mEdgeGlowTop.isFinished()) {
93                         mEdgeGlowTop.onRelease();
94                     }
95                 }
96                 mOverScrollDeltaY = 0;
97             }
98         }
99     }
100 
101     /**
102      * Set touch delta values indicating the current amount of overscroll.
103      *
104      * @param deltaX
105      * @param deltaY
106      */
setOverScrollDeltas(int deltaX, int deltaY)107     public void setOverScrollDeltas(int deltaX, int deltaY) {
108         mOverScrollDeltaX = deltaX;
109         mOverScrollDeltaY = deltaY;
110     }
111 
112     /**
113      * Absorb leftover fling velocity into one of the edge glows as appropriate.
114      *
115      * @param x Current X scroll offset
116      * @param y Current Y scroll offset
117      * @param oldX Old X scroll offset
118      * @param oldY Old Y scroll offset
119      * @param rangeX Maximum range for horizontal scrolling
120      * @param rangeY Maximum range for vertical scrolling
121      */
absorbGlow(int x, int y, int oldX, int oldY, int rangeX, int rangeY)122     public void absorbGlow(int x, int y, int oldX, int oldY, int rangeX, int rangeY) {
123         if (rangeY > 0 || mHostView.getWebView().getOverScrollMode() == View.OVER_SCROLL_ALWAYS) {
124             if (y < 0 && oldY >= 0) {
125                 mEdgeGlowTop.onAbsorb((int) mHostView.mScroller.getCurrVelocity());
126                 if (!mEdgeGlowBottom.isFinished()) {
127                     mEdgeGlowBottom.onRelease();
128                 }
129             } else if (y > rangeY && oldY <= rangeY) {
130                 mEdgeGlowBottom.onAbsorb((int) mHostView.mScroller.getCurrVelocity());
131                 if (!mEdgeGlowTop.isFinished()) {
132                     mEdgeGlowTop.onRelease();
133                 }
134             }
135         }
136 
137         if (rangeX > 0) {
138             if (x < 0 && oldX >= 0) {
139                 mEdgeGlowLeft.onAbsorb((int) mHostView.mScroller.getCurrVelocity());
140                 if (!mEdgeGlowRight.isFinished()) {
141                     mEdgeGlowRight.onRelease();
142                 }
143             } else if (x > rangeX && oldX <= rangeX) {
144                 mEdgeGlowRight.onAbsorb((int) mHostView.mScroller.getCurrVelocity());
145                 if (!mEdgeGlowLeft.isFinished()) {
146                     mEdgeGlowLeft.onRelease();
147                 }
148             }
149         }
150     }
151 
152     /**
153      * Draw the glow effect along the sides of the widget. mEdgeGlow* must be non-null.
154      *
155      * @param canvas Canvas to draw into, transformed into view coordinates.
156      * @return true if glow effects are still animating and the view should invalidate again.
157      */
drawEdgeGlows(Canvas canvas)158     public boolean drawEdgeGlows(Canvas canvas) {
159         final int scrollX = mHostView.getScrollX();
160         final int scrollY = mHostView.getScrollY();
161         final int width = mHostView.getWidth();
162         int height = mHostView.getHeight();
163 
164         boolean invalidateForGlow = false;
165         if (!mEdgeGlowTop.isFinished()) {
166             final int restoreCount = canvas.save();
167 
168             canvas.translate(scrollX, mHostView.getVisibleTitleHeight() + Math.min(0, scrollY));
169             mEdgeGlowTop.setSize(width, height);
170             invalidateForGlow |= mEdgeGlowTop.draw(canvas);
171             canvas.restoreToCount(restoreCount);
172         }
173         if (!mEdgeGlowBottom.isFinished()) {
174             final int restoreCount = canvas.save();
175 
176             canvas.translate(-width + scrollX, Math.max(mHostView.computeMaxScrollY(), scrollY)
177                     + height);
178             canvas.rotate(180, width, 0);
179             mEdgeGlowBottom.setSize(width, height);
180             invalidateForGlow |= mEdgeGlowBottom.draw(canvas);
181             canvas.restoreToCount(restoreCount);
182         }
183         if (!mEdgeGlowLeft.isFinished()) {
184             final int restoreCount = canvas.save();
185 
186             canvas.rotate(270);
187             canvas.translate(-height - scrollY, Math.min(0, scrollX));
188             mEdgeGlowLeft.setSize(height, width);
189             invalidateForGlow |= mEdgeGlowLeft.draw(canvas);
190             canvas.restoreToCount(restoreCount);
191         }
192         if (!mEdgeGlowRight.isFinished()) {
193             final int restoreCount = canvas.save();
194 
195             canvas.rotate(90);
196             canvas.translate(scrollY,
197                     -(Math.max(mHostView.computeMaxScrollX(), scrollX) + width));
198             mEdgeGlowRight.setSize(height, width);
199             invalidateForGlow |= mEdgeGlowRight.draw(canvas);
200             canvas.restoreToCount(restoreCount);
201         }
202         return invalidateForGlow;
203     }
204 
205     /**
206      * @return True if any glow is still animating
207      */
isAnimating()208     public boolean isAnimating() {
209         return (!mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished() ||
210                 !mEdgeGlowLeft.isFinished() || !mEdgeGlowRight.isFinished());
211     }
212 
213     /**
214      * Release all glows from any touch pulls in progress.
215      */
releaseAll()216     public void releaseAll() {
217         mEdgeGlowTop.onRelease();
218         mEdgeGlowBottom.onRelease();
219         mEdgeGlowLeft.onRelease();
220         mEdgeGlowRight.onRelease();
221     }
222 }
223