1/*
2 * Copyright 2018 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
17package androidx.core.widget;
18
19import static org.hamcrest.CoreMatchers.is;
20import static org.hamcrest.MatcherAssert.assertThat;
21import static org.mockito.ArgumentMatchers.any;
22import static org.mockito.ArgumentMatchers.anyInt;
23import static org.mockito.ArgumentMatchers.eq;
24import static org.mockito.Mockito.doReturn;
25import static org.mockito.Mockito.never;
26import static org.mockito.Mockito.spy;
27import static org.mockito.Mockito.times;
28import static org.mockito.Mockito.verify;
29
30import android.content.Context;
31import android.support.test.filters.SmallTest;
32import android.support.test.runner.AndroidJUnit4;
33import android.support.v4.BaseInstrumentationTestCase;
34import android.view.View;
35import android.view.ViewGroup;
36import android.widget.FrameLayout;
37
38import androidx.annotation.NonNull;
39import androidx.annotation.Nullable;
40import androidx.core.test.R;
41import androidx.core.view.NestedScrollingChild2;
42import androidx.core.view.NestedScrollingParent2;
43import androidx.core.view.ViewCompat;
44
45import org.junit.Before;
46import org.junit.Test;
47import org.junit.runner.RunWith;
48
49/**
50 * So far these tests only cover {@code NestedScrollView}'s implementation of
51 * {@link NestedScrollingParent2} and the backwards compatibility of {@code NestedScrollView}'s
52 * implementation of {@link androidx.core.view.NestedScrollingParent} for the methods that
53 * {@link NestedScrollingParent2} overloads.
54 */
55
56@RunWith(AndroidJUnit4.class)
57@SmallTest
58public class NestedScrollViewNestedScrollingParentTest extends
59        BaseInstrumentationTestCase<TestContentViewActivity> {
60
61    private NestedScrollView mNestedScrollView;
62    private NestedScrollingSpyView mParent;
63    private View mChild;
64
65    public NestedScrollViewNestedScrollingParentTest() {
66        super(TestContentViewActivity.class);
67    }
68
69    @Before
70    public void instantiateMembers() {
71        mNestedScrollView = new NestedScrollView(mActivityTestRule.getActivity());
72        mParent = spy(new NestedScrollingSpyView(mActivityTestRule.getActivity()));
73        mChild = new View(mActivityTestRule.getActivity());
74    }
75
76    @Test
77    public void onStartNestedScroll_scrollAxisIncludesVertical_alwaysReturnsTrue() {
78        int vertical = ViewCompat.SCROLL_AXIS_VERTICAL;
79        int both = ViewCompat.SCROLL_AXIS_VERTICAL | ViewCompat.SCROLL_AXIS_HORIZONTAL;
80
81        onStartNestedScrollV1(vertical, true);
82        onStartNestedScrollV1(both, true);
83
84        onStartNestedScrollV2(vertical, true);
85        onStartNestedScrollV2(both, true);
86    }
87
88    @Test
89    public void onStartNestedScroll_scrollAxisExcludesVertical_alwaysReturnsFalse() {
90        int horizontal = ViewCompat.SCROLL_AXIS_HORIZONTAL;
91        int neither = ViewCompat.SCROLL_AXIS_NONE;
92
93        onStartNestedScrollV1(horizontal, false);
94        onStartNestedScrollV1(neither, false);
95
96        onStartNestedScrollV2(horizontal, false);
97        onStartNestedScrollV2(neither, false);
98    }
99
100    @Test
101    public void onNestedScrollAccepted_callsParentsOnStartNestedScrollWithCorrectParams()
102            throws Throwable {
103        setupNestedScrollViewWithParentAndChild();
104        mActivityTestRule.runOnUiThread(new Runnable() {
105            @Override
106            public void run() {
107
108                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
109                        ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH);
110
111                verify(mParent).onStartNestedScroll(mNestedScrollView, mNestedScrollView,
112                        ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH);
113            }
114        });
115    }
116
117    @Test
118    public void onNestedScrollAccepted_callsParentsOnNestedScrollAcceptedWithCorrectParams()
119            throws Throwable {
120        setupNestedScrollViewWithParentAndChild();
121        mActivityTestRule.runOnUiThread(new Runnable() {
122            @Override
123            public void run() {
124                doReturn(true)
125                        .when(mParent)
126                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
127
128                mNestedScrollView.onNestedScrollAccepted(
129                        mChild,
130                        mChild,
131                        ViewCompat.SCROLL_AXIS_VERTICAL,
132                        ViewCompat.TYPE_NON_TOUCH);
133
134                    verify(mParent, times(1)).onNestedScrollAccepted(
135                            mNestedScrollView,
136                            mNestedScrollView,
137                            ViewCompat.SCROLL_AXIS_VERTICAL,
138                            ViewCompat.TYPE_NON_TOUCH);
139                    verify(mParent, times(1)).onNestedScrollAccepted(
140                            any(View.class),
141                            any(View.class),
142                            anyInt(),
143                            anyInt());
144            }
145        });
146    }
147
148    @Test
149    public void onNestedScrollAccepted_withBothOrientations_pOnNestedScrollAcceptedCalledWithVert()
150            throws Throwable {
151        setupNestedScrollViewWithParentAndChild();
152        mActivityTestRule.runOnUiThread(new Runnable() {
153            @Override
154            public void run() {
155                doReturn(true)
156                        .when(mParent)
157                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
158
159                mNestedScrollView.onNestedScrollAccepted(
160                        mChild,
161                        mChild,
162                        ViewCompat.SCROLL_AXIS_VERTICAL | ViewCompat.SCROLL_AXIS_HORIZONTAL,
163                        ViewCompat.TYPE_NON_TOUCH);
164
165                verify(mParent, times(1)).onNestedScrollAccepted(
166                        any(View.class),
167                        any(View.class),
168                        eq(ViewCompat.SCROLL_AXIS_VERTICAL),
169                        anyInt());
170                verify(mParent, times(1)).onNestedScrollAccepted(
171                        any(View.class),
172                        any(View.class),
173                        anyInt(),
174                        anyInt());
175
176            }
177        });
178    }
179
180    @Test
181    public void onNestedScrollAccepted_parentRejects_parentOnNestedScrollAcceptedNotCalled()
182            throws Throwable {
183        setupNestedScrollViewWithParentAndChild();
184        mActivityTestRule.runOnUiThread(new Runnable() {
185            @Override
186            public void run() {
187                doReturn(false)
188                        .when(mParent)
189                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
190
191                mNestedScrollView.onNestedScrollAccepted(
192                        mChild,
193                        mChild,
194                        ViewCompat.SCROLL_AXIS_VERTICAL,
195                        ViewCompat.TYPE_TOUCH);
196
197                verify(mParent, never()).onNestedScrollAccepted(
198                        any(View.class),
199                        any(View.class),
200                        anyInt(),
201                        anyInt());
202            }
203        });
204    }
205
206    @Test
207    public void onNestedScrollAccepted_v1_callsParentWithTypeTouch() throws Throwable {
208        setupNestedScrollViewWithParentAndChild();
209        mActivityTestRule.runOnUiThread(new Runnable() {
210            @Override
211            public void run() {
212                doReturn(true)
213                        .when(mParent)
214                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
215
216                mNestedScrollView.onNestedScrollAccepted(
217                        mChild,
218                        mChild,
219                        ViewCompat.SCROLL_AXIS_VERTICAL);
220
221                verify(mParent, times(1)).onNestedScrollAccepted(
222                        any(View.class),
223                        any(View.class),
224                        anyInt(),
225                        eq(ViewCompat.TYPE_TOUCH));
226                verify(mParent, times(1)).onNestedScrollAccepted(
227                        any(View.class),
228                        any(View.class),
229                        anyInt(),
230                        anyInt());
231            }
232        });
233    }
234
235    @Test
236    public void onStopNestedScroll_parentOnStopNestedScrollCalledWithCorrectParams()
237            throws Throwable {
238        setupNestedScrollViewWithParentAndChild();
239        mActivityTestRule.runOnUiThread(new Runnable() {
240            @Override
241            public void run() {
242                doReturn(true)
243                        .when(mParent)
244                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
245                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
246                            ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH);
247
248                mNestedScrollView.onStopNestedScroll(mChild, ViewCompat.TYPE_NON_TOUCH);
249
250                verify(mParent, times(1)).onStopNestedScroll(mNestedScrollView,
251                        ViewCompat.TYPE_NON_TOUCH);
252                verify(mParent, times(1)).onStopNestedScroll(any(View.class), anyInt());
253            }
254        });
255    }
256
257    // TODO(shepshapard), test with interactions where scroll type changes.
258
259    @Test
260    public void onStopNestedScroll_parentRejects_parentOnStopNestedScrollNotCalled()
261            throws Throwable {
262        setupNestedScrollViewWithParentAndChild();
263        mActivityTestRule.runOnUiThread(new Runnable() {
264            @Override
265            public void run() {
266                doReturn(false)
267                        .when(mParent)
268                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
269                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
270                        ViewCompat.SCROLL_AXIS_VERTICAL);
271
272                mNestedScrollView.onStopNestedScroll(mChild, ViewCompat.TYPE_NON_TOUCH);
273
274                verify(mParent, never()).onStopNestedScroll(any(View.class), anyInt());
275            }
276        });
277    }
278
279    @Test
280    public void onStopNestedScroll_calledWithTypeNotYetAccepted_parentOnStopNestedScrollNotCalled()
281            throws Throwable {
282        setupNestedScrollViewWithParentAndChild();
283        mActivityTestRule.runOnUiThread(new Runnable() {
284            @Override
285            public void run() {
286                doReturn(true)
287                        .when(mParent)
288                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
289                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
290                        ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH);
291
292                mNestedScrollView.onStopNestedScroll(mChild, ViewCompat.TYPE_NON_TOUCH);
293
294                verify(mParent, never()).onStopNestedScroll(any(View.class), anyInt());
295            }
296        });
297    }
298
299    @Test
300    public void onStopNestedScroll_v1_parentOnStopNestedScrollCalledWithTypeTouch()
301            throws Throwable {
302        setupNestedScrollViewWithParentAndChild();
303        mActivityTestRule.runOnUiThread(new Runnable() {
304            @Override
305            public void run() {
306                doReturn(true)
307                        .when(mParent)
308                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
309                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
310                        ViewCompat.SCROLL_AXIS_VERTICAL);
311
312                mNestedScrollView.onStopNestedScroll(mChild);
313
314                verify(mParent, times(1)).onStopNestedScroll(any(View.class),
315                        eq(ViewCompat.TYPE_TOUCH));
316                verify(mParent, times(1)).onStopNestedScroll(any(View.class), anyInt());
317            }
318        });
319    }
320
321    @Test
322    public void onNestedScroll_nsvScrolls() throws Throwable {
323        setupNestedScrollViewWithParentAndChild(50, 100);
324        mActivityTestRule.runOnUiThread(new Runnable() {
325            @Override
326            public void run() {
327
328                mNestedScrollView.onNestedScroll(mChild, 0, 0, 0, 50, ViewCompat.TYPE_NON_TOUCH);
329
330                assertThat(mNestedScrollView.getScrollY(), is(50));
331            }
332        });
333    }
334
335    @Test
336    public void onNestedScroll_negativeScroll_nsvScrollsNegative() throws Throwable {
337        setupNestedScrollViewWithParentAndChild(50, 100);
338        mActivityTestRule.runOnUiThread(new Runnable() {
339            @Override
340            public void run() {
341                mNestedScrollView.scrollTo(0, 50);
342
343                mNestedScrollView.onNestedScroll(mChild, 0, 0, 0, -50, ViewCompat.TYPE_NON_TOUCH);
344
345                assertThat(mNestedScrollView.getScrollY(), is(0));
346            }
347        });
348    }
349
350    @Test
351    public void onNestedScroll_nsvConsumesEntireScroll_correctScrollDistancesPastToParent()
352            throws Throwable {
353        setupNestedScrollViewWithParentAndChild(50, 100);
354        mActivityTestRule.runOnUiThread(new Runnable() {
355            @Override
356            public void run() {
357                doReturn(true)
358                        .when(mParent)
359                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
360                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
361                        ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH);
362
363                mNestedScrollView.onNestedScroll(mChild, 0, 0, 0, 50, ViewCompat.TYPE_NON_TOUCH);
364
365                verify(mParent, times(1)).onNestedScroll(any(View.class), eq(0), eq(50), eq(0),
366                        eq(0), anyInt());
367                verify(mParent, times(1)).onNestedScroll(any(View.class), anyInt(), anyInt(),
368                        anyInt(), anyInt(), anyInt());
369            }
370        });
371    }
372
373    @Test
374    public void onNestedScroll_nsvCanOnlyConsumePartOfScroll_correctScrollDistancesPastToParent()
375            throws Throwable {
376        setupNestedScrollViewWithParentAndChild(50, 100);
377        mActivityTestRule.runOnUiThread(new Runnable() {
378            @Override
379            public void run() {
380                doReturn(true)
381                        .when(mParent)
382                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
383                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
384                        ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH);
385                mNestedScrollView.onNestedScroll(mChild, 0, 0, 0, 75, ViewCompat.TYPE_NON_TOUCH);
386
387                verify(mParent, times(1)).onNestedScroll(any(View.class), eq(0), eq(50), eq(0),
388                        eq(25), anyInt());
389                verify(mParent, times(1)).onNestedScroll(any(View.class), anyInt(), anyInt(),
390                        anyInt(), anyInt(), anyInt());
391            }
392        });
393    }
394
395    @Test
396    public void onNestedScroll_nsvCanOnlyConsumePartOfScrollNeg_correctScrollDistancesPastToParent()
397            throws Throwable {
398        setupNestedScrollViewWithParentAndChild(50, 100);
399        mActivityTestRule.runOnUiThread(new Runnable() {
400            @Override
401            public void run() {
402                doReturn(true)
403                        .when(mParent)
404                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
405                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
406                        ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH);
407                mNestedScrollView.scrollTo(0, 50);
408
409                mNestedScrollView.onNestedScroll(mChild, 0, 0, 0, -75, ViewCompat.TYPE_NON_TOUCH);
410
411                verify(mParent, times(1)).onNestedScroll(any(View.class), eq(0), eq(-50), eq(0),
412                        eq(-25), anyInt());
413                verify(mParent, times(1)).onNestedScroll(any(View.class), anyInt(), anyInt(),
414                        anyInt(), anyInt(), anyInt());
415            }
416        });
417    }
418
419    @Test
420    public void onNestedScroll_nsvIsAtEndOfScroll_correctScrollDistancesPastToParent()
421            throws Throwable {
422        setupNestedScrollViewWithParentAndChild(50, 100);
423        mActivityTestRule.runOnUiThread(new Runnable() {
424            @Override
425            public void run() {
426                doReturn(true)
427                        .when(mParent)
428                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
429                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
430                        ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH);
431                mNestedScrollView.scrollTo(0, 50);
432
433                mNestedScrollView.onNestedScroll(mChild, 0, 0, 0, 50, ViewCompat.TYPE_NON_TOUCH);
434
435                verify(mParent, times(1)).onNestedScroll(any(View.class), eq(0), eq(0), eq(0),
436                        eq(50), anyInt());
437                verify(mParent, times(1)).onNestedScroll(any(View.class), anyInt(), anyInt(),
438                        anyInt(), anyInt(), anyInt());
439            }
440        });
441    }
442
443    @Test
444    public void onNestedScroll_parentRejects_parentOnNestedScrollNotCalled() throws Throwable {
445        setupNestedScrollViewWithParentAndChild(50, 100);
446        mActivityTestRule.runOnUiThread(new Runnable() {
447            @Override
448            public void run() {
449                doReturn(false)
450                        .when(mParent)
451                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
452                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
453                        ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH);
454
455                mNestedScrollView.onNestedScroll(mChild, 0, 0, 0, 50, ViewCompat.TYPE_NON_TOUCH);
456
457                verify(mParent, never()).onNestedScroll(any(View.class), anyInt(), anyInt(),
458                        anyInt(), anyInt(), anyInt());
459            }
460        });
461    }
462
463    @Test
464    public void onNestedScroll_calledWithTypeNotYetAccepted_parentOnStopNestedScrollNotCalled()
465            throws Throwable {
466        setupNestedScrollViewWithParentAndChild(50, 100);
467        mActivityTestRule.runOnUiThread(new Runnable() {
468            @Override
469            public void run() {
470                doReturn(true)
471                        .when(mParent)
472                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
473                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
474                        ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH);
475
476                mNestedScrollView.onNestedScroll(mChild, 0, 0, 0, 50, ViewCompat.TYPE_NON_TOUCH);
477
478                verify(mParent, never()).onNestedScroll(any(View.class), anyInt(), anyInt(),
479                        anyInt(), anyInt(), anyInt());
480            }
481        });
482    }
483
484    @Test
485    public void onNestedScroll_v1_parentOnNestedScrollCalledWithTypeTouch()
486            throws Throwable {
487        setupNestedScrollViewWithParentAndChild(50, 100);
488        mActivityTestRule.runOnUiThread(new Runnable() {
489            @Override
490            public void run() {
491                doReturn(true)
492                        .when(mParent)
493                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
494                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
495                        ViewCompat.SCROLL_AXIS_VERTICAL);
496
497                mNestedScrollView.onNestedScroll(mChild, 0, 0, 0, 50);
498
499                verify(mParent, times(1)).onNestedScroll(any(View.class), anyInt(), anyInt(),
500                        anyInt(), anyInt(), eq(ViewCompat.TYPE_TOUCH));
501                verify(mParent, times(1)).onNestedScroll(any(View.class), anyInt(), anyInt(),
502                        anyInt(), anyInt(), anyInt());
503            }
504        });
505    }
506
507    @Test
508    public void onNestedPreScroll_parentOnNestedPreScrollCalledWithCorrectParams()
509            throws Throwable {
510        setupNestedScrollViewWithParentAndChild();
511        mActivityTestRule.runOnUiThread(new Runnable() {
512            @Override
513            public void run() {
514                doReturn(true)
515                        .when(mParent)
516                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
517                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
518                        ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH);
519
520                mNestedScrollView.onNestedPreScroll(mChild, 1, 2, new int[]{0, 0},
521                        ViewCompat.TYPE_NON_TOUCH);
522
523                verify(mParent, times(1)).onNestedPreScroll(eq(mNestedScrollView), eq(1), eq(2),
524                        eq(new int[]{0, 0}), eq(ViewCompat.TYPE_NON_TOUCH));
525                verify(mParent, times(1)).onNestedPreScroll(any(View.class), anyInt(), anyInt(),
526                        any(int[].class), anyInt());
527            }
528        });
529    }
530
531    @Test
532    public void onNestedPreScroll_parentRejects_parentOnNestedPreScrollNotCalled()
533            throws Throwable {
534        setupNestedScrollViewWithParentAndChild();
535        mActivityTestRule.runOnUiThread(new Runnable() {
536            @Override
537            public void run() {
538                doReturn(false)
539                        .when(mParent)
540                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
541                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
542                        ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH);
543
544                mNestedScrollView.onNestedPreScroll(mChild, 1, 2, new int[2],
545                        ViewCompat.TYPE_NON_TOUCH);
546
547                verify(mParent, never()).onNestedPreScroll(any(View.class), anyInt(), anyInt(),
548                        any(int[].class), anyInt());
549            }
550        });
551    }
552
553    @Test
554    public void onNestedPreScroll_calledWithTypeNotYetAccepted_parentOnStopNestedScrollNotCalled()
555            throws Throwable {
556        setupNestedScrollViewWithParentAndChild();
557        mActivityTestRule.runOnUiThread(new Runnable() {
558            @Override
559            public void run() {
560                doReturn(true)
561                        .when(mParent)
562                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
563                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
564                        ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH);
565
566                mNestedScrollView.onNestedPreScroll(mChild, 1, 2, new int[2],
567                        ViewCompat.TYPE_NON_TOUCH);
568
569                verify(mParent, never()).onNestedPreScroll(any(View.class), anyInt(), anyInt(),
570                        any(int[].class), anyInt());
571            }
572        });
573    }
574
575    @Test
576    public void onNestedPreScroll_v1_parentOnNestedPreScrollCalledWithTypeTouch() throws Throwable {
577        setupNestedScrollViewWithParentAndChild();
578        mActivityTestRule.runOnUiThread(new Runnable() {
579            @Override
580            public void run() {
581                doReturn(true)
582                        .when(mParent)
583                        .onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt());
584                mNestedScrollView.onNestedScrollAccepted(mChild, mChild,
585                        ViewCompat.SCROLL_AXIS_VERTICAL);
586                int[] consumed = new int[2];
587
588                mNestedScrollView.onNestedPreScroll(mChild, 1, 2, consumed);
589
590                verify(mParent, times(1)).onNestedPreScroll(any(View.class), anyInt(), anyInt(),
591                        any(int[].class), eq(ViewCompat.TYPE_TOUCH));
592                verify(mParent, times(1)).onNestedPreScroll(any(View.class), anyInt(), anyInt(),
593                        any(int[].class), anyInt());
594            }
595        });
596    }
597
598    private void onStartNestedScrollV1(int iScrollAxis, boolean oRetValue) {
599        boolean retVal = mNestedScrollView.onStartNestedScroll(mChild, mChild, iScrollAxis);
600        assertThat(retVal, is(oRetValue));
601    }
602
603    private void onStartNestedScrollV2(int iScrollAxis, boolean oRetValue) {
604        boolean retVal = mNestedScrollView.onStartNestedScroll(mChild, mChild, iScrollAxis,
605                ViewCompat.TYPE_TOUCH);
606        assertThat(retVal, is(oRetValue));
607    }
608
609    private void setupNestedScrollViewWithParentAndChild() throws Throwable {
610        setupNestedScrollViewWithParentAndChild(ViewGroup.LayoutParams.MATCH_PARENT,
611                ViewGroup.LayoutParams.MATCH_PARENT);
612    }
613
614    private void setupNestedScrollViewWithParentAndChild(int nestedScrollViewHeight,
615            int childHeight) throws Throwable {
616        final TestContentView testContentView =
617                mActivityTestRule.getActivity().findViewById(R.id.testContentView);
618
619        mNestedScrollView.setLayoutParams(new ViewGroup.LayoutParams(
620                ViewGroup.LayoutParams.MATCH_PARENT, nestedScrollViewHeight));
621        mNestedScrollView.setMinimumHeight(nestedScrollViewHeight);
622
623        mChild.setLayoutParams(new ViewGroup.LayoutParams(
624                ViewGroup.LayoutParams.MATCH_PARENT, childHeight));
625        mChild.setMinimumHeight(childHeight);
626
627        testContentView.expectLayouts(1);
628        mActivityTestRule.runOnUiThread(new Runnable() {
629            @Override
630            public void run() {
631                mNestedScrollView.addView(mChild);
632                mParent.addView(mNestedScrollView);
633                testContentView.addView(mParent);
634            }
635        });
636        testContentView.awaitLayouts(2);
637    }
638
639    public class NestedScrollingSpyView extends FrameLayout implements NestedScrollingChild2,
640            NestedScrollingParent2 {
641
642        public NestedScrollingSpyView(Context context) {
643            super(context);
644        }
645
646        @Override
647        public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes,
648                int type) {
649            return false;
650        }
651
652        @Override
653        public void onNestedScrollAccepted(@NonNull View child, @NonNull View target, int axes,
654                int type) {
655
656        }
657
658        @Override
659        public void onStopNestedScroll(@NonNull View target, int type) {
660
661        }
662
663        @Override
664        public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed,
665                int dxUnconsumed, int dyUnconsumed, int type) {
666
667        }
668
669        @Override
670        public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed,
671                int type) {
672
673        }
674
675        @Override
676        public boolean startNestedScroll(int axes, int type) {
677            return false;
678        }
679
680        @Override
681        public void stopNestedScroll(int type) {
682
683        }
684
685        @Override
686        public boolean hasNestedScrollingParent(int type) {
687            return false;
688        }
689
690        @Override
691        public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
692                int dyUnconsumed, @Nullable int[] offsetInWindow, int type) {
693            return false;
694        }
695
696        @Override
697        public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,
698                @Nullable int[] offsetInWindow, int type) {
699            return false;
700        }
701
702        @Override
703        public void setNestedScrollingEnabled(boolean enabled) {
704
705        }
706
707        @Override
708        public boolean isNestedScrollingEnabled() {
709            return false;
710        }
711
712        @Override
713        public boolean startNestedScroll(int axes) {
714            return false;
715        }
716
717        @Override
718        public void stopNestedScroll() {
719
720        }
721
722        @Override
723        public boolean hasNestedScrollingParent() {
724            return false;
725        }
726
727        @Override
728        public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
729                int dyUnconsumed, int[] offsetInWindow) {
730            return false;
731        }
732
733        @Override
734        public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed,
735                int[] offsetInWindow) {
736            return false;
737        }
738
739        @Override
740        public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
741            return false;
742        }
743
744        @Override
745        public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
746            return false;
747        }
748
749        @Override
750        public boolean onStartNestedScroll(View child, View target, int axes) {
751            return false;
752        }
753
754        @Override
755        public void onNestedScrollAccepted(View child, View target, int axes) {
756
757        }
758
759        @Override
760        public void onStopNestedScroll(View target) {
761
762        }
763
764        @Override
765        public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed,
766                int dyUnconsumed) {
767
768        }
769
770        @Override
771        public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
772
773        }
774
775        @Override
776        public boolean onNestedFling(View target, float velocityX, float velocityY,
777                boolean consumed) {
778            return false;
779        }
780
781        @Override
782        public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
783            return false;
784        }
785
786        @Override
787        public int getNestedScrollAxes() {
788            return 0;
789        }
790    }
791
792}
793