- add sources.
[platform/framework/web/crosswalk.git] / src / android_webview / javatests / src / org / chromium / android_webview / test / AwScrollOffsetManagerTest.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.test;
6
7 import android.content.Context;
8 import android.graphics.Rect;
9 import android.test.InstrumentationTestCase;
10 import android.test.suitebuilder.annotation.SmallTest;
11 import android.view.View.MeasureSpec;
12 import android.view.View;
13 import android.widget.OverScroller;
14
15 import org.chromium.android_webview.AwScrollOffsetManager;
16 import org.chromium.base.test.util.Feature;
17
18 public class AwScrollOffsetManagerTest extends InstrumentationTestCase {
19     private static class TestScrollOffsetManagerDelegate implements AwScrollOffsetManager.Delegate {
20         private int mOverScrollDeltaX;
21         private int mOverScrollDeltaY;
22         private int mOverScrollCallCount;
23         private int mScrollX;
24         private int mScrollY;
25         private int mNativeScrollX;
26         private int mNativeScrollY;
27         private int mInvalidateCount;
28
29         public int getOverScrollDeltaX() {
30             return mOverScrollDeltaX;
31         }
32
33         public int getOverScrollDeltaY() {
34             return mOverScrollDeltaY;
35         }
36
37         public int getOverScrollCallCount() {
38             return mOverScrollCallCount;
39         }
40
41         public int getScrollX() {
42             return mScrollX;
43         }
44
45         public int getScrollY() {
46             return mScrollY;
47         }
48
49         public int getNativeScrollX() {
50             return mNativeScrollX;
51         }
52
53         public int getNativeScrollY() {
54             return mNativeScrollY;
55         }
56
57         public int getInvalidateCount() {
58             return mInvalidateCount;
59         }
60
61         @Override
62         public void overScrollContainerViewBy(int deltaX, int deltaY, int scrollX, int scrollY,
63                 int scrollRangeX, int scrollRangeY, boolean isTouchEvent) {
64             mOverScrollDeltaX = deltaX;
65             mOverScrollDeltaY = deltaY;
66             mOverScrollCallCount += 1;
67         }
68
69         @Override
70         public void scrollContainerViewTo(int x, int y) {
71             mScrollX = x;
72             mScrollY = y;
73         }
74
75         @Override
76         public void scrollNativeTo(int x, int y) {
77             mNativeScrollX = x;
78             mNativeScrollY = y;
79         }
80
81         @Override
82         public int getContainerViewScrollX() {
83             return mScrollX;
84         }
85
86         @Override
87         public int getContainerViewScrollY() {
88             return mScrollY;
89         }
90
91         @Override
92         public void invalidate() {
93             mInvalidateCount += 1;
94         }
95     }
96
97     private void simulateScrolling(AwScrollOffsetManager offsetManager,
98             TestScrollOffsetManagerDelegate delegate, int scrollX, int scrollY) {
99         // Scrolling is a two-phase action. First we ask the manager to scroll
100         int callCount = delegate.getOverScrollCallCount();
101         offsetManager.scrollContainerViewTo(scrollX, scrollY);
102         // The manager then asks the delegate to overscroll the view.
103         assertEquals(callCount + 1, delegate.getOverScrollCallCount());
104         assertEquals(scrollX, delegate.getOverScrollDeltaX() + delegate.getScrollX());
105         assertEquals(scrollY, delegate.getOverScrollDeltaY() + delegate.getScrollY());
106         // As a response to that the menager expects the view to call back with the new scroll.
107         offsetManager.onContainerViewOverScrolled(scrollX, scrollY, false, false);
108     }
109
110     private void simlateOverScrollPropagation(AwScrollOffsetManager offsetManager,
111             TestScrollOffsetManagerDelegate delegate) {
112         assertTrue(delegate.getOverScrollCallCount() > 0);
113
114         offsetManager.onContainerViewOverScrolled(
115                 delegate.getOverScrollDeltaX() + delegate.getScrollX(),
116                 delegate.getOverScrollDeltaY() + delegate.getScrollY(), false, false);
117     }
118
119     @SmallTest
120     @Feature({"AndroidWebView"})
121     public void testWhenContentSizeMatchesView() {
122         TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
123         OverScroller scroller = new OverScroller(getInstrumentation().getContext());
124         AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
125
126         final int width = 132;
127         final int height = 212;
128         final int scrollX = 11;
129         final int scrollY = 13;
130
131         offsetManager.setMaxScrollOffset(0, 0);
132         offsetManager.setContainerViewSize(width, height);
133
134         assertEquals(width, offsetManager.computeHorizontalScrollRange());
135         assertEquals(height, offsetManager.computeVerticalScrollRange());
136
137         // Since the view size and contents size are equal no scrolling should be possible.
138         assertEquals(0, offsetManager.computeMaximumHorizontalScrollOffset());
139         assertEquals(0, offsetManager.computeMaximumVerticalScrollOffset());
140
141         // Scrolling should generate overscroll but not update the scroll offset.
142         simulateScrolling(offsetManager, delegate, scrollX, scrollY);
143         assertEquals(scrollX, delegate.getOverScrollDeltaX());
144         assertEquals(scrollY, delegate.getOverScrollDeltaY());
145         assertEquals(0, delegate.getScrollX());
146         assertEquals(0, delegate.getScrollY());
147         assertEquals(0, delegate.getNativeScrollX());
148         assertEquals(0, delegate.getNativeScrollY());
149
150         // Scrolling to 0,0 should result in no deltas.
151         simulateScrolling(offsetManager, delegate, 0, 0);
152         assertEquals(0, delegate.getOverScrollDeltaX());
153         assertEquals(0, delegate.getOverScrollDeltaY());
154
155         // Negative scrolling should result in negative deltas but no scroll offset update.
156         simulateScrolling(offsetManager, delegate, -scrollX, -scrollY);
157         assertEquals(-scrollX, delegate.getOverScrollDeltaX());
158         assertEquals(-scrollY, delegate.getOverScrollDeltaY());
159         assertEquals(0, delegate.getScrollX());
160         assertEquals(0, delegate.getScrollY());
161         assertEquals(0, delegate.getNativeScrollX());
162         assertEquals(0, delegate.getNativeScrollY());
163     }
164
165     private static final int VIEW_WIDTH = 211;
166     private static final int VIEW_HEIGHT = 312;
167     private static final int MAX_HORIZONTAL_OFFSET = 757;
168     private static final int MAX_VERTICAL_OFFSET = 127;
169     private static final int CONTENT_WIDTH = VIEW_WIDTH + MAX_HORIZONTAL_OFFSET;
170     private static final int CONTENT_HEIGHT = VIEW_HEIGHT + MAX_VERTICAL_OFFSET;
171
172     @SmallTest
173     @Feature({"AndroidWebView"})
174     public void testScrollRangeAndMaxOffset() {
175         TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
176         OverScroller scroller = new OverScroller(getInstrumentation().getContext());
177         AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
178
179         offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
180         offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
181
182         assertEquals(CONTENT_WIDTH, offsetManager.computeHorizontalScrollRange());
183         assertEquals(CONTENT_HEIGHT, offsetManager.computeVerticalScrollRange());
184
185         assertEquals(MAX_HORIZONTAL_OFFSET, offsetManager.computeMaximumHorizontalScrollOffset());
186         assertEquals(MAX_VERTICAL_OFFSET, offsetManager.computeMaximumVerticalScrollOffset());
187
188         // Scrolling beyond the maximum should be clamped.
189         final int scrollX = MAX_HORIZONTAL_OFFSET + 10;
190         final int scrollY = MAX_VERTICAL_OFFSET + 11;
191
192         simulateScrolling(offsetManager, delegate, scrollX, scrollY);
193         assertEquals(scrollX, delegate.getOverScrollDeltaX());
194         assertEquals(scrollY, delegate.getOverScrollDeltaY());
195         assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getScrollX());
196         assertEquals(MAX_VERTICAL_OFFSET, delegate.getScrollY());
197         assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getNativeScrollX());
198         assertEquals(MAX_VERTICAL_OFFSET, delegate.getNativeScrollY());
199
200         // Scrolling to negative coordinates should be clamped back to 0,0.
201         simulateScrolling(offsetManager, delegate, -scrollX, -scrollY);
202         assertEquals(0, delegate.getScrollX());
203         assertEquals(0, delegate.getScrollY());
204         assertEquals(0, delegate.getNativeScrollX());
205         assertEquals(0, delegate.getNativeScrollY());
206
207         // The onScrollChanged method is callable by third party code and should also be clamped
208         offsetManager.onContainerViewScrollChanged(scrollX, scrollY);
209         assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getNativeScrollX());
210         assertEquals(MAX_VERTICAL_OFFSET, delegate.getNativeScrollY());
211
212         offsetManager.onContainerViewScrollChanged(-scrollX, -scrollY);
213         assertEquals(0, delegate.getNativeScrollX());
214         assertEquals(0, delegate.getNativeScrollY());
215     }
216
217     @SmallTest
218     @Feature({"AndroidWebView"})
219     public void testDelegateCanOverrideScroll() {
220         final int overrideScrollX = 10;
221         final int overrideScrollY = 10;
222
223         TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate() {
224             @Override
225             public int getContainerViewScrollX() {
226                 return overrideScrollX;
227             }
228
229             @Override
230             public int getContainerViewScrollY() {
231                 return overrideScrollY;
232             }
233         };
234         OverScroller scroller = new OverScroller(getInstrumentation().getContext());
235         AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
236
237         offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
238         offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
239
240         offsetManager.onContainerViewOverScrolled(0, 0, false, false);
241         assertEquals(overrideScrollX, delegate.getNativeScrollX());
242         assertEquals(overrideScrollY, delegate.getNativeScrollY());
243     }
244
245     @SmallTest
246     @Feature({"AndroidWebView"})
247     public void testDelegateOverridenScrollsDontExceedBounds() {
248         final int overrideScrollX = MAX_HORIZONTAL_OFFSET + 10;
249         final int overrideScrollY = MAX_VERTICAL_OFFSET + 20;
250         TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate() {
251             @Override
252             public int getContainerViewScrollX() {
253                 return overrideScrollX;
254             }
255
256             @Override
257             public int getContainerViewScrollY() {
258                 return overrideScrollY;
259             }
260         };
261         OverScroller scroller = new OverScroller(getInstrumentation().getContext());
262         AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
263
264         offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
265         offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
266
267         offsetManager.onContainerViewOverScrolled(0, 0, false, false);
268         assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getNativeScrollX());
269         assertEquals(MAX_VERTICAL_OFFSET, delegate.getNativeScrollY());
270     }
271
272     @SmallTest
273     @Feature({"AndroidWebView"})
274     public void testScrollContainerViewTo() {
275         TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
276         OverScroller scroller = new OverScroller(getInstrumentation().getContext());
277         AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
278
279         final int scrollX = 31;
280         final int scrollY = 41;
281
282         offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
283         offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
284
285         assertEquals(0, delegate.getOverScrollDeltaX());
286         assertEquals(0, delegate.getOverScrollDeltaY());
287         int callCount = delegate.getOverScrollCallCount();
288
289         offsetManager.scrollContainerViewTo(scrollX, scrollY);
290         assertEquals(callCount + 1, delegate.getOverScrollCallCount());
291         assertEquals(scrollX, delegate.getOverScrollDeltaX());
292         assertEquals(scrollY, delegate.getOverScrollDeltaY());
293     }
294
295     @SmallTest
296     @Feature({"AndroidWebView"})
297     public void testOnContainerViewOverScrolled() {
298         TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
299         OverScroller scroller = new OverScroller(getInstrumentation().getContext());
300         AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
301
302         final int scrollX = 31;
303         final int scrollY = 41;
304
305         offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
306         offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
307
308         assertEquals(0, delegate.getScrollX());
309         assertEquals(0, delegate.getScrollY());
310         assertEquals(0, delegate.getNativeScrollX());
311         assertEquals(0, delegate.getNativeScrollY());
312
313         offsetManager.onContainerViewOverScrolled(scrollX, scrollY, false, false);
314         assertEquals(scrollX, delegate.getScrollX());
315         assertEquals(scrollY, delegate.getScrollY());
316         assertEquals(scrollX, delegate.getNativeScrollX());
317         assertEquals(scrollY, delegate.getNativeScrollY());
318     }
319
320     @SmallTest
321     @Feature({"AndroidWebView"})
322     public void testDefersScrollUntilTouchEnd() {
323         TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
324         OverScroller scroller = new OverScroller(getInstrumentation().getContext());
325         AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
326
327         final int scrollX = 31;
328         final int scrollY = 41;
329
330         offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
331         offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
332
333         offsetManager.setProcessingTouchEvent(true);
334         offsetManager.onContainerViewOverScrolled(scrollX, scrollY, false, false);
335         assertEquals(scrollX, delegate.getScrollX());
336         assertEquals(scrollY, delegate.getScrollY());
337         assertEquals(0, delegate.getNativeScrollX());
338         assertEquals(0, delegate.getNativeScrollY());
339
340         offsetManager.setProcessingTouchEvent(false);
341         assertEquals(scrollX, delegate.getScrollX());
342         assertEquals(scrollY, delegate.getScrollY());
343         assertEquals(scrollX, delegate.getNativeScrollX());
344         assertEquals(scrollY, delegate.getNativeScrollY());
345     }
346
347     @SmallTest
348     @Feature({"AndroidWebView"})
349     public void testFlingScroll() {
350         TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
351         OverScroller scroller = new OverScroller(getInstrumentation().getContext());
352         AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
353
354         offsetManager.flingScroll(0, 101);
355         assertTrue(!scroller.isFinished());
356         assertTrue(delegate.getInvalidateCount() == 1);
357         assertEquals(101, (int) scroller.getCurrVelocity());
358
359         offsetManager.flingScroll(111, 0);
360         assertTrue(!scroller.isFinished());
361         assertTrue(delegate.getInvalidateCount() == 2);
362         assertEquals(111, (int) scroller.getCurrVelocity());
363     }
364
365     @SmallTest
366     @Feature({"AndroidWebView"})
367     public void testRequestChildRectangleOnScreenDontScrollIfAlreadyThere() {
368         TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
369         OverScroller scroller = new OverScroller(getInstrumentation().getContext());
370         AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
371
372         offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
373         offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
374
375         offsetManager.requestChildRectangleOnScreen(0, 0,
376                 new Rect(0, 0, VIEW_WIDTH / 4, VIEW_HEIGHT / 4), true);
377         assertEquals(0, delegate.getOverScrollDeltaX());
378         assertEquals(0, delegate.getOverScrollDeltaY());
379         assertEquals(0, delegate.getScrollX());
380         assertEquals(0, delegate.getScrollY());
381
382         offsetManager.requestChildRectangleOnScreen(3 * VIEW_WIDTH / 4, 3 * VIEW_HEIGHT / 4,
383                 new Rect(0, 0, VIEW_WIDTH / 4, VIEW_HEIGHT / 4), true);
384         assertEquals(0, delegate.getOverScrollDeltaX());
385         assertEquals(0, delegate.getOverScrollDeltaY());
386         assertEquals(0, delegate.getScrollX());
387         assertEquals(0, delegate.getScrollY());
388     }
389
390     @SmallTest
391     @Feature({"AndroidWebView"})
392     public void testRequestChildRectangleOnScreenScrollToBottom() {
393         TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
394         OverScroller scroller = new OverScroller(getInstrumentation().getContext());
395         AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
396
397         final int rectWidth = 2;
398         final int rectHeight = 3;
399
400         offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
401         offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
402
403         offsetManager.requestChildRectangleOnScreen(CONTENT_WIDTH - rectWidth,
404                 CONTENT_HEIGHT - rectHeight, new Rect(0, 0, rectWidth, rectHeight), true);
405         simlateOverScrollPropagation(offsetManager, delegate);
406         assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getOverScrollDeltaX());
407         assertEquals(CONTENT_HEIGHT - rectHeight - VIEW_HEIGHT / 3, delegate.getOverScrollDeltaY());
408         assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getScrollX());
409         assertEquals(MAX_VERTICAL_OFFSET, delegate.getScrollY());
410     }
411
412     @SmallTest
413     @Feature({"AndroidWebView"})
414     public void testRequestChildRectangleOnScreenScrollToBottomLargeRect() {
415         TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
416         OverScroller scroller = new OverScroller(getInstrumentation().getContext());
417         AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
418
419         final int rectWidth = VIEW_WIDTH;
420         final int rectHeight = VIEW_HEIGHT;
421
422         offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
423         offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
424
425         offsetManager.requestChildRectangleOnScreen(CONTENT_WIDTH - rectWidth,
426                 CONTENT_HEIGHT - rectHeight, new Rect(0, 0, rectWidth, rectHeight), true);
427         simlateOverScrollPropagation(offsetManager, delegate);
428         assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getOverScrollDeltaX());
429         assertEquals(MAX_VERTICAL_OFFSET, delegate.getOverScrollDeltaY());
430         assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getScrollX());
431         assertEquals(MAX_VERTICAL_OFFSET, delegate.getScrollY());
432     }
433
434     @SmallTest
435     @Feature({"AndroidWebView"})
436     public void testRequestChildRectangleOnScreenScrollToTop() {
437         TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
438         OverScroller scroller = new OverScroller(getInstrumentation().getContext());
439         AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
440
441         final int rectWidth = 2;
442         final int rectHeight = 3;
443
444         offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
445         offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
446         simulateScrolling(offsetManager, delegate,
447                 CONTENT_WIDTH - VIEW_WIDTH, CONTENT_HEIGHT - VIEW_HEIGHT);
448
449         offsetManager.requestChildRectangleOnScreen(0, 0,
450                 new Rect(0, 0, rectWidth, rectHeight), true);
451         simlateOverScrollPropagation(offsetManager, delegate);
452         assertEquals(-CONTENT_WIDTH + VIEW_WIDTH, delegate.getOverScrollDeltaX());
453         assertEquals(-CONTENT_HEIGHT + VIEW_HEIGHT, delegate.getOverScrollDeltaY());
454         assertEquals(0, delegate.getScrollX());
455         assertEquals(0, delegate.getScrollX());
456     }
457 }