Home | History | Annotate | Download | only in widget
      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 
     17 package androidx.core.widget;
     18 
     19 import static org.hamcrest.CoreMatchers.is;
     20 import static org.hamcrest.MatcherAssert.assertThat;
     21 import static org.mockito.ArgumentMatchers.any;
     22 import static org.mockito.ArgumentMatchers.anyInt;
     23 import static org.mockito.ArgumentMatchers.eq;
     24 import static org.mockito.Mockito.doReturn;
     25 import static org.mockito.Mockito.never;
     26 import static org.mockito.Mockito.spy;
     27 import static org.mockito.Mockito.times;
     28 import static org.mockito.Mockito.verify;
     29 
     30 import android.content.Context;
     31 import android.support.test.filters.SmallTest;
     32 import android.support.test.runner.AndroidJUnit4;
     33 import android.support.v4.BaseInstrumentationTestCase;
     34 import android.view.View;
     35 import android.view.ViewGroup;
     36 import android.widget.FrameLayout;
     37 
     38 import androidx.annotation.NonNull;
     39 import androidx.annotation.Nullable;
     40 import androidx.core.test.R;
     41 import androidx.core.view.NestedScrollingChild2;
     42 import androidx.core.view.NestedScrollingParent2;
     43 import androidx.core.view.ViewCompat;
     44 
     45 import org.junit.Before;
     46 import org.junit.Test;
     47 import 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
     58 public 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