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.recyclerview.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.anyBoolean; 23 import static org.mockito.ArgumentMatchers.anyFloat; 24 import static org.mockito.ArgumentMatchers.anyInt; 25 import static org.mockito.ArgumentMatchers.eq; 26 import static org.mockito.Mockito.doAnswer; 27 import static org.mockito.Mockito.never; 28 import static org.mockito.Mockito.verify; 29 import static org.mockito.Mockito.when; 30 31 import android.content.Context; 32 import android.os.SystemClock; 33 import android.view.MotionEvent; 34 import android.view.View; 35 import android.view.ViewConfiguration; 36 import android.view.ViewGroup; 37 import android.widget.FrameLayout; 38 39 import androidx.core.view.NestedScrollingChild3; 40 import androidx.core.view.NestedScrollingParent3; 41 import androidx.core.view.ViewCompat; 42 import androidx.test.core.app.ApplicationProvider; 43 import androidx.test.ext.junit.runners.AndroidJUnit4; 44 import androidx.test.filters.LargeTest; 45 import androidx.testutils.Direction; 46 import androidx.testutils.FlingData; 47 import androidx.testutils.MotionEventData; 48 import androidx.testutils.SimpleGestureGeneratorKt; 49 50 import org.jspecify.annotations.NonNull; 51 import org.jspecify.annotations.Nullable; 52 import org.junit.Test; 53 import org.junit.runner.RunWith; 54 import org.mockito.InOrder; 55 import org.mockito.Mockito; 56 import org.mockito.invocation.InvocationOnMock; 57 import org.mockito.stubbing.Answer; 58 59 import java.util.List; 60 61 /** 62 * Small integration tests that verifies that {@link RecyclerView} interacts with the latest 63 * version of the nested scroll parents correctly. 64 */ 65 @RunWith(AndroidJUnit4.class) 66 @LargeTest 67 public class RecyclerViewNestedScrollingChildTest { 68 69 private NestedScrollingSpyView mParentSpy; 70 private RecyclerView mRecyclerView; 71 private int mTouchSlop; 72 setup(boolean vertical, int scrollDistance, boolean parentAccepts)73 private void setup(boolean vertical, int scrollDistance, boolean parentAccepts) { 74 75 Context context = ApplicationProvider.getApplicationContext(); 76 77 // Create views 78 79 mTouchSlop = ViewConfiguration.get( 80 ApplicationProvider.getApplicationContext()).getScaledTouchSlop(); 81 82 mRecyclerView = new RecyclerView(context); 83 mRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER); 84 mRecyclerView.setMinimumWidth(1000); 85 mRecyclerView.setMinimumHeight(1000); 86 87 mParentSpy = Mockito.spy(new NestedScrollingSpyView(context)); 88 mParentSpy.setMinimumWidth(1000); 89 mParentSpy.setMinimumHeight(1000); 90 91 // Setup RecyclerView 92 int orientation = vertical ? RecyclerView.VERTICAL : RecyclerView.HORIZONTAL; 93 mRecyclerView.setLayoutManager(new LinearLayoutManager(context, orientation, false)); 94 mRecyclerView.setAdapter(new TestAdapter(context, 1000 + scrollDistance, 1, vertical)); 95 96 // Create view hierarchy 97 mParentSpy.addView(mRecyclerView); 98 99 // Measure and layout 100 int measureSpecWidth = View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY); 101 int measureSpecHeight = View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY); 102 mParentSpy.measure(measureSpecWidth, measureSpecHeight); 103 mParentSpy.layout(0, 0, 1000, 1000); 104 105 when(mParentSpy.onStartNestedScroll(any(View.class), any(View.class), anyInt(), anyInt())) 106 .thenReturn(parentAccepts); 107 } 108 109 @Test uiFingerDown_vertical_parentHasNestedScrollingChildWithTypeTouch()110 public void uiFingerDown_vertical_parentHasNestedScrollingChildWithTypeTouch() { 111 setup(true, 100, true); 112 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 500, 500, 0); 113 114 mRecyclerView.dispatchTouchEvent(down); 115 116 assertThat(mParentSpy.axesForTypeTouch, is(ViewCompat.SCROLL_AXIS_VERTICAL)); 117 assertThat(mParentSpy.axesForTypeNonTouch, is(ViewCompat.SCROLL_AXIS_NONE)); 118 } 119 120 @Test uiFingerDown_horizontal_parentHasNestedScrollingChildWithTypeTouch()121 public void uiFingerDown_horizontal_parentHasNestedScrollingChildWithTypeTouch() { 122 setup(false, 100, true); 123 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 500, 500, 0); 124 125 mRecyclerView.dispatchTouchEvent(down); 126 127 assertThat(mParentSpy.axesForTypeTouch, is(ViewCompat.SCROLL_AXIS_HORIZONTAL)); 128 assertThat(mParentSpy.axesForTypeNonTouch, is(ViewCompat.SCROLL_AXIS_NONE)); 129 } 130 131 @Test uiFingerDown_parentRejects_parentDoesNotHaveNestedScrollingChild()132 public void uiFingerDown_parentRejects_parentDoesNotHaveNestedScrollingChild() { 133 setup(true, 100, false); 134 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 500, 500, 0); 135 136 mRecyclerView.dispatchTouchEvent(down); 137 138 assertThat(mParentSpy.axesForTypeTouch, is(ViewCompat.SCROLL_AXIS_NONE)); 139 assertThat(mParentSpy.axesForTypeNonTouch, is(ViewCompat.SCROLL_AXIS_NONE)); 140 } 141 142 @Test uiFingerUp_afterFingerDown_parentDoesNotHaveNestedScrollingChild()143 public void uiFingerUp_afterFingerDown_parentDoesNotHaveNestedScrollingChild() { 144 setup(true, 100, true); 145 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 500, 500, 0); 146 MotionEvent up = MotionEvent.obtain(0, 100, MotionEvent.ACTION_UP, 500, 500, 0); 147 mRecyclerView.dispatchTouchEvent(down); 148 149 mRecyclerView.dispatchTouchEvent(up); 150 151 assertThat(mParentSpy.axesForTypeTouch, is(ViewCompat.SCROLL_AXIS_NONE)); 152 assertThat(mParentSpy.axesForTypeNonTouch, is(ViewCompat.SCROLL_AXIS_NONE)); 153 } 154 155 @Test uiFingerScroll_vertical_parentOnNestedPreScrollCalledCorrectly()156 public void uiFingerScroll_vertical_parentOnNestedPreScrollCalledCorrectly() { 157 setup(true, 100, true); 158 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 500, 500, 0); 159 MotionEvent move = MotionEvent.obtain(0, 100, MotionEvent.ACTION_MOVE, 500, 300, 0); 160 161 mRecyclerView.dispatchTouchEvent(down); 162 mRecyclerView.dispatchTouchEvent(move); 163 164 // Can't verify 'consumed' parameter values due to mutation, so instead capturing actual 165 // values manually in the the NestedScrollingSpyView object. 166 verify(mParentSpy).onNestedPreScroll(eq(mRecyclerView), eq(0), eq(200 - mTouchSlop), 167 any(int[].class), eq(ViewCompat.TYPE_TOUCH)); 168 assertThat(mParentSpy.onNestedPreScrollConsumedX, is(0)); 169 assertThat(mParentSpy.onNestedPreScrollConsumedY, is(0)); 170 171 move = MotionEvent.obtain(0, 200, MotionEvent.ACTION_MOVE, 500, 300 - mTouchSlop / 2, 0); 172 mRecyclerView.dispatchTouchEvent(move); 173 174 verify(mParentSpy).onNestedPreScroll(eq(mRecyclerView), eq(0), eq(mTouchSlop / 2), 175 any(int[].class), eq(ViewCompat.TYPE_TOUCH)); 176 assertThat(mParentSpy.onNestedPreScrollConsumedX, is(0)); 177 assertThat(mParentSpy.onNestedPreScrollConsumedY, is(0)); 178 } 179 180 @Test uiFingerScroll_horizontal_parentOnNestedPreScrollCalledCorrectly()181 public void uiFingerScroll_horizontal_parentOnNestedPreScrollCalledCorrectly() { 182 setup(false, 100, true); 183 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 500, 500, 0); 184 MotionEvent move = MotionEvent.obtain(0, 100, MotionEvent.ACTION_MOVE, 300, 500, 0); 185 186 mRecyclerView.dispatchTouchEvent(down); 187 mRecyclerView.dispatchTouchEvent(move); 188 189 // Can't verify 'consumed' parameter values due to mutation, so instead capturing actual 190 // values manually in the the NestedScrollingSpyView object. 191 verify(mParentSpy).onNestedPreScroll(eq(mRecyclerView), eq(200 - mTouchSlop), eq(0), 192 any(int[].class), eq(ViewCompat.TYPE_TOUCH)); 193 assertThat(mParentSpy.onNestedPreScrollConsumedX, is(0)); 194 assertThat(mParentSpy.onNestedPreScrollConsumedY, is(0)); 195 196 move = MotionEvent.obtain(0, 200, MotionEvent.ACTION_MOVE, 300 - mTouchSlop / 2, 500, 0); 197 mRecyclerView.dispatchTouchEvent(move); 198 199 verify(mParentSpy).onNestedPreScroll(eq(mRecyclerView), eq(mTouchSlop / 2), eq(0), 200 any(int[].class), eq(ViewCompat.TYPE_TOUCH)); 201 assertThat(mParentSpy.onNestedPreScrollConsumedX, is(0)); 202 assertThat(mParentSpy.onNestedPreScrollConsumedY, is(0)); 203 } 204 205 @Test uiFingerScroll_scrollsBeyondLimitVertical_parentOnNestedScrollCalledCorrectly()206 public void uiFingerScroll_scrollsBeyondLimitVertical_parentOnNestedScrollCalledCorrectly() { 207 setup(true, 100, true); 208 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 500, 500, 0); 209 MotionEvent move = 210 MotionEvent.obtain(0, 100, MotionEvent.ACTION_MOVE, 500, 300 - mTouchSlop, 0); 211 212 mParentSpy.dispatchTouchEvent(down); 213 mParentSpy.dispatchTouchEvent(move); 214 215 verify(mParentSpy).onNestedScroll(mRecyclerView, 0, 100, 0, 100, ViewCompat.TYPE_TOUCH, 216 new int[]{0, 0}); 217 } 218 219 @Test uiFingerScroll_scrollsBeyondLimitHorizontal_parentOnNestedScrollCalledCorrectly()220 public void uiFingerScroll_scrollsBeyondLimitHorizontal_parentOnNestedScrollCalledCorrectly() { 221 setup(false, 100, true); 222 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 500, 500, 0); 223 MotionEvent move = 224 MotionEvent.obtain(0, 100, MotionEvent.ACTION_MOVE, 300 - mTouchSlop, 500, 0); 225 226 mParentSpy.dispatchTouchEvent(down); 227 mParentSpy.dispatchTouchEvent(move); 228 229 verify(mParentSpy).onNestedScroll(mRecyclerView, 100, 0, 100, 0, ViewCompat.TYPE_TOUCH, 230 new int[]{0, 0}); 231 } 232 233 @Test uiFingerScroll_scrollsWithinLimitVertical_parentOnNestedScrollCalledCorrectly()234 public void uiFingerScroll_scrollsWithinLimitVertical_parentOnNestedScrollCalledCorrectly() { 235 setup(true, 100, true); 236 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 500, 500, 0); 237 MotionEvent move = 238 MotionEvent.obtain(0, 100, MotionEvent.ACTION_MOVE, 500, 450 - mTouchSlop, 0); 239 240 mParentSpy.dispatchTouchEvent(down); 241 mParentSpy.dispatchTouchEvent(move); 242 243 verify(mParentSpy).onNestedScroll(mRecyclerView, 0, 50, 0, 0, ViewCompat.TYPE_TOUCH, 244 new int[]{0, 0}); 245 } 246 247 @Test uiFingerScroll_scrollsWithinLimitHorizontal_parentOnNestedScrollCalledCorrectly()248 public void uiFingerScroll_scrollsWithinLimitHorizontal_parentOnNestedScrollCalledCorrectly() { 249 setup(false, 100, true); 250 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 500, 500, 0); 251 MotionEvent move = 252 MotionEvent.obtain(0, 100, MotionEvent.ACTION_MOVE, 450 - mTouchSlop, 500, 0); 253 254 mParentSpy.dispatchTouchEvent(down); 255 mParentSpy.dispatchTouchEvent(move); 256 257 verify(mParentSpy).onNestedScroll(mRecyclerView, 50, 0, 0, 0, ViewCompat.TYPE_TOUCH, 258 new int[]{0, 0}); 259 } 260 261 @Test uiFingerScroll_vertical_preSelfPostChainWorks()262 public void uiFingerScroll_vertical_preSelfPostChainWorks() { 263 setup(true, 100, true); 264 doAnswer(new Answer() { 265 public Object answer(InvocationOnMock invocation) { 266 Object[] args = invocation.getArguments(); 267 ((int[]) args[3])[1] = 50; 268 return null; 269 } 270 }).when(mParentSpy) 271 .onNestedPreScroll(any(View.class), anyInt(), anyInt(), any(int[].class), anyInt()); 272 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 500, 500, 0); 273 MotionEvent move = 274 MotionEvent.obtain(0, 100, MotionEvent.ACTION_MOVE, 500, 300, 0); 275 276 mRecyclerView.dispatchTouchEvent(down); 277 mRecyclerView.dispatchTouchEvent(move); 278 279 // Can't verify 'consumed' parameter values due to mutation, so instead capturing actual 280 // values manually in the the NestedScrollingSpyView object. 281 verify(mParentSpy).onNestedPreScroll(eq(mRecyclerView), eq(0), eq(200 - mTouchSlop), 282 any(int[].class), eq(ViewCompat.TYPE_TOUCH)); 283 assertThat(mParentSpy.onNestedPreScrollConsumedX, is(0)); 284 assertThat(mParentSpy.onNestedPreScrollConsumedY, is(0)); 285 286 verify(mParentSpy).onNestedScroll(mRecyclerView, 0, 100, 0, 50 - mTouchSlop, 287 ViewCompat.TYPE_TOUCH, new int[]{0, 0}); 288 } 289 290 @Test uiFingerScroll_horizontal_preSelfPostChainWorks()291 public void uiFingerScroll_horizontal_preSelfPostChainWorks() { 292 setup(false, 100, true); 293 doAnswer(new Answer() { 294 public Object answer(InvocationOnMock invocation) { 295 Object[] args = invocation.getArguments(); 296 ((int[]) args[3])[0] = 50; 297 return null; 298 } 299 }).when(mParentSpy) 300 .onNestedPreScroll(any(View.class), anyInt(), anyInt(), any(int[].class), anyInt()); 301 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 500, 500, 0); 302 MotionEvent move = MotionEvent.obtain(0, 100, MotionEvent.ACTION_MOVE, 300, 500, 0); 303 304 mRecyclerView.dispatchTouchEvent(down); 305 mRecyclerView.dispatchTouchEvent(move); 306 307 // Can't verify 'consumed' parameter values due to mutation, so instead capturing actual 308 // values manually in the the NestedScrollingSpyView object. 309 verify(mParentSpy).onNestedPreScroll(eq(mRecyclerView), eq(200 - mTouchSlop), eq(0), 310 any(int[].class), eq(ViewCompat.TYPE_TOUCH)); 311 assertThat(mParentSpy.onNestedPreScrollConsumedX, is(0)); 312 assertThat(mParentSpy.onNestedPreScrollConsumedY, is(0)); 313 314 verify(mParentSpy).onNestedScroll(mRecyclerView, 100, 0, 50 - mTouchSlop, 0, 315 ViewCompat.TYPE_TOUCH, new int[]{0, 0}); 316 } 317 318 @Test uiFling_vertical_parentHasNestedScrollingChildWithTypeFling()319 public void uiFling_vertical_parentHasNestedScrollingChildWithTypeFling() { 320 setup(true, 100, true); 321 long startTime = SystemClock.uptimeMillis(); 322 323 SimpleGestureGeneratorKt 324 .simulateFling(mRecyclerView, startTime, 500, 500, Direction.UP); 325 326 assertThat(mParentSpy.axesForTypeTouch, is(ViewCompat.SCROLL_AXIS_NONE)); 327 assertThat(mParentSpy.axesForTypeNonTouch, is(ViewCompat.SCROLL_AXIS_VERTICAL)); 328 } 329 330 @Test uiFling_horizontal_parentHasNestedScrollingChildWithTypeFling()331 public void uiFling_horizontal_parentHasNestedScrollingChildWithTypeFling() { 332 setup(false, 100, true); 333 long startTime = SystemClock.uptimeMillis(); 334 335 SimpleGestureGeneratorKt 336 .simulateFling(mRecyclerView, startTime, 500, 500, Direction.LEFT); 337 338 assertThat(mParentSpy.axesForTypeTouch, is(ViewCompat.SCROLL_AXIS_NONE)); 339 assertThat(mParentSpy.axesForTypeNonTouch, is(ViewCompat.SCROLL_AXIS_HORIZONTAL)); 340 } 341 342 @Test uiFling_callsNestedFlingsCorrectly()343 public void uiFling_callsNestedFlingsCorrectly() { 344 setup(true, 100, true); 345 long startTime = SystemClock.uptimeMillis(); 346 347 SimpleGestureGeneratorKt 348 .simulateFling(mRecyclerView, startTime, 500, 500, Direction.UP); 349 350 InOrder inOrder = Mockito.inOrder(mParentSpy); 351 inOrder.verify(mParentSpy).onNestedPreFling( 352 eq(mRecyclerView), 353 eq(0f), 354 anyFloat()); 355 inOrder.verify(mParentSpy).onNestedFling( 356 eq(mRecyclerView), 357 eq(0f), 358 anyFloat(), 359 eq(true)); 360 } 361 362 @Test uiDown_duringFling_stopsNestedScrolling()363 public void uiDown_duringFling_stopsNestedScrolling() { 364 365 // Arrange 366 367 setup(true, 1000, true); 368 369 final Context context = ApplicationProvider.getApplicationContext(); 370 FlingData flingData = SimpleGestureGeneratorKt.generateFlingData(context); 371 372 final long firstDownTime = SystemClock.uptimeMillis(); 373 // Should be after fling events occurred. 374 final long secondDownTime = firstDownTime + flingData.getTime() + 100; 375 376 List<MotionEventData> motionEventData = SimpleGestureGeneratorKt 377 .generateFlingMotionEventData(flingData, 500, 500, Direction.UP); 378 SimpleGestureGeneratorKt 379 .dispatchTouchEvents(mRecyclerView, firstDownTime, motionEventData); 380 381 // Assumption check that onStopNestedScroll has not yet been called of type TYPE_NON_TOUCH. 382 verify(mParentSpy, never()) 383 .onStopNestedScroll(mRecyclerView, ViewCompat.TYPE_NON_TOUCH); 384 385 // Act 386 387 MotionEvent down = MotionEvent.obtain( 388 secondDownTime, 389 secondDownTime, 390 MotionEvent.ACTION_DOWN, 391 500, 392 500, 393 0); 394 mRecyclerView.dispatchTouchEvent(down); 395 396 // Assert 397 398 verify(mParentSpy).onStopNestedScroll(mRecyclerView, ViewCompat.TYPE_NON_TOUCH); 399 } 400 401 @Test uiFlings_parentReturnsFalseForOnNestedPreFling_onNestedFlingCalled()402 public void uiFlings_parentReturnsFalseForOnNestedPreFling_onNestedFlingCalled() { 403 uiFlings_returnValueOfOnNestedPreFlingDeterminesCallToOnNestedFling(false, true); 404 } 405 406 @Test uiFlings_parentReturnsTrueForOnNestedPreFling_onNestedFlingNotCalled()407 public void uiFlings_parentReturnsTrueForOnNestedPreFling_onNestedFlingNotCalled() { 408 uiFlings_returnValueOfOnNestedPreFlingDeterminesCallToOnNestedFling(true, false); 409 } 410 uiFlings_returnValueOfOnNestedPreFlingDeterminesCallToOnNestedFling( boolean returnValue, boolean onNestedFlingCalled)411 private void uiFlings_returnValueOfOnNestedPreFlingDeterminesCallToOnNestedFling( 412 boolean returnValue, boolean onNestedFlingCalled) { 413 setup(true, 100, true); 414 when(mParentSpy.onNestedPreFling(eq(mRecyclerView), anyFloat(), anyFloat())) 415 .thenReturn(returnValue); 416 417 long startTime = SystemClock.uptimeMillis(); 418 SimpleGestureGeneratorKt 419 .simulateFling(mRecyclerView, startTime, 500, 500, Direction.UP); 420 421 if (onNestedFlingCalled) { 422 verify(mParentSpy).onNestedFling(eq(mRecyclerView), anyFloat(), anyFloat(), eq(true)); 423 } else { 424 verify(mParentSpy, never()).onNestedFling(any(View.class), anyFloat(), anyFloat(), 425 anyBoolean()); 426 } 427 } 428 429 @Test smoothScrollBy_doesNotStartNestedScrolling()430 public void smoothScrollBy_doesNotStartNestedScrolling() { 431 setup(true, 100, true); 432 mRecyclerView.smoothScrollBy(0, 100); 433 verify(mParentSpy, never()).onStartNestedScroll( 434 any(View.class), any(View.class), anyInt(), anyInt()); 435 } 436 437 public class NestedScrollingSpyView extends FrameLayout implements NestedScrollingChild3, 438 NestedScrollingParent3 { 439 440 public int axesForTypeTouch; 441 public int axesForTypeNonTouch; 442 public int onNestedPreScrollConsumedX; 443 public int onNestedPreScrollConsumedY; 444 NestedScrollingSpyView(Context context)445 public NestedScrollingSpyView(Context context) { 446 super(context); 447 } 448 449 @Override onStartNestedScroll(@onNull View child, @NonNull View target, int axes, int type)450 public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes, 451 int type) { 452 return false; 453 } 454 455 @Override onNestedScrollAccepted(@onNull View child, @NonNull View target, int axes, int type)456 public void onNestedScrollAccepted(@NonNull View child, @NonNull View target, int axes, 457 int type) { 458 if (type == ViewCompat.TYPE_NON_TOUCH) { 459 axesForTypeNonTouch = axes; 460 } else { 461 axesForTypeTouch = axes; 462 } 463 } 464 465 @Override onStopNestedScroll(@onNull View target, int type)466 public void onStopNestedScroll(@NonNull View target, int type) { 467 if (type == ViewCompat.TYPE_NON_TOUCH) { 468 axesForTypeNonTouch = ViewCompat.SCROLL_AXIS_NONE; 469 } else { 470 axesForTypeTouch = ViewCompat.SCROLL_AXIS_NONE; 471 } 472 } 473 474 @Override onNestedScroll(@onNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type)475 public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, 476 int dxUnconsumed, int dyUnconsumed, int type) { 477 478 } 479 480 @Override onNestedPreScroll(@onNull View target, int dx, int dy, int @NonNull [] consumed, int type)481 public void onNestedPreScroll(@NonNull View target, int dx, int dy, 482 int @NonNull [] consumed, int type) { 483 onNestedPreScrollConsumedX = consumed[0]; 484 onNestedPreScrollConsumedY = consumed[1]; 485 } 486 487 @Override startNestedScroll(int axes, int type)488 public boolean startNestedScroll(int axes, int type) { 489 return false; 490 } 491 492 @Override stopNestedScroll(int type)493 public void stopNestedScroll(int type) { 494 495 } 496 497 @Override hasNestedScrollingParent(int type)498 public boolean hasNestedScrollingParent(int type) { 499 return false; 500 } 501 502 @Override dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int @Nullable [] offsetInWindow, int type)503 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, 504 int dyUnconsumed, int @Nullable [] offsetInWindow, int type) { 505 return false; 506 } 507 508 @Override dispatchNestedPreScroll(int dx, int dy, int @Nullable [] consumed, int @Nullable [] offsetInWindow, int type)509 public boolean dispatchNestedPreScroll(int dx, int dy, int @Nullable [] consumed, 510 int @Nullable [] offsetInWindow, int type) { 511 return false; 512 } 513 514 @Override onNestedScroll(@onNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type, int @NonNull [] consumed)515 public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, 516 int dxUnconsumed, int dyUnconsumed, int type, int @NonNull [] consumed) { 517 } 518 519 @Override dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int @Nullable [] offsetInWindow, int type, int @NonNull [] consumed)520 public void dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, 521 int dyUnconsumed, int @Nullable [] offsetInWindow, int type, 522 int @NonNull [] consumed) { 523 } 524 525 @Override setNestedScrollingEnabled(boolean enabled)526 public void setNestedScrollingEnabled(boolean enabled) { 527 528 } 529 530 @Override isNestedScrollingEnabled()531 public boolean isNestedScrollingEnabled() { 532 return false; 533 } 534 535 @Override startNestedScroll(int axes)536 public boolean startNestedScroll(int axes) { 537 return false; 538 } 539 540 @Override stopNestedScroll()541 public void stopNestedScroll() { 542 543 } 544 545 @Override hasNestedScrollingParent()546 public boolean hasNestedScrollingParent() { 547 return false; 548 } 549 550 @Override dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow)551 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, 552 int dyUnconsumed, int[] offsetInWindow) { 553 return false; 554 } 555 556 @Override dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow)557 public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, 558 int[] offsetInWindow) { 559 return false; 560 } 561 562 @Override dispatchNestedFling(float velocityX, float velocityY, boolean consumed)563 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 564 return false; 565 } 566 567 @Override dispatchNestedPreFling(float velocityX, float velocityY)568 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 569 return false; 570 } 571 572 @Override onStartNestedScroll(@onNull View child, @NonNull View target, int axes)573 public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes) { 574 return false; 575 } 576 577 @Override onNestedScrollAccepted(@onNull View child, @NonNull View target, int axes)578 public void onNestedScrollAccepted(@NonNull View child, @NonNull View target, int axes) { 579 580 } 581 582 @Override onStopNestedScroll(@onNull View target)583 public void onStopNestedScroll(@NonNull View target) { 584 585 } 586 587 @Override onNestedScroll(@onNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)588 public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, 589 int dxUnconsumed, int dyUnconsumed) { 590 591 } 592 593 @Override onNestedPreScroll( @onNull View target, int dx, int dy, int @NonNull [] consumed)594 public void onNestedPreScroll( 595 @NonNull View target, int dx, int dy, int @NonNull [] consumed) { 596 597 } 598 599 @Override onNestedFling(@onNull View target, float velocityX, float velocityY, boolean consumed)600 public boolean onNestedFling(@NonNull View target, float velocityX, float velocityY, 601 boolean consumed) { 602 return false; 603 } 604 605 @Override onNestedPreFling(@onNull View target, float velocityX, float velocityY)606 public boolean onNestedPreFling(@NonNull View target, float velocityX, float velocityY) { 607 return false; 608 } 609 610 @Override getNestedScrollAxes()611 public int getNestedScrollAxes() { 612 return 0; 613 } 614 } 615 616 private class TestAdapter extends RecyclerView.Adapter<TestViewHolder> { 617 618 private Context mContext; 619 private int mOrientationSize; 620 private int mItemCount; 621 private boolean mVertical; 622 TestAdapter(Context context, float orientationSize, int itemCount, boolean vertical)623 TestAdapter(Context context, float orientationSize, int itemCount, boolean vertical) { 624 mContext = context; 625 mOrientationSize = (int) Math.floor(orientationSize / itemCount); 626 mItemCount = itemCount; 627 mVertical = vertical; 628 } 629 630 @Override onCreateViewHolder(@onNull ViewGroup parent, int viewType)631 public @NonNull TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 632 View view = new View(mContext); 633 634 int width; 635 int height; 636 if (mVertical) { 637 width = ViewGroup.LayoutParams.MATCH_PARENT; 638 height = mOrientationSize; 639 } else { 640 width = mOrientationSize; 641 height = ViewGroup.LayoutParams.MATCH_PARENT; 642 } 643 644 view.setLayoutParams(new ViewGroup.LayoutParams(width, height)); 645 view.setMinimumHeight(mOrientationSize); 646 return new TestViewHolder(view); 647 } 648 649 @Override onBindViewHolder(@onNull TestViewHolder holder, int position)650 public void onBindViewHolder(@NonNull TestViewHolder holder, int position) { 651 652 } 653 654 @Override getItemCount()655 public int getItemCount() { 656 return mItemCount; 657 } 658 } 659 660 private class TestViewHolder extends RecyclerView.ViewHolder { 661 TestViewHolder(View itemView)662 TestViewHolder(View itemView) { 663 super(itemView); 664 } 665 } 666 667 } 668