GridWidgetTest.java revision 38b880c10a1169c558c1b952e36d330780f21ba3
1/* 2 * Copyright (C) 2015 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 */ 16package androidx.leanback.widget; 17 18import static org.junit.Assert.assertEquals; 19import static org.junit.Assert.assertFalse; 20import static org.junit.Assert.assertNotNull; 21import static org.junit.Assert.assertNotSame; 22import static org.junit.Assert.assertNull; 23import static org.junit.Assert.assertSame; 24import static org.junit.Assert.assertTrue; 25import static org.mockito.Mockito.any; 26import static org.mockito.Mockito.anyInt; 27import static org.mockito.Mockito.mock; 28import static org.mockito.Mockito.timeout; 29import static org.mockito.Mockito.times; 30import static org.mockito.Mockito.verify; 31 32import android.content.Intent; 33import android.graphics.Canvas; 34import android.graphics.Color; 35import android.graphics.Rect; 36import android.graphics.drawable.ColorDrawable; 37import android.os.Build; 38import android.os.Parcelable; 39import android.support.test.InstrumentationRegistry; 40import android.support.test.filters.LargeTest; 41import android.support.test.filters.SdkSuppress; 42import android.support.test.rule.ActivityTestRule; 43import android.support.test.runner.AndroidJUnit4; 44import androidx.leanback.test.R; 45import androidx.leanback.testutils.PollingCheck; 46import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; 47import androidx.recyclerview.widget.DefaultItemAnimator; 48import androidx.recyclerview.widget.RecyclerView; 49import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate; 50import android.text.Selection; 51import android.text.Spannable; 52import android.util.DisplayMetrics; 53import android.util.SparseArray; 54import android.util.SparseIntArray; 55import android.util.TypedValue; 56import android.view.KeyEvent; 57import android.view.View; 58import android.view.ViewGroup; 59import android.widget.TextView; 60 61import org.junit.After; 62import org.junit.Rule; 63import org.junit.Test; 64import org.junit.rules.TestName; 65import org.junit.runner.RunWith; 66import org.mockito.Mockito; 67 68import java.util.ArrayList; 69import java.util.Arrays; 70import java.util.Comparator; 71import java.util.HashMap; 72import java.util.HashSet; 73 74@LargeTest 75@RunWith(AndroidJUnit4.class) 76public class GridWidgetTest { 77 78 private static final float DELTA = 1f; 79 private static final boolean HUMAN_DELAY = false; 80 private static final long WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS = 60000; 81 private static final int WAIT_FOR_LAYOUT_PASS_TIMEOUT_MS = 2000; 82 private static final int WAIT_FOR_ITEM_ANIMATION_FINISH_TIMEOUT_MS = 6000; 83 84 protected ActivityTestRule<GridActivity> mActivityTestRule; 85 protected GridActivity mActivity; 86 protected BaseGridView mGridView; 87 protected GridLayoutManager mLayoutManager; 88 private GridLayoutManager.OnLayoutCompleteListener mWaitLayoutListener; 89 protected int mOrientation; 90 protected int mNumRows; 91 protected int[] mRemovedItems; 92 93 private final Comparator<View> mRowSortComparator = new Comparator<View>() { 94 @Override 95 public int compare(View lhs, View rhs) { 96 if (mOrientation == BaseGridView.HORIZONTAL) { 97 return lhs.getLeft() - rhs.getLeft(); 98 } else { 99 return lhs.getTop() - rhs.getTop(); 100 } 101 }; 102 }; 103 104 /** 105 * Verify margins between items on same row are same. 106 */ 107 private final Runnable mVerifyLayout = new Runnable() { 108 @Override 109 public void run() { 110 verifyMargin(); 111 } 112 }; 113 114 @Rule public TestName testName = new TestName(); 115 116 public static void sendKey(int keyCode) { 117 InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(keyCode); 118 } 119 120 public static void sendRepeatedKeys(int repeats, int keyCode) { 121 for (int i = 0; i < repeats; i++) { 122 InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(keyCode); 123 } 124 } 125 126 private void humanDelay(int delay) throws InterruptedException { 127 if (HUMAN_DELAY) Thread.sleep(delay); 128 } 129 /** 130 * Change size of the Adapter and notifyDataSetChanged. 131 */ 132 private void changeArraySize(final int size) throws Throwable { 133 performAndWaitForAnimation(new Runnable() { 134 @Override 135 public void run() { 136 mActivity.changeArraySize(size); 137 } 138 }); 139 } 140 141 static String dumpGridView(BaseGridView gridView) { 142 return "findFocus:" + gridView.getRootView().findFocus() 143 + " isLayoutRequested:" + gridView.isLayoutRequested() 144 + " selectedPosition:" + gridView.getSelectedPosition() 145 + " adapter.itemCount:" + gridView.getAdapter().getItemCount() 146 + " itemAnimator.isRunning:" + gridView.getItemAnimator().isRunning() 147 + " scrollState:" + gridView.getScrollState(); 148 } 149 150 /** 151 * Change selected position. 152 */ 153 private void setSelectedPosition(final int position, final int scrollExtra) throws Throwable { 154 startWaitLayout(); 155 mActivityTestRule.runOnUiThread(new Runnable() { 156 @Override 157 public void run() { 158 mGridView.setSelectedPosition(position, scrollExtra); 159 } 160 }); 161 waitForLayout(false); 162 } 163 164 private void setSelectedPosition(final int position) throws Throwable { 165 setSelectedPosition(position, 0); 166 } 167 168 private void setSelectedPositionSmooth(final int position) throws Throwable { 169 mActivityTestRule.runOnUiThread(new Runnable() { 170 @Override 171 public void run() { 172 mGridView.setSelectedPositionSmooth(position); 173 } 174 }); 175 } 176 /** 177 * Scrolls using given key. 178 */ 179 protected void scroll(int key, Runnable verify) throws Throwable { 180 do { 181 if (verify != null) { 182 mActivityTestRule.runOnUiThread(verify); 183 } 184 sendRepeatedKeys(10, key); 185 try { 186 Thread.sleep(300); 187 } catch (InterruptedException ex) { 188 break; 189 } 190 } while (mGridView.getLayoutManager().isSmoothScrolling() 191 || mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE); 192 } 193 194 protected void scrollToBegin(Runnable verify) throws Throwable { 195 int key; 196 // first move to first column/row 197 if (mOrientation == BaseGridView.HORIZONTAL) { 198 key = KeyEvent.KEYCODE_DPAD_UP; 199 } else { 200 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 201 key = KeyEvent.KEYCODE_DPAD_RIGHT; 202 } else { 203 key = KeyEvent.KEYCODE_DPAD_LEFT; 204 } 205 } 206 scroll(key, null); 207 if (mOrientation == BaseGridView.HORIZONTAL) { 208 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 209 key = KeyEvent.KEYCODE_DPAD_RIGHT; 210 } else { 211 key = KeyEvent.KEYCODE_DPAD_LEFT; 212 } 213 } else { 214 key = KeyEvent.KEYCODE_DPAD_UP; 215 } 216 scroll(key, verify); 217 } 218 219 protected void scrollToEnd(Runnable verify) throws Throwable { 220 int key; 221 // first move to first column/row 222 if (mOrientation == BaseGridView.HORIZONTAL) { 223 key = KeyEvent.KEYCODE_DPAD_UP; 224 } else { 225 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 226 key = KeyEvent.KEYCODE_DPAD_RIGHT; 227 } else { 228 key = KeyEvent.KEYCODE_DPAD_LEFT; 229 } 230 } 231 scroll(key, null); 232 if (mOrientation == BaseGridView.HORIZONTAL) { 233 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 234 key = KeyEvent.KEYCODE_DPAD_LEFT; 235 } else { 236 key = KeyEvent.KEYCODE_DPAD_RIGHT; 237 } 238 } else { 239 key = KeyEvent.KEYCODE_DPAD_DOWN; 240 } 241 scroll(key, verify); 242 } 243 244 /** 245 * Group and sort children by their position on each row (HORIZONTAL) or column(VERTICAL). 246 */ 247 protected View[][] sortByRows() { 248 final HashMap<Integer, ArrayList<View>> rows = new HashMap<Integer, ArrayList<View>>(); 249 ArrayList<Integer> rowLocations = new ArrayList<>(); 250 for (int i = 0; i < mGridView.getChildCount(); i++) { 251 View v = mGridView.getChildAt(i); 252 int rowLocation; 253 if (mOrientation == BaseGridView.HORIZONTAL) { 254 rowLocation = v.getTop(); 255 } else { 256 rowLocation = mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL 257 ? v.getRight() : v.getLeft(); 258 } 259 ArrayList<View> views = rows.get(rowLocation); 260 if (views == null) { 261 views = new ArrayList<View>(); 262 rows.put(rowLocation, views); 263 rowLocations.add(rowLocation); 264 } 265 views.add(v); 266 } 267 Object[] sortedLocations = rowLocations.toArray(); 268 Arrays.sort(sortedLocations); 269 if (mNumRows != rows.size()) { 270 assertEquals("Dump Views by rows "+rows, mNumRows, rows.size()); 271 } 272 View[][] sorted = new View[rows.size()][]; 273 for (int i = 0; i < rowLocations.size(); i++) { 274 Integer rowLocation = rowLocations.get(i); 275 ArrayList<View> arr = rows.get(rowLocation); 276 View[] views = arr.toArray(new View[arr.size()]); 277 Arrays.sort(views, mRowSortComparator); 278 sorted[i] = views; 279 } 280 return sorted; 281 } 282 283 protected void verifyMargin() { 284 View[][] sorted = sortByRows(); 285 for (int row = 0; row < sorted.length; row++) { 286 View[] views = sorted[row]; 287 int margin = -1; 288 for (int i = 1; i < views.length; i++) { 289 if (mOrientation == BaseGridView.HORIZONTAL) { 290 assertEquals(mGridView.getHorizontalMargin(), 291 views[i].getLeft() - views[i - 1].getRight()); 292 } else { 293 assertEquals(mGridView.getVerticalMargin(), 294 views[i].getTop() - views[i - 1].getBottom()); 295 } 296 } 297 } 298 } 299 300 protected void verifyBeginAligned() { 301 View[][] sorted = sortByRows(); 302 int alignedLocation = 0; 303 if (mOrientation == BaseGridView.HORIZONTAL) { 304 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 305 for (int i = 0; i < sorted.length; i++) { 306 if (i == 0) { 307 alignedLocation = sorted[i][sorted[i].length - 1].getRight(); 308 } else { 309 assertEquals(alignedLocation, sorted[i][sorted[i].length - 1].getRight()); 310 } 311 } 312 } else { 313 for (int i = 0; i < sorted.length; i++) { 314 if (i == 0) { 315 alignedLocation = sorted[i][0].getLeft(); 316 } else { 317 assertEquals(alignedLocation, sorted[i][0].getLeft()); 318 } 319 } 320 } 321 } else { 322 for (int i = 0; i < sorted.length; i++) { 323 if (i == 0) { 324 alignedLocation = sorted[i][0].getTop(); 325 } else { 326 assertEquals(alignedLocation, sorted[i][0].getTop()); 327 } 328 } 329 } 330 } 331 332 protected int[] getEndEdges() { 333 View[][] sorted = sortByRows(); 334 int[] edges = new int[sorted.length]; 335 if (mOrientation == BaseGridView.HORIZONTAL) { 336 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 337 for (int i = 0; i < sorted.length; i++) { 338 edges[i] = sorted[i][0].getLeft(); 339 } 340 } else { 341 for (int i = 0; i < sorted.length; i++) { 342 edges[i] = sorted[i][sorted[i].length - 1].getRight(); 343 } 344 } 345 } else { 346 for (int i = 0; i < sorted.length; i++) { 347 edges[i] = sorted[i][sorted[i].length - 1].getBottom(); 348 } 349 } 350 return edges; 351 } 352 353 protected void verifyEdgesSame(int[] edges, int[] edges2) { 354 assertEquals(edges.length, edges2.length); 355 for (int i = 0; i < edges.length; i++) { 356 assertEquals(edges[i], edges2[i]); 357 } 358 } 359 360 protected void verifyBoundCount(int count) { 361 if (mActivity.getBoundCount() != count) { 362 StringBuffer b = new StringBuffer(); 363 b.append("ItemsLength: "); 364 for (int i = 0; i < mActivity.mItemLengths.length; i++) { 365 b.append(mActivity.mItemLengths[i]).append(","); 366 } 367 assertEquals("Bound count does not match, ItemsLengths: "+ b, 368 count, mActivity.getBoundCount()); 369 } 370 } 371 372 private static int getCenterY(View v) { 373 return (v.getTop() + v.getBottom())/2; 374 } 375 376 private static int getCenterX(View v) { 377 return (v.getLeft() + v.getRight())/2; 378 } 379 380 private void initActivity(Intent intent) throws Throwable { 381 mActivityTestRule = new ActivityTestRule<GridActivity>(GridActivity.class, false, false); 382 mActivity = mActivityTestRule.launchActivity(intent); 383 mActivityTestRule.runOnUiThread(new Runnable() { 384 @Override 385 public void run() { 386 mActivity.setTitle(testName.getMethodName()); 387 } 388 }); 389 Thread.sleep(1000); 390 mGridView = mActivity.mGridView; 391 mLayoutManager = (GridLayoutManager) mGridView.getLayoutManager(); 392 } 393 394 @After 395 public void clearTest() { 396 mWaitLayoutListener = null; 397 mLayoutManager = null; 398 mGridView = null; 399 mActivity = null; 400 mActivityTestRule = null; 401 } 402 403 /** 404 * Must be called before waitForLayout() to prepare layout listener. 405 */ 406 protected void startWaitLayout() { 407 if (mWaitLayoutListener != null) { 408 throw new IllegalStateException("startWaitLayout() already called"); 409 } 410 if (mLayoutManager.mLayoutCompleteListener != null) { 411 throw new IllegalStateException("Cannot startWaitLayout()"); 412 } 413 mWaitLayoutListener = mLayoutManager.mLayoutCompleteListener = 414 mock(GridLayoutManager.OnLayoutCompleteListener.class); 415 } 416 417 /** 418 * wait layout to be called and remove the listener. 419 */ 420 protected void waitForLayout() { 421 waitForLayout(true); 422 } 423 424 /** 425 * wait layout to be called and remove the listener. 426 * @param force True if always wait regardless if layout requested 427 */ 428 protected void waitForLayout(boolean force) { 429 if (mWaitLayoutListener == null) { 430 throw new IllegalStateException("startWaitLayout() not called"); 431 } 432 if (mWaitLayoutListener != mLayoutManager.mLayoutCompleteListener) { 433 throw new IllegalStateException("layout listener inconistent"); 434 } 435 try { 436 if (force || mGridView.isLayoutRequested()) { 437 verify(mWaitLayoutListener, timeout(WAIT_FOR_LAYOUT_PASS_TIMEOUT_MS).atLeastOnce()) 438 .onLayoutCompleted(any(RecyclerView.State.class)); 439 } 440 } finally { 441 mWaitLayoutListener = null; 442 mLayoutManager.mLayoutCompleteListener = null; 443 } 444 } 445 446 /** 447 * If currently running animator, wait for it to finish, otherwise return immediately. 448 * To wait the ItemAnimator start, you can use waitForLayout() to make sure layout pass has 449 * processed adapter change. 450 */ 451 protected void waitForItemAnimation(int timeoutMs) throws Throwable { 452 final RecyclerView.ItemAnimator.ItemAnimatorFinishedListener listener = mock( 453 RecyclerView.ItemAnimator.ItemAnimatorFinishedListener.class); 454 mActivityTestRule.runOnUiThread(new Runnable() { 455 @Override 456 public void run() { 457 mGridView.getItemAnimator().isRunning(listener); 458 } 459 }); 460 verify(listener, timeout(timeoutMs).atLeastOnce()).onAnimationsFinished(); 461 } 462 463 protected void waitForItemAnimation() throws Throwable { 464 waitForItemAnimation(WAIT_FOR_ITEM_ANIMATION_FINISH_TIMEOUT_MS); 465 } 466 467 /** 468 * wait animation start 469 */ 470 protected void waitForItemAnimationStart() throws Throwable { 471 long totalWait = 0; 472 while (!mGridView.getItemAnimator().isRunning()) { 473 Thread.sleep(10); 474 if ((totalWait += 10) > WAIT_FOR_ITEM_ANIMATION_FINISH_TIMEOUT_MS) { 475 throw new RuntimeException("waitForItemAnimationStart Timeout"); 476 } 477 } 478 } 479 480 /** 481 * Run task in UI thread and wait for layout and ItemAnimator finishes. 482 */ 483 protected void performAndWaitForAnimation(Runnable task) throws Throwable { 484 startWaitLayout(); 485 mActivityTestRule.runOnUiThread(task); 486 waitForLayout(); 487 waitForItemAnimation(); 488 } 489 490 protected void waitForScrollIdle() throws Throwable { 491 waitForScrollIdle(null); 492 } 493 494 /** 495 * Wait for grid view stop scroll and optionally verify state of grid view. 496 */ 497 protected void waitForScrollIdle(Runnable verify) throws Throwable { 498 Thread.sleep(100); 499 int total = 0; 500 while (mGridView.getLayoutManager().isSmoothScrolling() 501 || mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE) { 502 if ((total += 100) >= WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS) { 503 throw new RuntimeException("waitForScrollIdle Timeout"); 504 } 505 try { 506 Thread.sleep(100); 507 } catch (InterruptedException ex) { 508 break; 509 } 510 if (verify != null) { 511 mActivityTestRule.runOnUiThread(verify); 512 } 513 } 514 } 515 516 @Test 517 public void testThreeRowHorizontalBasic() throws Throwable { 518 Intent intent = new Intent(); 519 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid); 520 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100); 521 initActivity(intent); 522 mOrientation = BaseGridView.HORIZONTAL; 523 mNumRows = 3; 524 525 scrollToEnd(mVerifyLayout); 526 527 scrollToBegin(mVerifyLayout); 528 529 verifyBeginAligned(); 530 } 531 532 static class DividerDecoration extends RecyclerView.ItemDecoration { 533 534 private ColorDrawable mTopDivider; 535 private ColorDrawable mBottomDivider; 536 private int mLeftOffset; 537 private int mRightOffset; 538 private int mTopOffset; 539 private int mBottomOffset; 540 541 DividerDecoration(int leftOffset, int topOffset, int rightOffset, int bottomOffset) { 542 mLeftOffset = leftOffset; 543 mTopOffset = topOffset; 544 mRightOffset = rightOffset; 545 mBottomOffset = bottomOffset; 546 } 547 548 @Override 549 public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { 550 if (mTopDivider == null) { 551 mTopDivider = new ColorDrawable(Color.RED); 552 } 553 if (mBottomDivider == null) { 554 mBottomDivider = new ColorDrawable(Color.BLUE); 555 } 556 final int childCount = parent.getChildCount(); 557 final int width = parent.getWidth(); 558 for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) { 559 final View view = parent.getChildAt(childViewIndex); 560 mTopDivider.setBounds(0, (int) view.getY() - mTopOffset, width, (int) view.getY()); 561 mTopDivider.draw(c); 562 mBottomDivider.setBounds(0, (int) view.getY() + view.getHeight(), width, 563 (int) view.getY() + view.getHeight() + mBottomOffset); 564 mBottomDivider.draw(c); 565 } 566 } 567 568 @Override 569 public void getItemOffsets(Rect outRect, View view, RecyclerView parent, 570 RecyclerView.State state) { 571 outRect.left = mLeftOffset; 572 outRect.top = mTopOffset; 573 outRect.right = mRightOffset; 574 outRect.bottom = mBottomOffset; 575 } 576 } 577 578 @Test 579 public void testItemDecorationAndMargins() throws Throwable { 580 581 final int leftMargin = 3; 582 final int topMargin = 4; 583 final int rightMargin = 7; 584 final int bottomMargin = 8; 585 final int itemHeight = 100; 586 587 Intent intent = new Intent(); 588 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 589 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{itemHeight, itemHeight, itemHeight}); 590 intent.putExtra(GridActivity.EXTRA_LAYOUT_MARGINS, 591 new int[]{leftMargin, topMargin, rightMargin, bottomMargin}); 592 initActivity(intent); 593 mOrientation = BaseGridView.VERTICAL; 594 mNumRows = 1; 595 596 final int paddingLeft = mGridView.getPaddingLeft(); 597 final int paddingTop = mGridView.getPaddingTop(); 598 final int verticalSpace = mGridView.getVerticalMargin(); 599 final int decorationLeft = 17; 600 final int decorationTop = 1; 601 final int decorationRight = 19; 602 final int decorationBottom = 2; 603 604 performAndWaitForAnimation(new Runnable() { 605 @Override 606 public void run() { 607 mGridView.addItemDecoration(new DividerDecoration(decorationLeft, decorationTop, 608 decorationRight, decorationBottom)); 609 } 610 }); 611 612 View child0 = mGridView.getChildAt(0); 613 View child1 = mGridView.getChildAt(1); 614 View child2 = mGridView.getChildAt(2); 615 616 assertEquals(itemHeight, child0.getBottom() - child0.getTop()); 617 618 // verify left margins 619 assertEquals(paddingLeft + leftMargin + decorationLeft, child0.getLeft()); 620 assertEquals(paddingLeft + leftMargin + decorationLeft, child1.getLeft()); 621 assertEquals(paddingLeft + leftMargin + decorationLeft, child2.getLeft()); 622 // verify top bottom margins and decoration offset 623 assertEquals(paddingTop + topMargin + decorationTop, child0.getTop()); 624 assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin, 625 child1.getTop() - child0.getBottom()); 626 assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin, 627 child2.getTop() - child1.getBottom()); 628 629 } 630 631 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 632 @Test 633 public void testItemDecorationAndMarginsAndOpticalBounds() throws Throwable { 634 final int leftMargin = 3; 635 final int topMargin = 4; 636 final int rightMargin = 7; 637 final int bottomMargin = 8; 638 final int itemHeight = 100; 639 final int ninePatchDrawableResourceId = R.drawable.lb_card_shadow_focused; 640 641 Intent intent = new Intent(); 642 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 643 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{itemHeight, itemHeight, itemHeight}); 644 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout); 645 intent.putExtra(GridActivity.EXTRA_LAYOUT_MARGINS, 646 new int[]{leftMargin, topMargin, rightMargin, bottomMargin}); 647 intent.putExtra(GridActivity.EXTRA_NINEPATCH_SHADOW, ninePatchDrawableResourceId); 648 initActivity(intent); 649 mOrientation = BaseGridView.VERTICAL; 650 mNumRows = 1; 651 652 final int paddingLeft = mGridView.getPaddingLeft(); 653 final int paddingTop = mGridView.getPaddingTop(); 654 final int verticalSpace = mGridView.getVerticalMargin(); 655 final int decorationLeft = 17; 656 final int decorationTop = 1; 657 final int decorationRight = 19; 658 final int decorationBottom = 2; 659 660 final Rect opticalPaddings = new Rect(); 661 mGridView.getResources().getDrawable(ninePatchDrawableResourceId) 662 .getPadding(opticalPaddings); 663 final int opticalInsetsLeft = opticalPaddings.left; 664 final int opticalInsetsTop = opticalPaddings.top; 665 final int opticalInsetsRight = opticalPaddings.right; 666 final int opticalInsetsBottom = opticalPaddings.bottom; 667 assertTrue(opticalInsetsLeft > 0); 668 assertTrue(opticalInsetsTop > 0); 669 assertTrue(opticalInsetsRight > 0); 670 assertTrue(opticalInsetsBottom > 0); 671 672 performAndWaitForAnimation(new Runnable() { 673 @Override 674 public void run() { 675 mGridView.addItemDecoration(new DividerDecoration(decorationLeft, decorationTop, 676 decorationRight, decorationBottom)); 677 } 678 }); 679 680 View child0 = mGridView.getChildAt(0); 681 View child1 = mGridView.getChildAt(1); 682 View child2 = mGridView.getChildAt(2); 683 684 assertEquals(itemHeight + opticalInsetsTop + opticalInsetsBottom, 685 child0.getBottom() - child0.getTop()); 686 687 // verify left margins decoration and optical insets 688 assertEquals(paddingLeft + leftMargin + decorationLeft - opticalInsetsLeft, 689 child0.getLeft()); 690 assertEquals(paddingLeft + leftMargin + decorationLeft - opticalInsetsLeft, 691 child1.getLeft()); 692 assertEquals(paddingLeft + leftMargin + decorationLeft - opticalInsetsLeft, 693 child2.getLeft()); 694 // verify top bottom margins decoration offset and optical insets 695 assertEquals(paddingTop + topMargin + decorationTop, child0.getTop() + opticalInsetsTop); 696 assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin, 697 (child1.getTop() + opticalInsetsTop) - (child0.getBottom() - opticalInsetsBottom)); 698 assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin, 699 (child2.getTop() + opticalInsetsTop) - (child1.getBottom() - opticalInsetsBottom)); 700 701 } 702 703 @Test 704 public void testThreeColumnVerticalBasic() throws Throwable { 705 706 Intent intent = new Intent(); 707 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid); 708 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 709 initActivity(intent); 710 mOrientation = BaseGridView.VERTICAL; 711 mNumRows = 3; 712 713 scrollToEnd(mVerifyLayout); 714 715 scrollToBegin(mVerifyLayout); 716 717 verifyBeginAligned(); 718 } 719 720 @Test 721 public void testRedundantAppendRemove() throws Throwable { 722 Intent intent = new Intent(); 723 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 724 R.layout.vertical_grid_testredundantappendremove); 725 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{ 726 149,177,128,234,227,187,163,223,146,210,228,148,227,193,182,197,177,142,225,207, 727 157,171,209,204,187,184,123,221,197,153,202,179,193,214,226,173,225,143,188,159, 728 139,193,233,143,227,203,222,124,228,223,164,131,228,126,211,160,165,152,235,184, 729 155,224,149,181,171,229,200,234,177,130,164,172,188,139,132,203,179,220,147,131, 730 226,127,230,239,183,203,206,227,123,170,239,234,200,149,237,204,160,133,202,234, 731 173,122,139,149,151,153,216,231,121,145,227,153,186,174,223,180,123,215,206,216, 732 239,222,219,207,193,218,140,133,171,153,183,132,233,138,159,174,189,171,143,128, 733 152,222,141,202,224,190,134,120,181,231,230,136,132,224,136,210,207,150,128,183, 734 221,194,179,220,126,221,137,205,223,193,172,132,226,209,133,191,227,127,159,171, 735 180,149,237,177,194,207,170,202,161,144,147,199,205,186,164,140,193,203,224,129}); 736 initActivity(intent); 737 mOrientation = BaseGridView.VERTICAL; 738 mNumRows = 3; 739 740 scrollToEnd(mVerifyLayout); 741 742 scrollToBegin(mVerifyLayout); 743 744 verifyBeginAligned(); 745 } 746 747 @Test 748 public void testRedundantAppendRemove2() throws Throwable { 749 Intent intent = new Intent(); 750 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 751 R.layout.horizontal_grid_testredundantappendremove2); 752 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{ 753 318,333,199,224,246,273,269,289,340,313,265,306,349,269,185,282,257,354,316,252, 754 237,290,283,343,196,313,290,343,191,262,342,228,343,349,251,203,226,305,265,213, 755 216,333,295,188,187,281,288,311,244,232,224,332,290,181,267,276,226,261,335,355, 756 225,217,219,183,234,285,257,304,182,250,244,223,257,219,342,185,347,205,302,315, 757 299,309,292,237,192,309,228,250,347,227,337,298,299,185,185,331,223,284,265,351}); 758 initActivity(intent); 759 mOrientation = BaseGridView.HORIZONTAL; 760 mNumRows = 3; 761 mLayoutManager = (GridLayoutManager) mGridView.getLayoutManager(); 762 763 // test append without staggered result cache 764 scrollToEnd(mVerifyLayout); 765 766 int[] endEdges = getEndEdges(); 767 768 scrollToBegin(mVerifyLayout); 769 770 verifyBeginAligned(); 771 772 // now test append with staggered result cache 773 changeArraySize(3); 774 assertEquals("Staggerd cache should be kept as is when no item size change", 775 100, ((StaggeredGrid) mLayoutManager.mGrid).mLocations.size()); 776 777 changeArraySize(100); 778 779 scrollToEnd(mVerifyLayout); 780 781 // we should get same aligned end edges 782 int[] endEdges2 = getEndEdges(); 783 verifyEdgesSame(endEdges, endEdges2); 784 } 785 786 787 @Test 788 public void testLayoutWhenAViewIsInvalidated() throws Throwable { 789 Intent intent = new Intent(); 790 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 791 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000); 792 intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, true); 793 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 794 mNumRows = 1; 795 initActivity(intent); 796 mOrientation = BaseGridView.VERTICAL; 797 waitOneUiCycle(); 798 799 // push views to cache. 800 mActivityTestRule.runOnUiThread(new Runnable() { 801 @Override 802 public void run() { 803 mActivity.mItemLengths[0] = mActivity.mItemLengths[0] * 3; 804 mActivity.mGridView.getAdapter().notifyItemChanged(0); 805 } 806 }); 807 waitForItemAnimation(); 808 809 // notifyDataSetChange will mark the cached views FLAG_INVALID 810 mActivityTestRule.runOnUiThread(new Runnable() { 811 @Override 812 public void run() { 813 mActivity.mGridView.getAdapter().notifyDataSetChanged(); 814 } 815 }); 816 waitForItemAnimation(); 817 818 // Cached views will be added in prelayout with FLAG_INVALID, in post layout we should 819 // handle it properly 820 mActivityTestRule.runOnUiThread(new Runnable() { 821 @Override 822 public void run() { 823 mActivity.mItemLengths[0] = mActivity.mItemLengths[0] / 3; 824 mActivity.mGridView.getAdapter().notifyItemChanged(0); 825 } 826 }); 827 828 waitForItemAnimation(); 829 } 830 831 @Test 832 public void testWrongInsertViewIndexInFastRelayout() throws Throwable { 833 Intent intent = new Intent(); 834 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 835 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2); 836 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 837 mNumRows = 1; 838 initActivity(intent); 839 mOrientation = BaseGridView.VERTICAL; 840 841 // removing two children, they will be hidden views as first 2 children of RV. 842 mActivityTestRule.runOnUiThread(new Runnable() { 843 @Override 844 public void run() { 845 mGridView.getItemAnimator().setRemoveDuration(2000); 846 mActivity.removeItems(0, 2); 847 } 848 }); 849 waitForItemAnimationStart(); 850 851 // add three views and notify change of the first item. 852 startWaitLayout(); 853 mActivityTestRule.runOnUiThread(new Runnable() { 854 @Override 855 public void run() { 856 mActivity.addItems(0, new int[]{161, 161, 161}); 857 } 858 }); 859 waitForLayout(); 860 startWaitLayout(); 861 mActivityTestRule.runOnUiThread(new Runnable() { 862 @Override 863 public void run() { 864 mGridView.getAdapter().notifyItemChanged(0); 865 } 866 }); 867 waitForLayout(); 868 // after layout, the viewholder should still be the first child of LayoutManager. 869 assertEquals(0, mGridView.getChildAdapterPosition( 870 mGridView.getLayoutManager().getChildAt(0))); 871 } 872 873 @Test 874 public void testMoveIntoPrelayoutItems() throws Throwable { 875 Intent intent = new Intent(); 876 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 877 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000); 878 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 879 mNumRows = 1; 880 initActivity(intent); 881 mOrientation = BaseGridView.VERTICAL; 882 883 final int lastItemPos = mGridView.getChildCount() - 1; 884 assertTrue(mGridView.getChildCount() >= 4); 885 // notify change of 3 items, so prelayout will layout extra 3 items, then move an item 886 // into the extra layout range. Post layout's fastRelayout() should handle this properly. 887 mActivityTestRule.runOnUiThread(new Runnable() { 888 @Override 889 public void run() { 890 mGridView.getAdapter().notifyItemChanged(lastItemPos - 3); 891 mGridView.getAdapter().notifyItemChanged(lastItemPos - 2); 892 mGridView.getAdapter().notifyItemChanged(lastItemPos - 1); 893 mActivity.moveItem(900, lastItemPos + 2, true); 894 } 895 }); 896 waitForItemAnimation(); 897 } 898 899 @Test 900 public void testMoveIntoPrelayoutItems2() throws Throwable { 901 Intent intent = new Intent(); 902 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 903 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000); 904 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 905 mNumRows = 1; 906 initActivity(intent); 907 mOrientation = BaseGridView.VERTICAL; 908 909 setSelectedPosition(999); 910 final int firstItemPos = mGridView.getChildAdapterPosition(mGridView.getChildAt(0)); 911 assertTrue(mGridView.getChildCount() >= 4); 912 // notify change of 3 items, so prelayout will layout extra 3 items, then move an item 913 // into the extra layout range. Post layout's fastRelayout() should handle this properly. 914 mActivityTestRule.runOnUiThread(new Runnable() { 915 @Override 916 public void run() { 917 mGridView.getAdapter().notifyItemChanged(firstItemPos + 1); 918 mGridView.getAdapter().notifyItemChanged(firstItemPos + 2); 919 mGridView.getAdapter().notifyItemChanged(firstItemPos + 3); 920 mActivity.moveItem(0, firstItemPos - 2, true); 921 } 922 }); 923 waitForItemAnimation(); 924 } 925 926 void preparePredictiveLayout() throws Throwable { 927 Intent intent = new Intent(); 928 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear); 929 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100); 930 initActivity(intent); 931 mOrientation = BaseGridView.HORIZONTAL; 932 mNumRows = 1; 933 934 mActivityTestRule.runOnUiThread(new Runnable() { 935 @Override 936 public void run() { 937 mGridView.getItemAnimator().setAddDuration(1000); 938 mGridView.getItemAnimator().setRemoveDuration(1000); 939 mGridView.getItemAnimator().setMoveDuration(1000); 940 mGridView.getItemAnimator().setChangeDuration(1000); 941 mGridView.setSelectedPositionSmooth(50); 942 } 943 }); 944 waitForScrollIdle(mVerifyLayout); 945 } 946 947 @Test 948 public void testPredictiveLayoutAdd1() throws Throwable { 949 preparePredictiveLayout(); 950 mActivityTestRule.runOnUiThread(new Runnable() { 951 @Override 952 public void run() { 953 mActivity.addItems(51, new int[]{300, 300, 300, 300}); 954 } 955 }); 956 waitForItemAnimationStart(); 957 waitForItemAnimation(); 958 assertEquals(50, mGridView.getSelectedPosition()); 959 assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState()); 960 } 961 962 @Test 963 public void testPredictiveLayoutAdd2() throws Throwable { 964 preparePredictiveLayout(); 965 mActivityTestRule.runOnUiThread(new Runnable() { 966 @Override 967 public void run() { 968 mActivity.addItems(50, new int[]{300, 300, 300, 300}); 969 } 970 }); 971 waitForItemAnimationStart(); 972 waitForItemAnimation(); 973 assertEquals(54, mGridView.getSelectedPosition()); 974 assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState()); 975 } 976 977 @Test 978 public void testPredictiveLayoutRemove1() throws Throwable { 979 preparePredictiveLayout(); 980 mActivityTestRule.runOnUiThread(new Runnable() { 981 @Override 982 public void run() { 983 mActivity.removeItems(51, 3); 984 } 985 }); 986 waitForItemAnimationStart(); 987 waitForItemAnimation(); 988 assertEquals(50, mGridView.getSelectedPosition()); 989 assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState()); 990 } 991 992 @Test 993 public void testPredictiveLayoutRemove2() throws Throwable { 994 preparePredictiveLayout(); 995 mActivityTestRule.runOnUiThread(new Runnable() { 996 @Override 997 public void run() { 998 mActivity.removeItems(47, 3); 999 } 1000 }); 1001 waitForItemAnimationStart(); 1002 waitForItemAnimation(); 1003 assertEquals(47, mGridView.getSelectedPosition()); 1004 assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState()); 1005 } 1006 1007 @Test 1008 public void testPredictiveLayoutRemove3() throws Throwable { 1009 preparePredictiveLayout(); 1010 mActivityTestRule.runOnUiThread(new Runnable() { 1011 @Override 1012 public void run() { 1013 mActivity.removeItems(0, 51); 1014 } 1015 }); 1016 waitForItemAnimationStart(); 1017 waitForItemAnimation(); 1018 assertEquals(0, mGridView.getSelectedPosition()); 1019 assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState()); 1020 } 1021 1022 @Test 1023 public void testPredictiveOnMeasureWrapContent() throws Throwable { 1024 Intent intent = new Intent(); 1025 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1026 R.layout.horizontal_linear_wrap_content); 1027 int count = 50; 1028 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, count); 1029 initActivity(intent); 1030 mOrientation = BaseGridView.HORIZONTAL; 1031 mNumRows = 1; 1032 1033 waitForScrollIdle(mVerifyLayout); 1034 mActivityTestRule.runOnUiThread(new Runnable() { 1035 @Override 1036 public void run() { 1037 mGridView.setHasFixedSize(false); 1038 } 1039 }); 1040 1041 for (int i = 0; i < 30; i++) { 1042 final int oldCount = count; 1043 final int newCount = i; 1044 mActivityTestRule.runOnUiThread(new Runnable() { 1045 @Override 1046 public void run() { 1047 if (oldCount > 0) { 1048 mActivity.removeItems(0, oldCount); 1049 } 1050 if (newCount > 0) { 1051 int[] newItems = new int[newCount]; 1052 for (int i = 0; i < newCount; i++) { 1053 newItems[i] = 400; 1054 } 1055 mActivity.addItems(0, newItems); 1056 } 1057 } 1058 }); 1059 waitForItemAnimationStart(); 1060 waitForItemAnimation(); 1061 count = newCount; 1062 } 1063 1064 } 1065 1066 @Test 1067 public void testPredictiveLayoutRemove4() throws Throwable { 1068 Intent intent = new Intent(); 1069 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1070 R.layout.horizontal_grid); 1071 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 1072 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1073 initActivity(intent); 1074 mOrientation = BaseGridView.HORIZONTAL; 1075 mNumRows = 3; 1076 1077 mActivityTestRule.runOnUiThread(new Runnable() { 1078 @Override 1079 public void run() { 1080 mGridView.setSelectedPositionSmooth(50); 1081 } 1082 }); 1083 waitForScrollIdle(); 1084 performAndWaitForAnimation(new Runnable() { 1085 @Override 1086 public void run() { 1087 mActivity.removeItems(0, 49); 1088 } 1089 }); 1090 assertEquals(1, mGridView.getSelectedPosition()); 1091 } 1092 1093 @Test 1094 public void testPredictiveLayoutRemove5() throws Throwable { 1095 Intent intent = new Intent(); 1096 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1097 R.layout.horizontal_grid); 1098 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 1099 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 1100 initActivity(intent); 1101 mOrientation = BaseGridView.HORIZONTAL; 1102 mNumRows = 3; 1103 1104 mActivityTestRule.runOnUiThread(new Runnable() { 1105 @Override 1106 public void run() { 1107 mGridView.setSelectedPositionSmooth(50); 1108 } 1109 }); 1110 waitForScrollIdle(); 1111 performAndWaitForAnimation(new Runnable() { 1112 @Override 1113 public void run() { 1114 mActivity.removeItems(50, 40); 1115 } 1116 }); 1117 assertEquals(50, mGridView.getSelectedPosition()); 1118 scrollToBegin(mVerifyLayout); 1119 verifyBeginAligned(); 1120 } 1121 1122 void waitOneUiCycle() throws Throwable { 1123 mActivityTestRule.runOnUiThread(new Runnable() { 1124 @Override 1125 public void run() { 1126 } 1127 }); 1128 } 1129 1130 @Test 1131 public void testDontPruneMovingItem() throws Throwable { 1132 Intent intent = new Intent(); 1133 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear); 1134 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1135 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000); 1136 initActivity(intent); 1137 mOrientation = BaseGridView.HORIZONTAL; 1138 mNumRows = 1; 1139 1140 mActivityTestRule.runOnUiThread(new Runnable() { 1141 @Override 1142 public void run() { 1143 mGridView.getItemAnimator().setMoveDuration(2000); 1144 mGridView.setSelectedPosition(50); 1145 } 1146 }); 1147 waitForScrollIdle(); 1148 final ArrayList<RecyclerView.ViewHolder> moveViewHolders = new ArrayList(); 1149 for (int i = 51;; i++) { 1150 RecyclerView.ViewHolder vh = mGridView.findViewHolderForAdapterPosition(i); 1151 if (vh == null) { 1152 break; 1153 } 1154 moveViewHolders.add(vh); 1155 } 1156 1157 mActivityTestRule.runOnUiThread(new Runnable() { 1158 @Override 1159 public void run() { 1160 // add a lot of items, so we will push everything to right of 51 out side window 1161 int[] lots_items = new int[1000]; 1162 for (int i = 0; i < lots_items.length; i++) { 1163 lots_items[i] = 300; 1164 } 1165 mActivity.addItems(51, lots_items); 1166 } 1167 }); 1168 waitOneUiCycle(); 1169 // run a scroll pass, the scroll pass should not remove the animating views even they are 1170 // outside visible areas. 1171 mActivityTestRule.runOnUiThread(new Runnable() { 1172 @Override 1173 public void run() { 1174 mGridView.scrollBy(-3, 0); 1175 } 1176 }); 1177 waitOneUiCycle(); 1178 for (int i = 0; i < moveViewHolders.size(); i++) { 1179 assertSame(mGridView, moveViewHolders.get(i).itemView.getParent()); 1180 } 1181 } 1182 1183 @Test 1184 public void testMoveItemToTheRight() throws Throwable { 1185 Intent intent = new Intent(); 1186 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear); 1187 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1188 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000); 1189 initActivity(intent); 1190 mOrientation = BaseGridView.HORIZONTAL; 1191 mNumRows = 1; 1192 1193 mActivityTestRule.runOnUiThread(new Runnable() { 1194 @Override 1195 public void run() { 1196 mGridView.getItemAnimator().setAddDuration(2000); 1197 mGridView.getItemAnimator().setMoveDuration(2000); 1198 mGridView.setSelectedPosition(50); 1199 } 1200 }); 1201 waitForScrollIdle(); 1202 RecyclerView.ViewHolder moveViewHolder = mGridView.findViewHolderForAdapterPosition(51); 1203 1204 int lastPos = mGridView.getChildAdapterPosition(mGridView.getChildAt( 1205 mGridView.getChildCount() - 1)); 1206 mActivityTestRule.runOnUiThread(new Runnable() { 1207 @Override 1208 public void run() { 1209 mActivity.moveItem(51, 1000, true); 1210 } 1211 }); 1212 final ArrayList<View> moveInViewHolders = new ArrayList(); 1213 waitForItemAnimationStart(); 1214 mActivityTestRule.runOnUiThread(new Runnable() { 1215 @Override 1216 public void run() { 1217 for (int i = 0; i < mGridView.getLayoutManager().getChildCount(); i++) { 1218 View v = mGridView.getLayoutManager().getChildAt(i); 1219 if (mGridView.getChildAdapterPosition(v) >= 51) { 1220 moveInViewHolders.add(v); 1221 } 1222 } 1223 } 1224 }); 1225 waitOneUiCycle(); 1226 assertTrue("prelayout should layout extra items to slide in", 1227 moveInViewHolders.size() > lastPos - 51); 1228 // run a scroll pass, the scroll pass should not remove the animating views even they are 1229 // outside visible areas. 1230 mActivityTestRule.runOnUiThread(new Runnable() { 1231 @Override 1232 public void run() { 1233 mGridView.scrollBy(-3, 0); 1234 } 1235 }); 1236 waitOneUiCycle(); 1237 for (int i = 0; i < moveInViewHolders.size(); i++) { 1238 assertSame(mGridView, moveInViewHolders.get(i).getParent()); 1239 } 1240 assertSame(mGridView, moveViewHolder.itemView.getParent()); 1241 assertFalse(moveViewHolder.isRecyclable()); 1242 waitForItemAnimation(); 1243 assertNull(moveViewHolder.itemView.getParent()); 1244 assertTrue(moveViewHolder.isRecyclable()); 1245 } 1246 1247 @Test 1248 public void testMoveItemToTheLeft() throws Throwable { 1249 Intent intent = new Intent(); 1250 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear); 1251 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1252 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000); 1253 initActivity(intent); 1254 mOrientation = BaseGridView.HORIZONTAL; 1255 mNumRows = 1; 1256 1257 mActivityTestRule.runOnUiThread(new Runnable() { 1258 @Override 1259 public void run() { 1260 mGridView.getItemAnimator().setAddDuration(2000); 1261 mGridView.getItemAnimator().setMoveDuration(2000); 1262 mGridView.setSelectedPosition(1500); 1263 } 1264 }); 1265 waitForScrollIdle(); 1266 RecyclerView.ViewHolder moveViewHolder = mGridView.findViewHolderForAdapterPosition(1499); 1267 1268 int firstPos = mGridView.getChildAdapterPosition(mGridView.getChildAt(0)); 1269 mActivityTestRule.runOnUiThread(new Runnable() { 1270 @Override 1271 public void run() { 1272 mActivity.moveItem(1499, 1, true); 1273 } 1274 }); 1275 final ArrayList<View> moveInViewHolders = new ArrayList(); 1276 waitForItemAnimationStart(); 1277 mActivityTestRule.runOnUiThread(new Runnable() { 1278 @Override 1279 public void run() { 1280 for (int i = 0; i < mGridView.getLayoutManager().getChildCount(); i++) { 1281 View v = mGridView.getLayoutManager().getChildAt(i); 1282 if (mGridView.getChildAdapterPosition(v) <= 1499) { 1283 moveInViewHolders.add(v); 1284 } 1285 } 1286 } 1287 }); 1288 waitOneUiCycle(); 1289 assertTrue("prelayout should layout extra items to slide in ", 1290 moveInViewHolders.size() > 1499 - firstPos); 1291 // run a scroll pass, the scroll pass should not remove the animating views even they are 1292 // outside visible areas. 1293 mActivityTestRule.runOnUiThread(new Runnable() { 1294 @Override 1295 public void run() { 1296 mGridView.scrollBy(3, 0); 1297 } 1298 }); 1299 waitOneUiCycle(); 1300 for (int i = 0; i < moveInViewHolders.size(); i++) { 1301 assertSame(mGridView, moveInViewHolders.get(i).getParent()); 1302 } 1303 assertSame(mGridView, moveViewHolder.itemView.getParent()); 1304 assertFalse(moveViewHolder.isRecyclable()); 1305 waitForItemAnimation(); 1306 assertNull(moveViewHolder.itemView.getParent()); 1307 assertTrue(moveViewHolder.isRecyclable()); 1308 } 1309 1310 @Test 1311 public void testContinuousSwapForward() throws Throwable { 1312 Intent intent = new Intent(); 1313 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1314 R.layout.horizontal_linear); 1315 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 1316 initActivity(intent); 1317 mOrientation = BaseGridView.HORIZONTAL; 1318 mNumRows = 1; 1319 1320 mActivityTestRule.runOnUiThread(new Runnable() { 1321 @Override 1322 public void run() { 1323 mGridView.setSelectedPositionSmooth(150); 1324 } 1325 }); 1326 waitForScrollIdle(mVerifyLayout); 1327 for (int i = 150; i < 199; i++) { 1328 final int swapIndex = i; 1329 mActivityTestRule.runOnUiThread(new Runnable() { 1330 @Override 1331 public void run() { 1332 mActivity.swap(swapIndex, swapIndex + 1); 1333 } 1334 }); 1335 Thread.sleep(10); 1336 } 1337 waitForItemAnimation(); 1338 assertEquals(199, mGridView.getSelectedPosition()); 1339 // check if ItemAnimation finishes at aligned positions: 1340 int leftEdge = mGridView.getLayoutManager().findViewByPosition(199).getLeft(); 1341 mActivityTestRule.runOnUiThread(new Runnable() { 1342 @Override 1343 public void run() { 1344 mGridView.requestLayout(); 1345 } 1346 }); 1347 waitForScrollIdle(); 1348 assertEquals(leftEdge, mGridView.getLayoutManager().findViewByPosition(199).getLeft()); 1349 } 1350 1351 @Test 1352 public void testContinuousSwapBackward() throws Throwable { 1353 Intent intent = new Intent(); 1354 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1355 R.layout.horizontal_linear); 1356 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 1357 initActivity(intent); 1358 mOrientation = BaseGridView.HORIZONTAL; 1359 mNumRows = 1; 1360 1361 mActivityTestRule.runOnUiThread(new Runnable() { 1362 @Override 1363 public void run() { 1364 mGridView.setSelectedPositionSmooth(50); 1365 } 1366 }); 1367 waitForScrollIdle(mVerifyLayout); 1368 for (int i = 50; i > 0; i--) { 1369 final int swapIndex = i; 1370 mActivityTestRule.runOnUiThread(new Runnable() { 1371 @Override 1372 public void run() { 1373 mActivity.swap(swapIndex, swapIndex - 1); 1374 } 1375 }); 1376 Thread.sleep(10); 1377 } 1378 waitForItemAnimation(); 1379 assertEquals(0, mGridView.getSelectedPosition()); 1380 // check if ItemAnimation finishes at aligned positions: 1381 int leftEdge = mGridView.getLayoutManager().findViewByPosition(0).getLeft(); 1382 mActivityTestRule.runOnUiThread(new Runnable() { 1383 @Override 1384 public void run() { 1385 mGridView.requestLayout(); 1386 } 1387 }); 1388 waitForScrollIdle(); 1389 assertEquals(leftEdge, mGridView.getLayoutManager().findViewByPosition(0).getLeft()); 1390 } 1391 1392 void testSetSelectedPosition(final boolean inSmoothScroll, final boolean layoutRequested, 1393 final boolean viewVisible, final boolean smooth, 1394 final boolean resultLayoutRequested, final boolean resultSmoothScroller, 1395 final int resultScrollState) throws Throwable { 1396 Intent intent = new Intent(); 1397 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 1398 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1500); 1399 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1400 mNumRows = 1; 1401 initActivity(intent); 1402 mOrientation = BaseGridView.VERTICAL; 1403 1404 if (inSmoothScroll) { 1405 setSelectedPositionSmooth(500); 1406 } 1407 mActivityTestRule.runOnUiThread(new Runnable() { 1408 @Override 1409 public void run() { 1410 if (layoutRequested) { 1411 mGridView.requestLayout(); 1412 } 1413 final int position; 1414 if (viewVisible) { 1415 position = mGridView.getChildAdapterPosition(mGridView.getChildAt( 1416 mGridView.getChildCount() - 1)); 1417 } else { 1418 position = 1000; 1419 } 1420 if (smooth) { 1421 mGridView.setSelectedPositionSmooth(position); 1422 } else { 1423 mGridView.setSelectedPosition(position); 1424 } 1425 assertEquals("isLayoutRequested", resultLayoutRequested, 1426 mGridView.isLayoutRequested()); 1427 assertEquals("isSmoothScrolling", resultSmoothScroller, 1428 mGridView.getLayoutManager().isSmoothScrolling()); 1429 if (!resultSmoothScroller) { 1430 // getScrollState() only matters when is not running smoothScroller 1431 assertEquals("getScrollState", resultScrollState, 1432 mGridView.getScrollState()); 1433 } 1434 assertEquals("isLayoutRequested", resultLayoutRequested, 1435 mGridView.isLayoutRequested()); 1436 } 1437 }); 1438 } 1439 1440 @Test 1441 public void testSelectedPosition01() throws Throwable { 1442 testSetSelectedPosition(false, false, false, false, 1443 true, false, RecyclerView.SCROLL_STATE_IDLE); 1444 } 1445 1446 @Test 1447 public void testSelectedPosition02() throws Throwable { 1448 testSetSelectedPosition(false, false, false, true, 1449 false, true, RecyclerView.SCROLL_STATE_IDLE); 1450 } 1451 1452 @Test 1453 public void testSelectedPosition03() throws Throwable { 1454 testSetSelectedPosition(false, false, true, false, 1455 false, false, RecyclerView.SCROLL_STATE_IDLE); 1456 } 1457 1458 @Test 1459 public void testSelectedPosition04() throws Throwable { 1460 testSetSelectedPosition(false, false, true, true, 1461 false, false, RecyclerView.SCROLL_STATE_SETTLING); 1462 } 1463 1464 @Test 1465 public void testSelectedPosition05() throws Throwable { 1466 testSetSelectedPosition(false, true, false, false, 1467 true, false, RecyclerView.SCROLL_STATE_IDLE); 1468 } 1469 1470 @Test 1471 public void testSelectedPosition06() throws Throwable { 1472 testSetSelectedPosition(false, true, false, true, 1473 true, false, RecyclerView.SCROLL_STATE_IDLE); 1474 } 1475 1476 @Test 1477 public void testSelectedPosition07() throws Throwable { 1478 testSetSelectedPosition(false, true, true, false, 1479 true, false, RecyclerView.SCROLL_STATE_IDLE); 1480 } 1481 1482 @Test 1483 public void testSelectedPosition08() throws Throwable { 1484 testSetSelectedPosition(false, true, true, true, 1485 true, false, RecyclerView.SCROLL_STATE_IDLE); 1486 } 1487 1488 @Test 1489 public void testSelectedPosition09() throws Throwable { 1490 testSetSelectedPosition(true, false, false, false, 1491 true, false, RecyclerView.SCROLL_STATE_IDLE); 1492 } 1493 1494 @Test 1495 public void testSelectedPosition10() throws Throwable { 1496 testSetSelectedPosition(true, false, false, true, 1497 false, true, RecyclerView.SCROLL_STATE_IDLE); 1498 } 1499 1500 @Test 1501 public void testSelectedPosition11() throws Throwable { 1502 testSetSelectedPosition(true, false, true, false, 1503 false, false, RecyclerView.SCROLL_STATE_IDLE); 1504 } 1505 1506 @Test 1507 public void testSelectedPosition12() throws Throwable { 1508 testSetSelectedPosition(true, false, true, true, 1509 false, true, RecyclerView.SCROLL_STATE_IDLE); 1510 } 1511 1512 @Test 1513 public void testSelectedPosition13() throws Throwable { 1514 testSetSelectedPosition(true, true, false, false, 1515 true, false, RecyclerView.SCROLL_STATE_IDLE); 1516 } 1517 1518 @Test 1519 public void testSelectedPosition14() throws Throwable { 1520 testSetSelectedPosition(true, true, false, true, 1521 true, false, RecyclerView.SCROLL_STATE_IDLE); 1522 } 1523 1524 @Test 1525 public void testSelectedPosition15() throws Throwable { 1526 testSetSelectedPosition(true, true, true, false, 1527 true, false, RecyclerView.SCROLL_STATE_IDLE); 1528 } 1529 1530 @Test 1531 public void testSelectedPosition16() throws Throwable { 1532 testSetSelectedPosition(true, true, true, true, 1533 true, false, RecyclerView.SCROLL_STATE_IDLE); 1534 } 1535 1536 @Test 1537 public void testScrollAndStuck() throws Throwable { 1538 // see b/67370222 fastRelayout() may be stuck. 1539 final int numItems = 19; 1540 final int[] itemsLength = new int[numItems]; 1541 for (int i = 0; i < numItems; i++) { 1542 itemsLength[i] = 288; 1543 } 1544 Intent intent = new Intent(); 1545 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1546 R.layout.horizontal_linear); 1547 intent.putExtra(GridActivity.EXTRA_ITEMS, itemsLength); 1548 initActivity(intent); 1549 mOrientation = BaseGridView.HORIZONTAL; 1550 mNumRows = 1; 1551 1552 // set left right padding to 112, space between items to be 16. 1553 mActivityTestRule.runOnUiThread(new Runnable() { 1554 @Override 1555 public void run() { 1556 ViewGroup.LayoutParams lp = mGridView.getLayoutParams(); 1557 lp.width = 1920; 1558 mGridView.setLayoutParams(lp); 1559 mGridView.setPadding(112, mGridView.getPaddingTop(), 112, 1560 mGridView.getPaddingBottom()); 1561 mGridView.setItemSpacing(16); 1562 } 1563 }); 1564 waitOneUiCycle(); 1565 1566 int scrollPos = 0; 1567 while (true) { 1568 final View view = mGridView.getChildAt(mGridView.getChildCount() - 1); 1569 final int pos = mGridView.getChildViewHolder(view).getAdapterPosition(); 1570 if (scrollPos != pos) { 1571 scrollPos = pos; 1572 mActivityTestRule.runOnUiThread(new Runnable() { 1573 @Override 1574 public void run() { 1575 mGridView.smoothScrollToPosition(pos); 1576 } 1577 }); 1578 } 1579 // wait until we see 2nd from last: 1580 if (pos >= 17) { 1581 if (pos == 17) { 1582 // great we can test fastRelayout() bug. 1583 Thread.sleep(50); 1584 mActivityTestRule.runOnUiThread(new Runnable() { 1585 @Override 1586 public void run() { 1587 view.requestLayout(); 1588 } 1589 }); 1590 } 1591 break; 1592 } 1593 Thread.sleep(16); 1594 } 1595 waitForScrollIdle(); 1596 } 1597 1598 @Test 1599 public void testSwapAfterScroll() throws Throwable { 1600 Intent intent = new Intent(); 1601 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1602 R.layout.horizontal_linear); 1603 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 1604 initActivity(intent); 1605 mOrientation = BaseGridView.HORIZONTAL; 1606 mNumRows = 1; 1607 1608 mActivityTestRule.runOnUiThread(new Runnable() { 1609 @Override 1610 public void run() { 1611 mGridView.getItemAnimator().setMoveDuration(1000); 1612 mGridView.setSelectedPositionSmooth(150); 1613 } 1614 }); 1615 waitForScrollIdle(); 1616 mActivityTestRule.runOnUiThread(new Runnable() { 1617 @Override 1618 public void run() { 1619 mGridView.setSelectedPositionSmooth(151); 1620 } 1621 }); 1622 mActivityTestRule.runOnUiThread(new Runnable() { 1623 @Override 1624 public void run() { 1625 // we want to swap and select new target which is at 150 before swap 1626 mGridView.setSelectedPositionSmooth(150); 1627 mActivity.swap(150, 151); 1628 } 1629 }); 1630 waitForItemAnimation(); 1631 waitForScrollIdle(); 1632 assertEquals(151, mGridView.getSelectedPosition()); 1633 // check if ItemAnimation finishes at aligned positions: 1634 int leftEdge = mGridView.getLayoutManager().findViewByPosition(151).getLeft(); 1635 mActivityTestRule.runOnUiThread(new Runnable() { 1636 @Override 1637 public void run() { 1638 mGridView.requestLayout(); 1639 } 1640 }); 1641 waitForScrollIdle(); 1642 assertEquals(leftEdge, mGridView.getLayoutManager().findViewByPosition(151).getLeft()); 1643 } 1644 1645 void testScrollInSmoothScrolling(final boolean smooth, final boolean scrollToInvisible, 1646 final boolean useRecyclerViewMethod) throws Throwable { 1647 final int numItems = 100; 1648 final int[] itemsLength = new int[numItems]; 1649 for (int i = 0; i < numItems; i++) { 1650 itemsLength[i] = 288; 1651 } 1652 Intent intent = new Intent(); 1653 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1654 R.layout.horizontal_linear); 1655 intent.putExtra(GridActivity.EXTRA_ITEMS, itemsLength); 1656 initActivity(intent); 1657 mOrientation = BaseGridView.HORIZONTAL; 1658 mNumRows = 1; 1659 1660 // start a smoothScroller 1661 final int selectedPosition = 99; 1662 mActivityTestRule.runOnUiThread(new Runnable() { 1663 @Override 1664 public void run() { 1665 mGridView.smoothScrollToPosition(selectedPosition); 1666 } 1667 }); 1668 Thread.sleep(50); 1669 // while smoothScroller is still running, scroll to a different position 1670 final int[] existing_position = new int[1]; 1671 mActivityTestRule.runOnUiThread(new Runnable() { 1672 @Override 1673 public void run() { 1674 existing_position[0] = mGridView.getChildAdapterPosition( 1675 mGridView.getChildAt(mGridView.getChildCount() - 1)); 1676 if (scrollToInvisible) { 1677 existing_position[0] = existing_position[0] + 3; 1678 } 1679 if (useRecyclerViewMethod) { 1680 if (smooth) { 1681 mGridView.smoothScrollToPosition(existing_position[0]); 1682 } else { 1683 mGridView.scrollToPosition(existing_position[0]); 1684 } 1685 } else { 1686 if (smooth) { 1687 mGridView.setSelectedPositionSmooth(existing_position[0]); 1688 } else { 1689 mGridView.setSelectedPosition(existing_position[0]); 1690 } 1691 } 1692 } 1693 }); 1694 waitForScrollIdle(); 1695 assertEquals(existing_position[0], mGridView.getSelectedPosition()); 1696 assertTrue(mGridView.findViewHolderForAdapterPosition(existing_position[0]) 1697 .itemView.hasFocus()); 1698 } 1699 1700 @Test 1701 public void testScrollInSmoothScrolling1() throws Throwable { 1702 testScrollInSmoothScrolling(false, false, false); 1703 } 1704 1705 @Test 1706 public void testScrollInSmoothScrolling2() throws Throwable { 1707 testScrollInSmoothScrolling(false, false, true); 1708 } 1709 1710 @Test 1711 public void testScrollInSmoothScrolling3() throws Throwable { 1712 testScrollInSmoothScrolling(false, true, false); 1713 } 1714 1715 @Test 1716 public void testScrollInSmoothScrolling4() throws Throwable { 1717 testScrollInSmoothScrolling(false, true, true); 1718 } 1719 1720 @Test 1721 public void testScrollInSmoothScrolling5() throws Throwable { 1722 testScrollInSmoothScrolling(true, false, false); 1723 } 1724 1725 @Test 1726 public void testScrollInSmoothScrolling6() throws Throwable { 1727 testScrollInSmoothScrolling(true, false, true); 1728 } 1729 1730 @Test 1731 public void testScrollInSmoothScrolling7() throws Throwable { 1732 testScrollInSmoothScrolling(true, true, false); 1733 } 1734 1735 @Test 1736 public void testScrollInSmoothScrolling8() throws Throwable { 1737 testScrollInSmoothScrolling(true, true, true); 1738 } 1739 1740 @Test 1741 public void testScrollAfterRequestLayout() throws Throwable { 1742 Intent intent = new Intent(); 1743 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1744 R.layout.horizontal_linear); 1745 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10); 1746 initActivity(intent); 1747 mOrientation = BaseGridView.HORIZONTAL; 1748 mNumRows = 1; 1749 mActivityTestRule.runOnUiThread(new Runnable() { 1750 @Override 1751 public void run() { 1752 mGridView.setHasFixedSize(false); 1753 mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE); 1754 mGridView.setWindowAlignmentOffsetPercent(30); 1755 } 1756 }); 1757 waitOneUiCycle(); 1758 1759 final boolean[] scrolled = new boolean[1]; 1760 mGridView.addOnScrollListener(new RecyclerView.OnScrollListener() { 1761 @Override 1762 public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 1763 if (dx != 0) scrolled[0] = true; 1764 } 1765 }); 1766 mActivityTestRule.runOnUiThread(new Runnable() { 1767 @Override 1768 public void run() { 1769 mGridView.requestLayout(); 1770 mGridView.setSelectedPosition(1); 1771 } 1772 }); 1773 waitOneUiCycle(); 1774 assertFalse(scrolled[0]); 1775 } 1776 1777 @Test 1778 public void testScrollAfterItemAnimator() throws Throwable { 1779 Intent intent = new Intent(); 1780 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1781 R.layout.horizontal_linear); 1782 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10); 1783 initActivity(intent); 1784 mOrientation = BaseGridView.HORIZONTAL; 1785 mNumRows = 1; 1786 mActivityTestRule.runOnUiThread(new Runnable() { 1787 @Override 1788 public void run() { 1789 mGridView.setHasFixedSize(false); 1790 mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE); 1791 mGridView.setWindowAlignmentOffsetPercent(30); 1792 } 1793 }); 1794 waitOneUiCycle(); 1795 1796 final boolean[] scrolled = new boolean[1]; 1797 mGridView.addOnScrollListener(new RecyclerView.OnScrollListener() { 1798 @Override 1799 public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 1800 if (dx != 0) scrolled[0] = true; 1801 } 1802 }); 1803 mActivityTestRule.runOnUiThread(new Runnable() { 1804 @Override 1805 public void run() { 1806 mActivity.changeItem(0, 10); 1807 mGridView.setSelectedPosition(1); 1808 } 1809 }); 1810 waitOneUiCycle(); 1811 assertFalse(scrolled[0]); 1812 } 1813 1814 @Test 1815 public void testItemMovedHorizontal() throws Throwable { 1816 Intent intent = new Intent(); 1817 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1818 R.layout.horizontal_grid); 1819 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 1820 initActivity(intent); 1821 mOrientation = BaseGridView.HORIZONTAL; 1822 mNumRows = 3; 1823 1824 mActivityTestRule.runOnUiThread(new Runnable() { 1825 @Override 1826 public void run() { 1827 mGridView.setSelectedPositionSmooth(150); 1828 } 1829 }); 1830 waitForScrollIdle(mVerifyLayout); 1831 performAndWaitForAnimation(new Runnable() { 1832 @Override 1833 public void run() { 1834 mActivity.swap(150, 152); 1835 } 1836 }); 1837 mActivityTestRule.runOnUiThread(mVerifyLayout); 1838 1839 scrollToBegin(mVerifyLayout); 1840 1841 verifyBeginAligned(); 1842 } 1843 1844 @Test 1845 public void testItemMovedHorizontalRtl() throws Throwable { 1846 Intent intent = new Intent(); 1847 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1848 R.layout.horizontal_linear_rtl); 1849 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1850 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[] {40, 40, 40}); 1851 initActivity(intent); 1852 mOrientation = BaseGridView.HORIZONTAL; 1853 mNumRows = 1; 1854 1855 performAndWaitForAnimation(new Runnable() { 1856 @Override 1857 public void run() { 1858 mActivity.moveItem(0, 1, true); 1859 } 1860 }); 1861 assertEquals(mGridView.getWidth() - mGridView.getPaddingRight(), 1862 mGridView.findViewHolderForAdapterPosition(0).itemView.getRight()); 1863 } 1864 1865 @Test 1866 public void testScrollSecondaryCannotScroll() throws Throwable { 1867 Intent intent = new Intent(); 1868 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1869 R.layout.horizontal_grid); 1870 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1871 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000); 1872 initActivity(intent); 1873 mOrientation = BaseGridView.HORIZONTAL; 1874 mNumRows = 3; 1875 final int topPadding = 2; 1876 final int bottomPadding = 2; 1877 final int height = mGridView.getHeight(); 1878 final int spacing = 2; 1879 final int rowHeight = (height - topPadding - bottomPadding) / 4 - spacing; 1880 final HorizontalGridView horizontalGridView = (HorizontalGridView) mGridView; 1881 1882 startWaitLayout(); 1883 mActivityTestRule.runOnUiThread(new Runnable() { 1884 @Override 1885 public void run() { 1886 horizontalGridView.setPadding(0, topPadding, 0, bottomPadding); 1887 horizontalGridView.setItemSpacing(spacing); 1888 horizontalGridView.setNumRows(mNumRows); 1889 horizontalGridView.setRowHeight(rowHeight); 1890 } 1891 }); 1892 waitForLayout(); 1893 // navigate vertically in first column, first row should always be aligned to top padding 1894 for (int i = 0; i < 3; i++) { 1895 setSelectedPosition(i); 1896 assertEquals(topPadding, mGridView.findViewHolderForAdapterPosition(0).itemView 1897 .getTop()); 1898 } 1899 // navigate vertically in 100th column, first row should always be aligned to top padding 1900 for (int i = 300; i < 301; i++) { 1901 setSelectedPosition(i); 1902 assertEquals(topPadding, mGridView.findViewHolderForAdapterPosition(300).itemView 1903 .getTop()); 1904 } 1905 } 1906 1907 @Test 1908 public void testScrollSecondaryNeedScroll() throws Throwable { 1909 Intent intent = new Intent(); 1910 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1911 R.layout.horizontal_grid); 1912 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1913 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000); 1914 initActivity(intent); 1915 mOrientation = BaseGridView.HORIZONTAL; 1916 // test a lot of rows so we have to scroll vertically to reach 1917 mNumRows = 9; 1918 final int topPadding = 2; 1919 final int bottomPadding = 2; 1920 final int height = mGridView.getHeight(); 1921 final int spacing = 2; 1922 final int rowHeight = (height - topPadding - bottomPadding) / 4 - spacing; 1923 final HorizontalGridView horizontalGridView = (HorizontalGridView) mGridView; 1924 1925 startWaitLayout(); 1926 mActivityTestRule.runOnUiThread(new Runnable() { 1927 @Override 1928 public void run() { 1929 horizontalGridView.setPadding(0, topPadding, 0, bottomPadding); 1930 horizontalGridView.setItemSpacing(spacing); 1931 horizontalGridView.setNumRows(mNumRows); 1932 horizontalGridView.setRowHeight(rowHeight); 1933 } 1934 }); 1935 waitForLayout(); 1936 View view; 1937 // first row should be aligned to top padding 1938 setSelectedPosition(0); 1939 assertEquals(topPadding, mGridView.findViewHolderForAdapterPosition(0).itemView.getTop()); 1940 // middle row should be aligned to keyline (1/2 of screen height) 1941 setSelectedPosition(4); 1942 view = mGridView.findViewHolderForAdapterPosition(4).itemView; 1943 assertEquals(height / 2, (view.getTop() + view.getBottom()) / 2); 1944 // last row should be aligned to bottom padding. 1945 setSelectedPosition(8); 1946 view = mGridView.findViewHolderForAdapterPosition(8).itemView; 1947 assertEquals(height, view.getTop() + rowHeight + bottomPadding); 1948 setSelectedPositionSmooth(4); 1949 waitForScrollIdle(); 1950 // middle row should be aligned to keyline (1/2 of screen height) 1951 setSelectedPosition(4); 1952 view = mGridView.findViewHolderForAdapterPosition(4).itemView; 1953 assertEquals(height / 2, (view.getTop() + view.getBottom()) / 2); 1954 // first row should be aligned to top padding 1955 setSelectedPositionSmooth(0); 1956 waitForScrollIdle(); 1957 assertEquals(topPadding, mGridView.findViewHolderForAdapterPosition(0).itemView.getTop()); 1958 } 1959 1960 @Test 1961 public void testItemMovedVertical() throws Throwable { 1962 1963 Intent intent = new Intent(); 1964 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1965 R.layout.vertical_grid); 1966 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 1967 initActivity(intent); 1968 mOrientation = BaseGridView.VERTICAL; 1969 mNumRows = 3; 1970 1971 mGridView.setSelectedPositionSmooth(150); 1972 waitForScrollIdle(mVerifyLayout); 1973 performAndWaitForAnimation(new Runnable() { 1974 @Override 1975 public void run() { 1976 mActivity.swap(150, 152); 1977 } 1978 }); 1979 mActivityTestRule.runOnUiThread(mVerifyLayout); 1980 1981 scrollToEnd(mVerifyLayout); 1982 scrollToBegin(mVerifyLayout); 1983 1984 verifyBeginAligned(); 1985 } 1986 1987 @Test 1988 public void testAddLastItemHorizontal() throws Throwable { 1989 1990 Intent intent = new Intent(); 1991 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1992 R.layout.horizontal_linear); 1993 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50); 1994 initActivity(intent); 1995 mOrientation = BaseGridView.HORIZONTAL; 1996 mNumRows = 1; 1997 1998 mActivityTestRule.runOnUiThread( 1999 new Runnable() { 2000 @Override 2001 public void run() { 2002 mGridView.setSelectedPositionSmooth(49); 2003 } 2004 } 2005 ); 2006 waitForScrollIdle(mVerifyLayout); 2007 performAndWaitForAnimation(new Runnable() { 2008 @Override 2009 public void run() { 2010 mActivity.addItems(50, new int[]{150}); 2011 } 2012 }); 2013 2014 // assert new added item aligned to right edge 2015 assertEquals(mGridView.getWidth() - mGridView.getPaddingRight(), 2016 mGridView.getLayoutManager().findViewByPosition(50).getRight()); 2017 } 2018 2019 @Test 2020 public void testAddMultipleLastItemsHorizontal() throws Throwable { 2021 2022 Intent intent = new Intent(); 2023 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2024 R.layout.horizontal_linear); 2025 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50); 2026 initActivity(intent); 2027 mOrientation = BaseGridView.HORIZONTAL; 2028 mNumRows = 1; 2029 2030 mActivityTestRule.runOnUiThread( 2031 new Runnable() { 2032 @Override 2033 public void run() { 2034 mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_BOTH_EDGE); 2035 mGridView.setWindowAlignmentOffsetPercent(50); 2036 mGridView.setSelectedPositionSmooth(49); 2037 } 2038 } 2039 ); 2040 waitForScrollIdle(mVerifyLayout); 2041 performAndWaitForAnimation(new Runnable() { 2042 @Override 2043 public void run() { 2044 mActivity.addItems(50, new int[]{150, 150, 150, 150, 150, 150, 150, 150, 150, 2045 150, 150, 150, 150, 150}); 2046 } 2047 }); 2048 2049 // The focused item will be at center of window 2050 View view = mGridView.getLayoutManager().findViewByPosition(49); 2051 assertEquals(mGridView.getWidth() / 2, (view.getLeft() + view.getRight()) / 2); 2052 } 2053 2054 @Test 2055 public void testItemAddRemoveHorizontal() throws Throwable { 2056 2057 Intent intent = new Intent(); 2058 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2059 R.layout.horizontal_grid); 2060 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 2061 initActivity(intent); 2062 mOrientation = BaseGridView.HORIZONTAL; 2063 mNumRows = 3; 2064 2065 scrollToEnd(mVerifyLayout); 2066 int[] endEdges = getEndEdges(); 2067 2068 mGridView.setSelectedPositionSmooth(150); 2069 waitForScrollIdle(mVerifyLayout); 2070 performAndWaitForAnimation(new Runnable() { 2071 @Override 2072 public void run() { 2073 mRemovedItems = mActivity.removeItems(151, 4); 2074 } 2075 }); 2076 2077 scrollToEnd(mVerifyLayout); 2078 mGridView.setSelectedPositionSmooth(150); 2079 waitForScrollIdle(mVerifyLayout); 2080 2081 performAndWaitForAnimation(new Runnable() { 2082 @Override 2083 public void run() { 2084 mActivity.addItems(151, mRemovedItems); 2085 } 2086 }); 2087 scrollToEnd(mVerifyLayout); 2088 2089 // we should get same aligned end edges 2090 int[] endEdges2 = getEndEdges(); 2091 verifyEdgesSame(endEdges, endEdges2); 2092 2093 scrollToBegin(mVerifyLayout); 2094 verifyBeginAligned(); 2095 } 2096 2097 @Test 2098 public void testSetSelectedPositionDetached() throws Throwable { 2099 2100 Intent intent = new Intent(); 2101 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2102 R.layout.horizontal_linear); 2103 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50); 2104 initActivity(intent); 2105 mOrientation = BaseGridView.HORIZONTAL; 2106 mNumRows = 1; 2107 2108 final int focusToIndex = 49; 2109 final ViewGroup parent = (ViewGroup) mGridView.getParent(); 2110 mActivityTestRule.runOnUiThread(new Runnable() { 2111 @Override 2112 public void run() { 2113 parent.removeView(mGridView); 2114 } 2115 }); 2116 mActivityTestRule.runOnUiThread(new Runnable() { 2117 @Override 2118 public void run() { 2119 mGridView.setSelectedPositionSmooth(focusToIndex); 2120 } 2121 }); 2122 mActivityTestRule.runOnUiThread(new Runnable() { 2123 @Override 2124 public void run() { 2125 parent.addView(mGridView); 2126 mGridView.requestFocus(); 2127 } 2128 }); 2129 waitForScrollIdle(); 2130 assertEquals(mGridView.getSelectedPosition(), focusToIndex); 2131 assertTrue(mGridView.getLayoutManager().findViewByPosition(focusToIndex).hasFocus()); 2132 2133 final int focusToIndex2 = 0; 2134 mActivityTestRule.runOnUiThread(new Runnable() { 2135 @Override 2136 public void run() { 2137 parent.removeView(mGridView); 2138 } 2139 }); 2140 mActivityTestRule.runOnUiThread(new Runnable() { 2141 @Override 2142 public void run() { 2143 mGridView.setSelectedPosition(focusToIndex2); 2144 } 2145 }); 2146 mActivityTestRule.runOnUiThread(new Runnable() { 2147 @Override 2148 public void run() { 2149 parent.addView(mGridView); 2150 mGridView.requestFocus(); 2151 } 2152 }); 2153 assertEquals(mGridView.getSelectedPosition(), focusToIndex2); 2154 waitForScrollIdle(); 2155 assertTrue(mGridView.getLayoutManager().findViewByPosition(focusToIndex2).hasFocus()); 2156 } 2157 2158 @Test 2159 public void testBug22209986() throws Throwable { 2160 2161 Intent intent = new Intent(); 2162 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2163 R.layout.horizontal_linear); 2164 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50); 2165 initActivity(intent); 2166 mOrientation = BaseGridView.HORIZONTAL; 2167 mNumRows = 1; 2168 2169 final int focusToIndex = mGridView.getChildCount() - 1; 2170 mActivityTestRule.runOnUiThread(new Runnable() { 2171 @Override 2172 public void run() { 2173 mGridView.setSelectedPositionSmooth(focusToIndex); 2174 } 2175 }); 2176 2177 waitForScrollIdle(); 2178 mActivityTestRule.runOnUiThread(new Runnable() { 2179 @Override 2180 public void run() { 2181 mGridView.setSelectedPositionSmooth(focusToIndex + 1); 2182 } 2183 }); 2184 // let the scroll running for a while and requestLayout during scroll 2185 Thread.sleep(80); 2186 mActivityTestRule.runOnUiThread(new Runnable() { 2187 @Override 2188 public void run() { 2189 assertEquals(mGridView.getScrollState(), BaseGridView.SCROLL_STATE_SETTLING); 2190 mGridView.requestLayout(); 2191 } 2192 }); 2193 waitForScrollIdle(); 2194 2195 int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft(); 2196 2197 mActivityTestRule.runOnUiThread(new Runnable() { 2198 @Override 2199 public void run() { 2200 mGridView.requestLayout(); 2201 } 2202 }); 2203 waitForScrollIdle(); 2204 assertEquals(leftEdge, 2205 mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft()); 2206 } 2207 2208 void testScrollAndRemove(int[] itemsLength, int numItems) throws Throwable { 2209 2210 Intent intent = new Intent(); 2211 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2212 R.layout.horizontal_linear); 2213 if (itemsLength != null) { 2214 intent.putExtra(GridActivity.EXTRA_ITEMS, itemsLength); 2215 } else { 2216 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 2217 } 2218 initActivity(intent); 2219 mOrientation = BaseGridView.HORIZONTAL; 2220 mNumRows = 1; 2221 2222 final int focusToIndex = mGridView.getChildCount() - 1; 2223 mActivityTestRule.runOnUiThread(new Runnable() { 2224 @Override 2225 public void run() { 2226 mGridView.setSelectedPositionSmooth(focusToIndex); 2227 } 2228 }); 2229 2230 performAndWaitForAnimation(new Runnable() { 2231 @Override 2232 public void run() { 2233 mActivity.removeItems(focusToIndex, 1); 2234 } 2235 }); 2236 2237 waitOneUiCycle(); 2238 waitForScrollIdle(); 2239 int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft(); 2240 2241 mActivityTestRule.runOnUiThread(new Runnable() { 2242 @Override 2243 public void run() { 2244 mGridView.requestLayout(); 2245 } 2246 }); 2247 waitForScrollIdle(); 2248 assertEquals(leftEdge, 2249 mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft(), DELTA); 2250 } 2251 2252 @Test 2253 public void testScrollAndRemove() throws Throwable { 2254 // test random lengths for 50 items 2255 testScrollAndRemove(null, 50); 2256 } 2257 2258 /** 2259 * This test verifies if scroll limits are ignored when onLayoutChildren compensate remaining 2260 * scroll distance. b/64931938 2261 * In the test, second child is long, other children are short. 2262 * Test scrolls to the long child, and when scrolling, remove the long child. We made it long 2263 * to have enough remaining scroll distance when the layout pass kicks in. 2264 * The onLayoutChildren() would compensate the remaining scroll distance, moving all items 2265 * toward right, which will make the first item's left edge bigger than left padding, 2266 * which would violate the "scroll limit of left" in a regular scroll case, but 2267 * in layout pass, we still honor that scroll request, ignoring the scroll limit. 2268 */ 2269 @Test 2270 public void testScrollAndRemoveSample1() throws Throwable { 2271 DisplayMetrics dm = InstrumentationRegistry.getInstrumentation().getTargetContext() 2272 .getResources().getDisplayMetrics(); 2273 // screen width for long item and 4DP for other items 2274 int longItemLength = dm.widthPixels; 2275 int shortItemLength = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, dm); 2276 int[] items = new int[1000]; 2277 for (int i = 0; i < items.length; i++) { 2278 items[i] = shortItemLength; 2279 } 2280 items[1] = longItemLength; 2281 testScrollAndRemove(items, 0); 2282 } 2283 2284 @Test 2285 public void testScrollAndInsert() throws Throwable { 2286 2287 Intent intent = new Intent(); 2288 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2289 R.layout.vertical_grid); 2290 int[] items = new int[1000]; 2291 for (int i = 0; i < items.length; i++) { 2292 items[i] = 300 + (int)(Math.random() * 100); 2293 } 2294 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 2295 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 2296 mOrientation = BaseGridView.VERTICAL; 2297 mNumRows = 3; 2298 2299 initActivity(intent); 2300 2301 mActivityTestRule.runOnUiThread(new Runnable() { 2302 @Override 2303 public void run() { 2304 mGridView.setSelectedPositionSmooth(150); 2305 } 2306 }); 2307 waitForScrollIdle(mVerifyLayout); 2308 2309 View view = mGridView.getChildAt(mGridView.getChildCount() - 1); 2310 final int focusToIndex = mGridView.getChildAdapterPosition(view); 2311 mActivityTestRule.runOnUiThread(new Runnable() { 2312 @Override 2313 public void run() { 2314 mGridView.setSelectedPositionSmooth(focusToIndex); 2315 } 2316 }); 2317 2318 mActivityTestRule.runOnUiThread(new Runnable() { 2319 @Override 2320 public void run() { 2321 int[] newItems = new int[]{300, 300, 300}; 2322 mActivity.addItems(0, newItems); 2323 } 2324 }); 2325 waitForScrollIdle(); 2326 int topEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getTop(); 2327 mActivityTestRule.runOnUiThread(new Runnable() { 2328 @Override 2329 public void run() { 2330 mGridView.requestLayout(); 2331 } 2332 }); 2333 waitForScrollIdle(); 2334 assertEquals(topEdge, 2335 mGridView.getLayoutManager().findViewByPosition(focusToIndex).getTop()); 2336 } 2337 2338 @Test 2339 public void testScrollAndInsertBeforeVisibleItem() throws Throwable { 2340 2341 Intent intent = new Intent(); 2342 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2343 R.layout.vertical_grid); 2344 int[] items = new int[1000]; 2345 for (int i = 0; i < items.length; i++) { 2346 items[i] = 300 + (int)(Math.random() * 100); 2347 } 2348 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 2349 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 2350 mOrientation = BaseGridView.VERTICAL; 2351 mNumRows = 3; 2352 2353 initActivity(intent); 2354 2355 mActivityTestRule.runOnUiThread(new Runnable() { 2356 @Override 2357 public void run() { 2358 mGridView.setSelectedPositionSmooth(150); 2359 } 2360 }); 2361 waitForScrollIdle(mVerifyLayout); 2362 2363 View view = mGridView.getChildAt(mGridView.getChildCount() - 1); 2364 final int focusToIndex = mGridView.getChildAdapterPosition(view); 2365 mActivityTestRule.runOnUiThread(new Runnable() { 2366 @Override 2367 public void run() { 2368 mGridView.setSelectedPositionSmooth(focusToIndex); 2369 } 2370 }); 2371 2372 performAndWaitForAnimation(new Runnable() { 2373 @Override 2374 public void run() { 2375 int[] newItems = new int[]{300, 300, 300}; 2376 mActivity.addItems(focusToIndex, newItems); 2377 } 2378 }); 2379 } 2380 2381 @Test 2382 public void testSmoothScrollAndRemove() throws Throwable { 2383 2384 Intent intent = new Intent(); 2385 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2386 R.layout.horizontal_linear); 2387 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 300); 2388 initActivity(intent); 2389 mOrientation = BaseGridView.HORIZONTAL; 2390 mNumRows = 1; 2391 2392 final int focusToIndex = 200; 2393 mActivityTestRule.runOnUiThread(new Runnable() { 2394 @Override 2395 public void run() { 2396 mGridView.setSelectedPositionSmooth(focusToIndex); 2397 } 2398 }); 2399 2400 mActivityTestRule.runOnUiThread(new Runnable() { 2401 @Override 2402 public void run() { 2403 mActivity.removeItems(focusToIndex, 1); 2404 } 2405 }); 2406 2407 assertTrue("removing the index of not attached child should not affect smooth scroller", 2408 mGridView.getLayoutManager().isSmoothScrolling()); 2409 waitForScrollIdle(); 2410 int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft(); 2411 2412 mActivityTestRule.runOnUiThread(new Runnable() { 2413 @Override 2414 public void run() { 2415 mGridView.requestLayout(); 2416 } 2417 }); 2418 waitForScrollIdle(); 2419 assertEquals(leftEdge, 2420 mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft()); 2421 } 2422 2423 @Test 2424 public void testSmoothScrollAndRemove2() throws Throwable { 2425 2426 Intent intent = new Intent(); 2427 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2428 R.layout.horizontal_linear); 2429 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 300); 2430 initActivity(intent); 2431 mOrientation = BaseGridView.HORIZONTAL; 2432 mNumRows = 1; 2433 2434 final int focusToIndex = 200; 2435 mActivityTestRule.runOnUiThread(new Runnable() { 2436 @Override 2437 public void run() { 2438 mGridView.setSelectedPositionSmooth(focusToIndex); 2439 } 2440 }); 2441 2442 startWaitLayout(); 2443 mActivityTestRule.runOnUiThread(new Runnable() { 2444 @Override 2445 public void run() { 2446 final int removeIndex = mGridView.getChildViewHolder( 2447 mGridView.getChildAt(mGridView.getChildCount() - 1)).getAdapterPosition(); 2448 mActivity.removeItems(removeIndex, 1); 2449 } 2450 }); 2451 waitForLayout(); 2452 2453 assertTrue("removing the index of attached child should not kill smooth scroller", 2454 mGridView.getLayoutManager().isSmoothScrolling()); 2455 waitForItemAnimation(); 2456 waitForScrollIdle(); 2457 int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft(); 2458 2459 mActivityTestRule.runOnUiThread(new Runnable() { 2460 @Override 2461 public void run() { 2462 mGridView.requestLayout(); 2463 } 2464 }); 2465 waitForScrollIdle(); 2466 assertEquals(leftEdge, 2467 mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft()); 2468 } 2469 2470 @Test 2471 public void testPendingSmoothScrollAndRemove() throws Throwable { 2472 Intent intent = new Intent(); 2473 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2474 R.layout.vertical_linear); 2475 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 2476 int[] items = new int[100]; 2477 for (int i = 0; i < items.length; i++) { 2478 items[i] = 630 + (int)(Math.random() * 100); 2479 } 2480 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 2481 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 2482 mOrientation = BaseGridView.VERTICAL; 2483 mNumRows = 1; 2484 2485 initActivity(intent); 2486 2487 mGridView.setSelectedPositionSmooth(0); 2488 waitForScrollIdle(mVerifyLayout); 2489 assertTrue(mGridView.getChildAt(0).hasFocus()); 2490 2491 // Pressing lots of key to make sure smooth scroller is running 2492 mGridView.mLayoutManager.mMaxPendingMoves = 100; 2493 for (int i = 0; i < 100; i++) { 2494 sendKey(KeyEvent.KEYCODE_DPAD_DOWN); 2495 } 2496 2497 assertTrue(mGridView.getLayoutManager().isSmoothScrolling()); 2498 startWaitLayout(); 2499 mActivityTestRule.runOnUiThread(new Runnable() { 2500 @Override 2501 public void run() { 2502 final int removeIndex = mGridView.getChildViewHolder( 2503 mGridView.getChildAt(mGridView.getChildCount() - 1)).getAdapterPosition(); 2504 mActivity.removeItems(removeIndex, 1); 2505 } 2506 }); 2507 waitForLayout(); 2508 2509 assertTrue("removing the index of attached child should not kill smooth scroller", 2510 mGridView.getLayoutManager().isSmoothScrolling()); 2511 2512 waitForItemAnimation(); 2513 waitForScrollIdle(); 2514 int focusIndex = mGridView.getSelectedPosition(); 2515 int topEdge = mGridView.getLayoutManager().findViewByPosition(focusIndex).getTop(); 2516 2517 mActivityTestRule.runOnUiThread(new Runnable() { 2518 @Override 2519 public void run() { 2520 mGridView.requestLayout(); 2521 } 2522 }); 2523 waitForScrollIdle(); 2524 assertEquals(topEdge, 2525 mGridView.getLayoutManager().findViewByPosition(focusIndex).getTop()); 2526 } 2527 2528 @Test 2529 public void testFocusToFirstItem() throws Throwable { 2530 2531 Intent intent = new Intent(); 2532 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2533 R.layout.horizontal_grid); 2534 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 2535 initActivity(intent); 2536 mOrientation = BaseGridView.HORIZONTAL; 2537 mNumRows = 3; 2538 2539 performAndWaitForAnimation(new Runnable() { 2540 @Override 2541 public void run() { 2542 mRemovedItems = mActivity.removeItems(0, 200); 2543 } 2544 }); 2545 2546 humanDelay(500); 2547 performAndWaitForAnimation(new Runnable() { 2548 @Override 2549 public void run() { 2550 mActivity.addItems(0, mRemovedItems); 2551 } 2552 }); 2553 2554 humanDelay(500); 2555 assertTrue(mGridView.getLayoutManager().findViewByPosition(0).hasFocus()); 2556 2557 changeArraySize(0); 2558 2559 changeArraySize(200); 2560 assertTrue(mGridView.getLayoutManager().findViewByPosition(0).hasFocus()); 2561 } 2562 2563 @Test 2564 public void testNonFocusableHorizontal() throws Throwable { 2565 final int numItems = 200; 2566 final int startPos = 45; 2567 final int skips = 20; 2568 final int numColumns = 3; 2569 final int endPos = startPos + numColumns * (skips + 1); 2570 2571 Intent intent = new Intent(); 2572 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2573 R.layout.horizontal_grid); 2574 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 2575 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2576 mOrientation = BaseGridView.HORIZONTAL; 2577 mNumRows = numColumns; 2578 boolean[] focusable = new boolean[numItems]; 2579 for (int i = 0; i < focusable.length; i++) { 2580 focusable[i] = true; 2581 } 2582 for (int i = startPos + mNumRows, j = 0; j < skips; i += mNumRows, j++) { 2583 focusable[i] = false; 2584 } 2585 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 2586 initActivity(intent); 2587 2588 mGridView.setSelectedPositionSmooth(startPos); 2589 waitForScrollIdle(mVerifyLayout); 2590 2591 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 2592 sendKey(KeyEvent.KEYCODE_DPAD_LEFT); 2593 } else { 2594 sendKey(KeyEvent.KEYCODE_DPAD_RIGHT); 2595 } 2596 waitForScrollIdle(mVerifyLayout); 2597 assertEquals(endPos, mGridView.getSelectedPosition()); 2598 2599 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 2600 sendKey(KeyEvent.KEYCODE_DPAD_RIGHT); 2601 } else { 2602 sendKey(KeyEvent.KEYCODE_DPAD_LEFT); 2603 } 2604 waitForScrollIdle(mVerifyLayout); 2605 assertEquals(startPos, mGridView.getSelectedPosition()); 2606 2607 } 2608 2609 @Test 2610 public void testNoInitialFocusable() throws Throwable { 2611 2612 Intent intent = new Intent(); 2613 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2614 R.layout.horizontal_linear); 2615 final int numItems = 100; 2616 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 2617 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2618 mOrientation = BaseGridView.HORIZONTAL; 2619 mNumRows = 1; 2620 boolean[] focusable = new boolean[numItems]; 2621 final int firstFocusableIndex = 10; 2622 for (int i = 0; i < firstFocusableIndex; i++) { 2623 focusable[i] = false; 2624 } 2625 for (int i = firstFocusableIndex; i < focusable.length; i++) { 2626 focusable[i] = true; 2627 } 2628 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 2629 initActivity(intent); 2630 assertTrue(mGridView.isFocused()); 2631 2632 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 2633 sendKey(KeyEvent.KEYCODE_DPAD_LEFT); 2634 } else { 2635 sendKey(KeyEvent.KEYCODE_DPAD_RIGHT); 2636 } 2637 waitForScrollIdle(mVerifyLayout); 2638 assertEquals(firstFocusableIndex, mGridView.getSelectedPosition()); 2639 assertTrue(mGridView.getLayoutManager().findViewByPosition(firstFocusableIndex).hasFocus()); 2640 } 2641 2642 @Test 2643 public void testFocusOutOfEmptyListView() throws Throwable { 2644 2645 Intent intent = new Intent(); 2646 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2647 R.layout.horizontal_linear); 2648 final int numItems = 100; 2649 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 2650 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2651 mOrientation = BaseGridView.HORIZONTAL; 2652 mNumRows = 1; 2653 initActivity(intent); 2654 2655 final View horizontalGridView = new HorizontalGridViewEx(mGridView.getContext()); 2656 mActivityTestRule.runOnUiThread(new Runnable() { 2657 @Override 2658 public void run() { 2659 horizontalGridView.setFocusable(true); 2660 horizontalGridView.setFocusableInTouchMode(true); 2661 horizontalGridView.setLayoutParams(new ViewGroup.LayoutParams(100, 100)); 2662 ((ViewGroup) mGridView.getParent()).addView(horizontalGridView, 0); 2663 horizontalGridView.requestFocus(); 2664 } 2665 }); 2666 2667 assertTrue(horizontalGridView.isFocused()); 2668 2669 sendKey(KeyEvent.KEYCODE_DPAD_DOWN); 2670 2671 assertTrue(mGridView.hasFocus()); 2672 } 2673 2674 @Test 2675 public void testTransferFocusToChildWhenGainFocus() throws Throwable { 2676 2677 Intent intent = new Intent(); 2678 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2679 R.layout.horizontal_linear); 2680 final int numItems = 100; 2681 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 2682 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2683 mOrientation = BaseGridView.HORIZONTAL; 2684 mNumRows = 1; 2685 boolean[] focusable = new boolean[numItems]; 2686 final int firstFocusableIndex = 1; 2687 for (int i = 0; i < firstFocusableIndex; i++) { 2688 focusable[i] = false; 2689 } 2690 for (int i = firstFocusableIndex; i < focusable.length; i++) { 2691 focusable[i] = true; 2692 } 2693 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 2694 initActivity(intent); 2695 2696 assertEquals(firstFocusableIndex, mGridView.getSelectedPosition()); 2697 assertTrue(mGridView.getLayoutManager().findViewByPosition(firstFocusableIndex).hasFocus()); 2698 } 2699 2700 @Test 2701 public void testFocusFromSecondChild() throws Throwable { 2702 2703 Intent intent = new Intent(); 2704 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2705 R.layout.horizontal_linear); 2706 final int numItems = 100; 2707 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 2708 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2709 mOrientation = BaseGridView.HORIZONTAL; 2710 mNumRows = 1; 2711 boolean[] focusable = new boolean[numItems]; 2712 for (int i = 0; i < focusable.length; i++) { 2713 focusable[i] = false; 2714 } 2715 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 2716 initActivity(intent); 2717 2718 // switching Adapter to cause a full rebind, test if it will focus to second item. 2719 performAndWaitForAnimation(new Runnable() { 2720 @Override 2721 public void run() { 2722 mActivity.mNumItems = numItems; 2723 mActivity.mItemFocusables[1] = true; 2724 mActivity.rebindToNewAdapter(); 2725 } 2726 }); 2727 assertTrue(mGridView.findViewHolderForAdapterPosition(1).itemView.hasFocus()); 2728 } 2729 2730 @Test 2731 public void removeFocusableItemAndFocusableRecyclerViewGetsFocus() throws Throwable { 2732 final int numItems = 100; 2733 final int numColumns = 3; 2734 final int focusableIndex = 2; 2735 2736 Intent intent = new Intent(); 2737 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2738 R.layout.vertical_grid); 2739 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 2740 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2741 mOrientation = BaseGridView.VERTICAL; 2742 mNumRows = numColumns; 2743 boolean[] focusable = new boolean[numItems]; 2744 for (int i = 0; i < focusable.length; i++) { 2745 focusable[i] = false; 2746 } 2747 focusable[focusableIndex] = true; 2748 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 2749 initActivity(intent); 2750 2751 mActivityTestRule.runOnUiThread(new Runnable() { 2752 @Override 2753 public void run() { 2754 mGridView.setSelectedPositionSmooth(focusableIndex); 2755 } 2756 }); 2757 waitForScrollIdle(mVerifyLayout); 2758 assertEquals(focusableIndex, mGridView.getSelectedPosition()); 2759 2760 performAndWaitForAnimation(new Runnable() { 2761 @Override 2762 public void run() { 2763 mActivity.removeItems(focusableIndex, 1); 2764 } 2765 }); 2766 assertTrue(dumpGridView(mGridView), mGridView.isFocused()); 2767 } 2768 2769 @Test 2770 public void removeFocusableItemAndUnFocusableRecyclerViewLosesFocus() throws Throwable { 2771 final int numItems = 100; 2772 final int numColumns = 3; 2773 final int focusableIndex = 2; 2774 2775 Intent intent = new Intent(); 2776 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2777 R.layout.vertical_grid); 2778 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 2779 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2780 mOrientation = BaseGridView.VERTICAL; 2781 mNumRows = numColumns; 2782 boolean[] focusable = new boolean[numItems]; 2783 for (int i = 0; i < focusable.length; i++) { 2784 focusable[i] = false; 2785 } 2786 focusable[focusableIndex] = true; 2787 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 2788 initActivity(intent); 2789 2790 mActivityTestRule.runOnUiThread(new Runnable() { 2791 @Override 2792 public void run() { 2793 mGridView.setFocusableInTouchMode(false); 2794 mGridView.setFocusable(false); 2795 mGridView.setSelectedPositionSmooth(focusableIndex); 2796 } 2797 }); 2798 waitForScrollIdle(mVerifyLayout); 2799 assertEquals(focusableIndex, mGridView.getSelectedPosition()); 2800 2801 performAndWaitForAnimation(new Runnable() { 2802 @Override 2803 public void run() { 2804 mActivity.removeItems(focusableIndex, 1); 2805 } 2806 }); 2807 assertFalse(dumpGridView(mGridView), mGridView.hasFocus()); 2808 } 2809 2810 @Test 2811 public void testNonFocusableVertical() throws Throwable { 2812 final int numItems = 200; 2813 final int startPos = 44; 2814 final int skips = 20; 2815 final int numColumns = 3; 2816 final int endPos = startPos + numColumns * (skips + 1); 2817 2818 Intent intent = new Intent(); 2819 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2820 R.layout.vertical_grid); 2821 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 2822 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2823 mOrientation = BaseGridView.VERTICAL; 2824 mNumRows = numColumns; 2825 boolean[] focusable = new boolean[numItems]; 2826 for (int i = 0; i < focusable.length; i++) { 2827 focusable[i] = true; 2828 } 2829 for (int i = startPos + mNumRows, j = 0; j < skips; i += mNumRows, j++) { 2830 focusable[i] = false; 2831 } 2832 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 2833 initActivity(intent); 2834 2835 mGridView.setSelectedPositionSmooth(startPos); 2836 waitForScrollIdle(mVerifyLayout); 2837 2838 sendKey(KeyEvent.KEYCODE_DPAD_DOWN); 2839 waitForScrollIdle(mVerifyLayout); 2840 assertEquals(endPos, mGridView.getSelectedPosition()); 2841 2842 sendKey(KeyEvent.KEYCODE_DPAD_UP); 2843 waitForScrollIdle(mVerifyLayout); 2844 assertEquals(startPos, mGridView.getSelectedPosition()); 2845 2846 } 2847 2848 @Test 2849 public void testLtrFocusOutStartDisabled() throws Throwable { 2850 final int numItems = 200; 2851 2852 Intent intent = new Intent(); 2853 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid_ltr); 2854 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 2855 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2856 mOrientation = BaseGridView.VERTICAL; 2857 mNumRows = 2; 2858 initActivity(intent); 2859 2860 mActivityTestRule.runOnUiThread(new Runnable() { 2861 @Override 2862 public void run() { 2863 mGridView.requestFocus(); 2864 mGridView.setSelectedPositionSmooth(0); 2865 } 2866 }); 2867 waitForScrollIdle(mVerifyLayout); 2868 2869 sendKey(KeyEvent.KEYCODE_DPAD_LEFT); 2870 waitForScrollIdle(mVerifyLayout); 2871 assertTrue(mGridView.hasFocus()); 2872 } 2873 2874 @Test 2875 public void testVerticalGridRtl() throws Throwable { 2876 final int numItems = 200; 2877 2878 Intent intent = new Intent(); 2879 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid_rtl); 2880 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 2881 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2882 mOrientation = BaseGridView.VERTICAL; 2883 mNumRows = 2; 2884 initActivity(intent); 2885 2886 waitForScrollIdle(mVerifyLayout); 2887 2888 View item0 = mGridView.findViewHolderForAdapterPosition(0).itemView; 2889 View item1 = mGridView.findViewHolderForAdapterPosition(1).itemView; 2890 assertEquals(mGridView.getWidth() - mGridView.getPaddingRight(), item0.getRight()); 2891 assertEquals(item0.getLeft(), item1.getRight() + mGridView.getHorizontalSpacing()); 2892 } 2893 2894 @Test 2895 public void testRtlFocusOutStartDisabled() throws Throwable { 2896 final int numItems = 200; 2897 2898 Intent intent = new Intent(); 2899 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid_rtl); 2900 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 2901 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2902 mOrientation = BaseGridView.VERTICAL; 2903 mNumRows = 1; 2904 initActivity(intent); 2905 2906 mActivityTestRule.runOnUiThread(new Runnable() { 2907 @Override 2908 public void run() { 2909 mGridView.requestFocus(); 2910 mGridView.setSelectedPositionSmooth(0); 2911 } 2912 }); 2913 waitForScrollIdle(mVerifyLayout); 2914 2915 sendKey(KeyEvent.KEYCODE_DPAD_RIGHT); 2916 waitForScrollIdle(mVerifyLayout); 2917 assertTrue(mGridView.hasFocus()); 2918 } 2919 2920 @Test 2921 public void testTransferFocusable() throws Throwable { 2922 final int numItems = 200; 2923 final int numColumns = 3; 2924 final int startPos = 1; 2925 2926 Intent intent = new Intent(); 2927 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2928 R.layout.horizontal_grid); 2929 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 2930 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2931 mOrientation = BaseGridView.HORIZONTAL; 2932 mNumRows = numColumns; 2933 boolean[] focusable = new boolean[numItems]; 2934 for (int i = 0; i < focusable.length; i++) { 2935 focusable[i] = true; 2936 } 2937 for (int i = 0; i < startPos; i++) { 2938 focusable[i] = false; 2939 } 2940 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 2941 initActivity(intent); 2942 2943 changeArraySize(0); 2944 assertTrue(mGridView.isFocused()); 2945 2946 changeArraySize(numItems); 2947 assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus()); 2948 } 2949 2950 @Test 2951 public void testTransferFocusable2() throws Throwable { 2952 final int numItems = 200; 2953 final int numColumns = 3; 2954 final int startPos = 3; // make sure view at startPos is in visible area. 2955 2956 Intent intent = new Intent(); 2957 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2958 R.layout.horizontal_grid); 2959 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 2960 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 2961 mOrientation = BaseGridView.HORIZONTAL; 2962 mNumRows = numColumns; 2963 boolean[] focusable = new boolean[numItems]; 2964 for (int i = 0; i < focusable.length; i++) { 2965 focusable[i] = true; 2966 } 2967 for (int i = 0; i < startPos; i++) { 2968 focusable[i] = false; 2969 } 2970 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 2971 initActivity(intent); 2972 2973 assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus()); 2974 2975 changeArraySize(0); 2976 assertTrue(mGridView.isFocused()); 2977 2978 changeArraySize(numItems); 2979 assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus()); 2980 } 2981 2982 @Test 2983 public void testNonFocusableLoseInFastLayout() throws Throwable { 2984 Intent intent = new Intent(); 2985 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2986 R.layout.vertical_linear); 2987 int[] items = new int[300]; 2988 for (int i = 0; i < items.length; i++) { 2989 items[i] = 480; 2990 } 2991 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 2992 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2993 intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true); 2994 mOrientation = BaseGridView.VERTICAL; 2995 mNumRows = 1; 2996 int pressDown = 15; 2997 2998 initActivity(intent); 2999 3000 mGridView.setSelectedPositionSmooth(0); 3001 waitForScrollIdle(mVerifyLayout); 3002 3003 for (int i = 0; i < pressDown; i++) { 3004 sendKey(KeyEvent.KEYCODE_DPAD_DOWN); 3005 } 3006 waitForScrollIdle(mVerifyLayout); 3007 assertFalse(mGridView.isFocused()); 3008 3009 } 3010 3011 @Test 3012 public void testFocusableViewAvailable() throws Throwable { 3013 Intent intent = new Intent(); 3014 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3015 R.layout.vertical_linear); 3016 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0); 3017 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3018 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, 3019 new boolean[]{false, false, true, false, false}); 3020 mOrientation = BaseGridView.VERTICAL; 3021 mNumRows = 1; 3022 3023 initActivity(intent); 3024 3025 mActivityTestRule.runOnUiThread(new Runnable() { 3026 @Override 3027 public void run() { 3028 // RecyclerView does not respect focusable and focusableInTouchMode flag, so 3029 // set flags in code. 3030 mGridView.setFocusableInTouchMode(false); 3031 mGridView.setFocusable(false); 3032 } 3033 }); 3034 3035 assertFalse(mGridView.isFocused()); 3036 3037 final boolean[] scrolled = new boolean[]{false}; 3038 mGridView.addOnScrollListener(new RecyclerView.OnScrollListener() { 3039 @Override 3040 public void onScrolled(RecyclerView recyclerView, int dx, int dy){ 3041 if (dy > 0) { 3042 scrolled[0] = true; 3043 } 3044 } 3045 }); 3046 performAndWaitForAnimation(new Runnable() { 3047 @Override 3048 public void run() { 3049 mActivity.addItems(0, new int[]{200, 300, 500, 500, 200}); 3050 } 3051 }); 3052 waitForScrollIdle(mVerifyLayout); 3053 3054 assertFalse("GridView should not be scrolled", scrolled[0]); 3055 assertTrue(mGridView.getLayoutManager().findViewByPosition(2).hasFocus()); 3056 3057 } 3058 3059 @Test 3060 public void testSetSelectionWithDelta() throws Throwable { 3061 Intent intent = new Intent(); 3062 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3063 R.layout.vertical_linear); 3064 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 300); 3065 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3066 mOrientation = BaseGridView.VERTICAL; 3067 mNumRows = 1; 3068 3069 initActivity(intent); 3070 3071 mActivityTestRule.runOnUiThread(new Runnable() { 3072 @Override 3073 public void run() { 3074 mGridView.setSelectedPositionSmooth(3); 3075 } 3076 }); 3077 waitForScrollIdle(mVerifyLayout); 3078 int top1 = mGridView.getLayoutManager().findViewByPosition(3).getTop(); 3079 3080 humanDelay(1000); 3081 3082 // scroll to position with delta 3083 setSelectedPosition(3, 100); 3084 int top2 = mGridView.getLayoutManager().findViewByPosition(3).getTop(); 3085 assertEquals(top1 - 100, top2); 3086 3087 // scroll to same position without delta, it will be reset 3088 setSelectedPosition(3, 0); 3089 int top3 = mGridView.getLayoutManager().findViewByPosition(3).getTop(); 3090 assertEquals(top1, top3); 3091 3092 // scroll invisible item after last visible item 3093 final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 3094 .mGrid.getLastVisibleIndex(); 3095 setSelectedPosition(lastVisiblePos + 1, 100); 3096 int top4 = mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1).getTop(); 3097 assertEquals(top1 - 100, top4); 3098 3099 // scroll invisible item before first visible item 3100 final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 3101 .mGrid.getFirstVisibleIndex(); 3102 setSelectedPosition(firstVisiblePos - 1, 100); 3103 int top5 = mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1).getTop(); 3104 assertEquals(top1 - 100, top5); 3105 3106 // scroll to invisible item that is far away. 3107 setSelectedPosition(50, 100); 3108 int top6 = mGridView.getLayoutManager().findViewByPosition(50).getTop(); 3109 assertEquals(top1 - 100, top6); 3110 3111 // scroll to invisible item that is far away. 3112 mActivityTestRule.runOnUiThread(new Runnable() { 3113 @Override 3114 public void run() { 3115 mGridView.setSelectedPositionSmooth(100); 3116 } 3117 }); 3118 waitForScrollIdle(mVerifyLayout); 3119 int top7 = mGridView.getLayoutManager().findViewByPosition(100).getTop(); 3120 assertEquals(top1, top7); 3121 3122 // scroll to invisible item that is far away. 3123 setSelectedPosition(10, 50); 3124 int top8 = mGridView.getLayoutManager().findViewByPosition(10).getTop(); 3125 assertEquals(top1 - 50, top8); 3126 } 3127 3128 @Test 3129 public void testSetSelectionWithDeltaInGrid() throws Throwable { 3130 Intent intent = new Intent(); 3131 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3132 R.layout.vertical_grid); 3133 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500); 3134 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 3135 mOrientation = BaseGridView.VERTICAL; 3136 mNumRows = 3; 3137 3138 initActivity(intent); 3139 3140 mActivityTestRule.runOnUiThread(new Runnable() { 3141 @Override 3142 public void run() { 3143 mGridView.setSelectedPositionSmooth(10); 3144 } 3145 }); 3146 waitForScrollIdle(mVerifyLayout); 3147 int top1 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10)); 3148 3149 humanDelay(500); 3150 3151 // scroll to position with delta 3152 setSelectedPosition(20, 100); 3153 int top2 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20)); 3154 assertEquals(top1 - 100, top2); 3155 3156 // scroll to same position without delta, it will be reset 3157 setSelectedPosition(20, 0); 3158 int top3 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20)); 3159 assertEquals(top1, top3); 3160 3161 // scroll invisible item after last visible item 3162 final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 3163 .mGrid.getLastVisibleIndex(); 3164 setSelectedPosition(lastVisiblePos + 1, 100); 3165 int top4 = getCenterY(mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1)); 3166 verifyMargin(); 3167 assertEquals(top1 - 100, top4); 3168 3169 // scroll invisible item before first visible item 3170 final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 3171 .mGrid.getFirstVisibleIndex(); 3172 setSelectedPosition(firstVisiblePos - 1, 100); 3173 int top5 = getCenterY(mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1)); 3174 assertEquals(top1 - 100, top5); 3175 3176 // scroll to invisible item that is far away. 3177 setSelectedPosition(100, 100); 3178 int top6 = getCenterY(mGridView.getLayoutManager().findViewByPosition(100)); 3179 assertEquals(top1 - 100, top6); 3180 3181 // scroll to invisible item that is far away. 3182 mActivityTestRule.runOnUiThread(new Runnable() { 3183 @Override 3184 public void run() { 3185 mGridView.setSelectedPositionSmooth(200); 3186 } 3187 }); 3188 waitForScrollIdle(mVerifyLayout); 3189 Thread.sleep(500); 3190 int top7 = getCenterY(mGridView.getLayoutManager().findViewByPosition(200)); 3191 assertEquals(top1, top7); 3192 3193 // scroll to invisible item that is far away. 3194 setSelectedPosition(10, 50); 3195 int top8 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10)); 3196 assertEquals(top1 - 50, top8); 3197 } 3198 3199 3200 @Test 3201 public void testSetSelectionWithDeltaInGrid1() throws Throwable { 3202 Intent intent = new Intent(); 3203 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3204 R.layout.vertical_grid); 3205 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{ 3206 193,176,153,141,203,184,232,139,177,206,222,136,132,237,172,137, 3207 188,172,163,213,158,219,209,147,133,229,170,197,138,215,188,205, 3208 223,192,225,170,195,127,229,229,210,195,134,142,160,139,130,222, 3209 150,163,180,176,157,137,234,169,159,167,182,150,224,231,202,236, 3210 123,140,181,223,120,185,183,221,123,210,134,158,166,208,149,128, 3211 192,214,212,198,133,140,158,133,229,173,226,141,180,128,127,218, 3212 192,235,183,213,216,150,143,193,125,141,219,210,195,195,192,191, 3213 212,236,157,189,160,220,147,158,220,199,233,231,201,180,168,141, 3214 156,204,191,183,190,153,123,210,238,151,139,221,223,200,175,191, 3215 132,184,197,204,236,157,230,151,195,219,212,143,172,149,219,184, 3216 164,211,132,187,172,142,174,146,127,147,206,238,188,129,199,226, 3217 132,220,210,159,235,153,208,182,196,123,180,159,131,135,175,226, 3218 127,134,237,211,133,225,132,124,160,226,224,200,173,137,217,169, 3219 182,183,176,185,122,168,195,159,172,129,126,129,166,136,149,220, 3220 178,191,192,238,180,208,234,154,222,206,239,228,129,140,203,125, 3221 214,175,125,169,196,132,234,138,192,142,234,190,215,232,239,122, 3222 188,158,128,221,159,237,207,157,232,138,132,214,122,199,121,191, 3223 199,209,126,164,175,187,173,186,194,224,191,196,146,208,213,210, 3224 164,176,202,213,123,157,179,138,217,129,186,166,237,211,157,130, 3225 137,132,171,232,216,239,180,151,137,132,190,133,218,155,171,227, 3226 193,147,197,164,120,218,193,154,170,196,138,222,161,235,143,154, 3227 192,178,228,195,178,133,203,178,173,206,178,212,136,157,169,124, 3228 172,121,128,223,238,125,217,187,184,156,169,215,231,124,210,174, 3229 146,226,185,134,223,228,183,182,136,133,199,146,180,233,226,225, 3230 174,233,145,235,216,170,192,171,132,132,134,223,233,148,154,162, 3231 192,179,197,203,139,197,174,187,135,132,180,136,192,195,124,221, 3232 120,189,233,233,146,225,234,163,215,143,132,198,156,205,151,190, 3233 204,239,221,229,123,138,134,217,219,136,218,215,167,139,195,125, 3234 202,225,178,226,145,208,130,194,228,197,157,215,124,147,174,123, 3235 237,140,172,181,161,151,229,216,199,199,179,213,146,122,222,162, 3236 139,173,165,150,160,217,207,137,165,175,129,158,134,133,178,199, 3237 215,213,122,197 3238 }); 3239 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 3240 mOrientation = BaseGridView.VERTICAL; 3241 mNumRows = 3; 3242 3243 initActivity(intent); 3244 3245 mActivityTestRule.runOnUiThread(new Runnable() { 3246 @Override 3247 public void run() { 3248 mGridView.setSelectedPositionSmooth(10); 3249 } 3250 }); 3251 waitForScrollIdle(mVerifyLayout); 3252 int top1 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10)); 3253 3254 humanDelay(500); 3255 3256 // scroll to position with delta 3257 setSelectedPosition(20, 100); 3258 int top2 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20)); 3259 assertEquals(top1 - 100, top2); 3260 3261 // scroll to same position without delta, it will be reset 3262 setSelectedPosition(20, 0); 3263 int top3 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20)); 3264 assertEquals(top1, top3); 3265 3266 // scroll invisible item after last visible item 3267 final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 3268 .mGrid.getLastVisibleIndex(); 3269 setSelectedPosition(lastVisiblePos + 1, 100); 3270 int top4 = getCenterY(mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1)); 3271 verifyMargin(); 3272 assertEquals(top1 - 100, top4); 3273 3274 // scroll invisible item before first visible item 3275 final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 3276 .mGrid.getFirstVisibleIndex(); 3277 setSelectedPosition(firstVisiblePos - 1, 100); 3278 int top5 = getCenterY(mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1)); 3279 assertEquals(top1 - 100, top5); 3280 3281 // scroll to invisible item that is far away. 3282 setSelectedPosition(100, 100); 3283 int top6 = getCenterY(mGridView.getLayoutManager().findViewByPosition(100)); 3284 assertEquals(top1 - 100, top6); 3285 3286 // scroll to invisible item that is far away. 3287 mActivityTestRule.runOnUiThread(new Runnable() { 3288 @Override 3289 public void run() { 3290 mGridView.setSelectedPositionSmooth(200); 3291 } 3292 }); 3293 waitForScrollIdle(mVerifyLayout); 3294 Thread.sleep(500); 3295 int top7 = getCenterY(mGridView.getLayoutManager().findViewByPosition(200)); 3296 assertEquals(top1, top7); 3297 3298 // scroll to invisible item that is far away. 3299 setSelectedPosition(10, 50); 3300 int top8 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10)); 3301 assertEquals(top1 - 50, top8); 3302 } 3303 3304 @Test 3305 public void testSmoothScrollSelectionEvents() throws Throwable { 3306 Intent intent = new Intent(); 3307 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3308 R.layout.vertical_grid); 3309 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500); 3310 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3311 mOrientation = BaseGridView.VERTICAL; 3312 mNumRows = 3; 3313 initActivity(intent); 3314 3315 mActivityTestRule.runOnUiThread(new Runnable() { 3316 @Override 3317 public void run() { 3318 mGridView.setSelectedPositionSmooth(30); 3319 } 3320 }); 3321 waitForScrollIdle(mVerifyLayout); 3322 humanDelay(500); 3323 3324 final ArrayList<Integer> selectedPositions = new ArrayList<Integer>(); 3325 mGridView.setOnChildSelectedListener(new OnChildSelectedListener() { 3326 @Override 3327 public void onChildSelected(ViewGroup parent, View view, int position, long id) { 3328 selectedPositions.add(position); 3329 } 3330 }); 3331 3332 sendRepeatedKeys(10, KeyEvent.KEYCODE_DPAD_UP); 3333 humanDelay(500); 3334 waitForScrollIdle(mVerifyLayout); 3335 // should only get childselected event for item 0 once 3336 assertTrue(selectedPositions.size() > 0); 3337 assertEquals(0, selectedPositions.get(selectedPositions.size() - 1).intValue()); 3338 for (int i = selectedPositions.size() - 2; i >= 0; i--) { 3339 assertFalse(0 == selectedPositions.get(i).intValue()); 3340 } 3341 3342 } 3343 3344 @Test 3345 public void testSmoothScrollSelectionEventsLinear() throws Throwable { 3346 Intent intent = new Intent(); 3347 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3348 R.layout.vertical_linear); 3349 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500); 3350 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3351 mOrientation = BaseGridView.VERTICAL; 3352 mNumRows = 1; 3353 initActivity(intent); 3354 3355 mActivityTestRule.runOnUiThread(new Runnable() { 3356 @Override 3357 public void run() { 3358 mGridView.setSelectedPositionSmooth(10); 3359 } 3360 }); 3361 waitForScrollIdle(mVerifyLayout); 3362 humanDelay(500); 3363 3364 final ArrayList<Integer> selectedPositions = new ArrayList<Integer>(); 3365 mGridView.setOnChildSelectedListener(new OnChildSelectedListener() { 3366 @Override 3367 public void onChildSelected(ViewGroup parent, View view, int position, long id) { 3368 selectedPositions.add(position); 3369 } 3370 }); 3371 3372 sendRepeatedKeys(10, KeyEvent.KEYCODE_DPAD_UP); 3373 humanDelay(500); 3374 waitForScrollIdle(mVerifyLayout); 3375 // should only get childselected event for item 0 once 3376 assertTrue(selectedPositions.size() > 0); 3377 assertEquals(0, selectedPositions.get(selectedPositions.size() - 1).intValue()); 3378 for (int i = selectedPositions.size() - 2; i >= 0; i--) { 3379 assertFalse(0 == selectedPositions.get(i).intValue()); 3380 } 3381 3382 } 3383 3384 @Test 3385 public void testScrollToNoneExisting() throws Throwable { 3386 Intent intent = new Intent(); 3387 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3388 R.layout.vertical_grid); 3389 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100); 3390 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3391 mOrientation = BaseGridView.VERTICAL; 3392 mNumRows = 3; 3393 initActivity(intent); 3394 3395 mActivityTestRule.runOnUiThread(new Runnable() { 3396 @Override 3397 public void run() { 3398 mGridView.setSelectedPositionSmooth(99); 3399 } 3400 }); 3401 waitForScrollIdle(mVerifyLayout); 3402 humanDelay(500); 3403 3404 3405 mActivityTestRule.runOnUiThread(new Runnable() { 3406 @Override 3407 public void run() { 3408 mGridView.setSelectedPositionSmooth(50); 3409 } 3410 }); 3411 Thread.sleep(100); 3412 mActivityTestRule.runOnUiThread(new Runnable() { 3413 @Override 3414 public void run() { 3415 mGridView.requestLayout(); 3416 mGridView.setSelectedPositionSmooth(0); 3417 } 3418 }); 3419 waitForScrollIdle(mVerifyLayout); 3420 humanDelay(500); 3421 3422 } 3423 3424 @Test 3425 public void testSmoothscrollerInterrupted() throws Throwable { 3426 Intent intent = new Intent(); 3427 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3428 R.layout.vertical_linear); 3429 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 3430 int[] items = new int[100]; 3431 for (int i = 0; i < items.length; i++) { 3432 items[i] = 680; 3433 } 3434 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 3435 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3436 mOrientation = BaseGridView.VERTICAL; 3437 mNumRows = 1; 3438 3439 initActivity(intent); 3440 3441 mGridView.setSelectedPositionSmooth(0); 3442 waitForScrollIdle(mVerifyLayout); 3443 assertTrue(mGridView.getChildAt(0).hasFocus()); 3444 3445 // Pressing lots of key to make sure smooth scroller is running 3446 for (int i = 0; i < 20; i++) { 3447 sendKey(KeyEvent.KEYCODE_DPAD_DOWN); 3448 } 3449 while (mGridView.getLayoutManager().isSmoothScrolling() 3450 || mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE) { 3451 // Repeatedly pressing to make sure pending keys does not drop to zero. 3452 sendKey(KeyEvent.KEYCODE_DPAD_DOWN); 3453 } 3454 } 3455 3456 @Test 3457 public void testSmoothscrollerCancelled() throws Throwable { 3458 Intent intent = new Intent(); 3459 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3460 R.layout.vertical_linear); 3461 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 3462 int[] items = new int[100]; 3463 for (int i = 0; i < items.length; i++) { 3464 items[i] = 680; 3465 } 3466 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 3467 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3468 mOrientation = BaseGridView.VERTICAL; 3469 mNumRows = 1; 3470 3471 initActivity(intent); 3472 3473 mGridView.setSelectedPositionSmooth(0); 3474 waitForScrollIdle(mVerifyLayout); 3475 assertTrue(mGridView.getChildAt(0).hasFocus()); 3476 3477 int targetPosition = items.length - 1; 3478 mGridView.setSelectedPositionSmooth(targetPosition); 3479 mActivityTestRule.runOnUiThread(new Runnable() { 3480 @Override 3481 public void run() { 3482 mGridView.stopScroll(); 3483 } 3484 }); 3485 waitForScrollIdle(); 3486 waitForItemAnimation(); 3487 assertEquals(mGridView.getSelectedPosition(), targetPosition); 3488 assertSame(mGridView.getLayoutManager().findViewByPosition(targetPosition), 3489 mGridView.findFocus()); 3490 } 3491 3492 @Test 3493 public void testSetNumRowsAndAddItem() throws Throwable { 3494 Intent intent = new Intent(); 3495 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3496 R.layout.vertical_linear); 3497 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 3498 int[] items = new int[2]; 3499 for (int i = 0; i < items.length; i++) { 3500 items[i] = 300; 3501 } 3502 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 3503 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3504 mOrientation = BaseGridView.VERTICAL; 3505 mNumRows = 1; 3506 3507 initActivity(intent); 3508 3509 mGridView.setSelectedPositionSmooth(0); 3510 waitForScrollIdle(mVerifyLayout); 3511 3512 mActivity.addItems(items.length, new int[]{300}); 3513 3514 mActivityTestRule.runOnUiThread(new Runnable() { 3515 @Override 3516 public void run() { 3517 ((VerticalGridView) mGridView).setNumColumns(2); 3518 } 3519 }); 3520 Thread.sleep(1000); 3521 assertTrue(mGridView.getChildAt(2).getLeft() != mGridView.getChildAt(1).getLeft()); 3522 } 3523 3524 3525 @Test 3526 public void testRequestLayoutBugInLayout() throws Throwable { 3527 Intent intent = new Intent(); 3528 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3529 R.layout.vertical_linear); 3530 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout); 3531 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 3532 int[] items = new int[100]; 3533 for (int i = 0; i < items.length; i++) { 3534 items[i] = 300; 3535 } 3536 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 3537 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3538 mOrientation = BaseGridView.VERTICAL; 3539 mNumRows = 1; 3540 3541 initActivity(intent); 3542 3543 mActivityTestRule.runOnUiThread(new Runnable() { 3544 @Override 3545 public void run() { 3546 mGridView.setSelectedPositionSmooth(1); 3547 } 3548 }); 3549 waitForScrollIdle(mVerifyLayout); 3550 3551 sendKey(KeyEvent.KEYCODE_DPAD_UP); 3552 waitForScrollIdle(mVerifyLayout); 3553 3554 assertEquals("Line 2", ((TextView) mGridView.findFocus()).getText().toString()); 3555 } 3556 3557 3558 @Test 3559 public void testChangeLayoutInChild() throws Throwable { 3560 Intent intent = new Intent(); 3561 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3562 R.layout.vertical_linear_wrap_content); 3563 intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true); 3564 int[] items = new int[2]; 3565 for (int i = 0; i < items.length; i++) { 3566 items[i] = 300; 3567 } 3568 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 3569 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3570 mOrientation = BaseGridView.VERTICAL; 3571 mNumRows = 1; 3572 3573 initActivity(intent); 3574 3575 mActivityTestRule.runOnUiThread(new Runnable() { 3576 @Override 3577 public void run() { 3578 mGridView.setSelectedPositionSmooth(0); 3579 } 3580 }); 3581 waitForScrollIdle(mVerifyLayout); 3582 verifyMargin(); 3583 3584 mActivityTestRule.runOnUiThread(new Runnable() { 3585 @Override 3586 public void run() { 3587 mGridView.setSelectedPositionSmooth(1); 3588 } 3589 }); 3590 waitForScrollIdle(mVerifyLayout); 3591 verifyMargin(); 3592 } 3593 3594 @Test 3595 public void testWrapContent() throws Throwable { 3596 Intent intent = new Intent(); 3597 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3598 R.layout.horizontal_grid_wrap); 3599 int[] items = new int[200]; 3600 for (int i = 0; i < items.length; i++) { 3601 items[i] = 300; 3602 } 3603 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 3604 mOrientation = BaseGridView.HORIZONTAL; 3605 mNumRows = 1; 3606 3607 initActivity(intent); 3608 3609 mActivityTestRule.runOnUiThread(new Runnable() { 3610 @Override 3611 public void run() { 3612 mActivity.attachToNewAdapter(new int[0]); 3613 } 3614 }); 3615 3616 } 3617 3618 @Test 3619 public void testZeroFixedSecondarySize() throws Throwable { 3620 Intent intent = new Intent(); 3621 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3622 R.layout.vertical_linear_measured_with_zero); 3623 intent.putExtra(GridActivity.EXTRA_SECONDARY_SIZE_ZERO, true); 3624 int[] items = new int[2]; 3625 for (int i = 0; i < items.length; i++) { 3626 items[i] = 0; 3627 } 3628 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 3629 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3630 mOrientation = BaseGridView.VERTICAL; 3631 mNumRows = 1; 3632 3633 initActivity(intent); 3634 3635 } 3636 3637 @Test 3638 public void testChildStates() throws Throwable { 3639 Intent intent = new Intent(); 3640 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 3641 int[] items = new int[100]; 3642 for (int i = 0; i < items.length; i++) { 3643 items[i] = 200; 3644 } 3645 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 3646 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3647 intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true); 3648 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.selectable_text_view); 3649 mOrientation = BaseGridView.VERTICAL; 3650 mNumRows = 1; 3651 3652 initActivity(intent); 3653 mGridView.setSaveChildrenPolicy(VerticalGridView.SAVE_ALL_CHILD); 3654 3655 final SparseArray<Parcelable> container = new SparseArray<Parcelable>(); 3656 3657 // 1 Save view states 3658 mActivityTestRule.runOnUiThread(new Runnable() { 3659 @Override 3660 public void run() { 3661 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(0)) 3662 .getText()), 0, 1); 3663 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(1)) 3664 .getText()), 0, 1); 3665 mGridView.saveHierarchyState(container); 3666 } 3667 }); 3668 3669 // 2 Change view states 3670 mActivityTestRule.runOnUiThread(new Runnable() { 3671 @Override 3672 public void run() { 3673 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(0)) 3674 .getText()), 1, 2); 3675 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(1)) 3676 .getText()), 1, 2); 3677 } 3678 }); 3679 3680 // 3 Detached and re-attached, should still maintain state of (2) 3681 mActivityTestRule.runOnUiThread(new Runnable() { 3682 @Override 3683 public void run() { 3684 mGridView.setSelectedPositionSmooth(1); 3685 } 3686 }); 3687 waitForScrollIdle(mVerifyLayout); 3688 assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionStart(), 1); 3689 assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionEnd(), 2); 3690 assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionStart(), 1); 3691 assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionEnd(), 2); 3692 3693 // 4 Recycled and rebound, should load state from (2) 3694 mActivityTestRule.runOnUiThread(new Runnable() { 3695 @Override 3696 public void run() { 3697 mGridView.setSelectedPositionSmooth(20); 3698 } 3699 }); 3700 waitForScrollIdle(mVerifyLayout); 3701 mActivityTestRule.runOnUiThread(new Runnable() { 3702 @Override 3703 public void run() { 3704 mGridView.setSelectedPositionSmooth(0); 3705 } 3706 }); 3707 waitForScrollIdle(mVerifyLayout); 3708 assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionStart(), 1); 3709 assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionEnd(), 2); 3710 assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionStart(), 1); 3711 assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionEnd(), 2); 3712 } 3713 3714 3715 @Test 3716 public void testNoDispatchSaveChildState() throws Throwable { 3717 Intent intent = new Intent(); 3718 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 3719 int[] items = new int[100]; 3720 for (int i = 0; i < items.length; i++) { 3721 items[i] = 200; 3722 } 3723 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 3724 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3725 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.selectable_text_view); 3726 mOrientation = BaseGridView.VERTICAL; 3727 mNumRows = 1; 3728 3729 initActivity(intent); 3730 mGridView.setSaveChildrenPolicy(VerticalGridView.SAVE_NO_CHILD); 3731 3732 final SparseArray<Parcelable> container = new SparseArray<Parcelable>(); 3733 3734 // 1. Set text selection, save view states should do nothing on child 3735 mActivityTestRule.runOnUiThread(new Runnable() { 3736 @Override 3737 public void run() { 3738 for (int i = 0; i < mGridView.getChildCount(); i++) { 3739 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(i)) 3740 .getText()), 0, 1); 3741 } 3742 mGridView.saveHierarchyState(container); 3743 } 3744 }); 3745 3746 // 2. clear the text selection 3747 mActivityTestRule.runOnUiThread(new Runnable() { 3748 @Override 3749 public void run() { 3750 for (int i = 0; i < mGridView.getChildCount(); i++) { 3751 Selection.removeSelection((Spannable)(((TextView) mGridView.getChildAt(i)) 3752 .getText())); 3753 } 3754 } 3755 }); 3756 3757 // 3. Restore view states should be a no-op for child 3758 mActivityTestRule.runOnUiThread(new Runnable() { 3759 @Override 3760 public void run() { 3761 mGridView.restoreHierarchyState(container); 3762 for (int i = 0; i < mGridView.getChildCount(); i++) { 3763 assertEquals(-1, ((TextView) mGridView.getChildAt(i)).getSelectionStart()); 3764 assertEquals(-1, ((TextView) mGridView.getChildAt(i)).getSelectionEnd()); 3765 } 3766 } 3767 }); 3768 } 3769 3770 3771 static interface ViewTypeProvider { 3772 public int getViewType(int position); 3773 } 3774 3775 static interface ItemAlignmentFacetProvider { 3776 public ItemAlignmentFacet getItemAlignmentFacet(int viewType); 3777 } 3778 3779 static class TwoViewTypesProvider implements ViewTypeProvider { 3780 static int VIEW_TYPE_FIRST = 1; 3781 static int VIEW_TYPE_DEFAULT = 0; 3782 @Override 3783 public int getViewType(int position) { 3784 if (position == 0) { 3785 return VIEW_TYPE_FIRST; 3786 } else { 3787 return VIEW_TYPE_DEFAULT; 3788 } 3789 } 3790 } 3791 3792 static class ChangeableViewTypesProvider implements ViewTypeProvider { 3793 static SparseIntArray sViewTypes = new SparseIntArray(); 3794 @Override 3795 public int getViewType(int position) { 3796 return sViewTypes.get(position); 3797 } 3798 public static void clear() { 3799 sViewTypes.clear(); 3800 } 3801 public static void setViewType(int position, int type) { 3802 sViewTypes.put(position, type); 3803 } 3804 } 3805 3806 static class PositionItemAlignmentFacetProviderForRelativeLayout1 3807 implements ItemAlignmentFacetProvider { 3808 ItemAlignmentFacet mMultipleFacet; 3809 3810 PositionItemAlignmentFacetProviderForRelativeLayout1() { 3811 mMultipleFacet = new ItemAlignmentFacet(); 3812 ItemAlignmentFacet.ItemAlignmentDef[] defs = 3813 new ItemAlignmentFacet.ItemAlignmentDef[2]; 3814 defs[0] = new ItemAlignmentFacet.ItemAlignmentDef(); 3815 defs[0].setItemAlignmentViewId(R.id.t1); 3816 defs[1] = new ItemAlignmentFacet.ItemAlignmentDef(); 3817 defs[1].setItemAlignmentViewId(R.id.t2); 3818 defs[1].setItemAlignmentOffsetPercent(100); 3819 defs[1].setItemAlignmentOffset(-10); 3820 mMultipleFacet.setAlignmentDefs(defs); 3821 } 3822 3823 @Override 3824 public ItemAlignmentFacet getItemAlignmentFacet(int position) { 3825 if (position == 0) { 3826 return mMultipleFacet; 3827 } else { 3828 return null; 3829 } 3830 } 3831 } 3832 3833 @Test 3834 public void testMultipleScrollPosition1() throws Throwable { 3835 Intent intent = new Intent(); 3836 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 3837 R.layout.vertical_linear); 3838 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout); 3839 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 3840 int[] items = new int[100]; 3841 for (int i = 0; i < items.length; i++) { 3842 items[i] = 300; 3843 } 3844 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 3845 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3846 intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS, 3847 TwoViewTypesProvider.class.getName()); 3848 // Set ItemAlignment for each ViewHolder and view type, ViewHolder should 3849 // override the view type settings. 3850 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS, 3851 PositionItemAlignmentFacetProviderForRelativeLayout1.class.getName()); 3852 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_VIEWTYPE_CLASS, 3853 ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2.class.getName()); 3854 mOrientation = BaseGridView.VERTICAL; 3855 mNumRows = 1; 3856 3857 initActivity(intent); 3858 3859 assertEquals("First view is aligned with padding top", 3860 mGridView.getPaddingTop(), mGridView.getChildAt(0).getTop()); 3861 3862 sendKey(KeyEvent.KEYCODE_DPAD_DOWN); 3863 waitForScrollIdle(mVerifyLayout); 3864 3865 final View v = mGridView.getChildAt(0); 3866 View t1 = v.findViewById(R.id.t1); 3867 int t1align = (t1.getTop() + t1.getBottom()) / 2; 3868 View t2 = v.findViewById(R.id.t2); 3869 int t2align = t2.getBottom() - 10; 3870 assertEquals("Expected alignment for 2nd textview", 3871 mGridView.getPaddingTop() - (t2align - t1align), 3872 v.getTop()); 3873 } 3874 3875 static class PositionItemAlignmentFacetProviderForRelativeLayout2 implements 3876 ItemAlignmentFacetProvider { 3877 ItemAlignmentFacet mMultipleFacet; 3878 3879 PositionItemAlignmentFacetProviderForRelativeLayout2() { 3880 mMultipleFacet = new ItemAlignmentFacet(); 3881 ItemAlignmentFacet.ItemAlignmentDef[] defs = new ItemAlignmentFacet.ItemAlignmentDef[2]; 3882 defs[0] = new ItemAlignmentFacet.ItemAlignmentDef(); 3883 defs[0].setItemAlignmentViewId(R.id.t1); 3884 defs[0].setItemAlignmentOffsetPercent(0); 3885 defs[1] = new ItemAlignmentFacet.ItemAlignmentDef(); 3886 defs[1].setItemAlignmentViewId(R.id.t2); 3887 defs[1].setItemAlignmentOffsetPercent(ItemAlignmentFacet.ITEM_ALIGN_OFFSET_PERCENT_DISABLED); 3888 defs[1].setItemAlignmentOffset(-10); 3889 mMultipleFacet.setAlignmentDefs(defs); 3890 } 3891 3892 @Override 3893 public ItemAlignmentFacet getItemAlignmentFacet(int position) { 3894 if (position == 0) { 3895 return mMultipleFacet; 3896 } else { 3897 return null; 3898 } 3899 } 3900 } 3901 3902 @Test 3903 public void testMultipleScrollPosition2() throws Throwable { 3904 Intent intent = new Intent(); 3905 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 3906 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout); 3907 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 3908 int[] items = new int[100]; 3909 for (int i = 0; i < items.length; i++) { 3910 items[i] = 300; 3911 } 3912 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 3913 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3914 intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS, 3915 TwoViewTypesProvider.class.getName()); 3916 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS, 3917 PositionItemAlignmentFacetProviderForRelativeLayout2.class.getName()); 3918 mOrientation = BaseGridView.VERTICAL; 3919 mNumRows = 1; 3920 3921 initActivity(intent); 3922 3923 assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(), 3924 mGridView.getChildAt(0).getTop()); 3925 3926 sendKey(KeyEvent.KEYCODE_DPAD_DOWN); 3927 waitForScrollIdle(mVerifyLayout); 3928 3929 final View v = mGridView.getChildAt(0); 3930 View t1 = v.findViewById(R.id.t1); 3931 int t1align = t1.getTop(); 3932 View t2 = v.findViewById(R.id.t2); 3933 int t2align = t2.getTop() - 10; 3934 assertEquals("Expected alignment for 2nd textview", 3935 mGridView.getPaddingTop() - (t2align - t1align), v.getTop()); 3936 } 3937 3938 static class ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2 implements 3939 ItemAlignmentFacetProvider { 3940 ItemAlignmentFacet mMultipleFacet; 3941 3942 ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2() { 3943 mMultipleFacet = new ItemAlignmentFacet(); 3944 ItemAlignmentFacet.ItemAlignmentDef[] defs = new ItemAlignmentFacet.ItemAlignmentDef[2]; 3945 defs[0] = new ItemAlignmentFacet.ItemAlignmentDef(); 3946 defs[0].setItemAlignmentViewId(R.id.t1); 3947 defs[0].setItemAlignmentOffsetPercent(0); 3948 defs[1] = new ItemAlignmentFacet.ItemAlignmentDef(); 3949 defs[1].setItemAlignmentViewId(R.id.t2); 3950 defs[1].setItemAlignmentOffsetPercent(100); 3951 defs[1].setItemAlignmentOffset(-10); 3952 mMultipleFacet.setAlignmentDefs(defs); 3953 } 3954 3955 @Override 3956 public ItemAlignmentFacet getItemAlignmentFacet(int viewType) { 3957 if (viewType == TwoViewTypesProvider.VIEW_TYPE_FIRST) { 3958 return mMultipleFacet; 3959 } else { 3960 return null; 3961 } 3962 } 3963 } 3964 3965 @Test 3966 public void testMultipleScrollPosition3() throws Throwable { 3967 Intent intent = new Intent(); 3968 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 3969 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout); 3970 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 3971 int[] items = new int[100]; 3972 for (int i = 0; i < items.length; i++) { 3973 items[i] = 300; 3974 } 3975 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 3976 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 3977 intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS, 3978 TwoViewTypesProvider.class.getName()); 3979 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_VIEWTYPE_CLASS, 3980 ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2.class.getName()); 3981 mOrientation = BaseGridView.VERTICAL; 3982 mNumRows = 1; 3983 3984 initActivity(intent); 3985 3986 assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(), 3987 mGridView.getChildAt(0).getTop()); 3988 3989 sendKey(KeyEvent.KEYCODE_DPAD_DOWN); 3990 waitForScrollIdle(mVerifyLayout); 3991 3992 final View v = mGridView.getChildAt(0); 3993 View t1 = v.findViewById(R.id.t1); 3994 int t1align = t1.getTop(); 3995 View t2 = v.findViewById(R.id.t2); 3996 int t2align = t2.getBottom() - 10; 3997 assertEquals("Expected alignment for 2nd textview", 3998 mGridView.getPaddingTop() - (t2align - t1align), v.getTop()); 3999 } 4000 4001 @Test 4002 public void testSelectionAndAddItemInOneCycle() throws Throwable { 4003 Intent intent = new Intent(); 4004 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4005 R.layout.vertical_linear); 4006 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0); 4007 initActivity(intent); 4008 mOrientation = BaseGridView.HORIZONTAL; 4009 mNumRows = 1; 4010 4011 performAndWaitForAnimation(new Runnable() { 4012 @Override 4013 public void run() { 4014 mActivity.addItems(0, new int[]{300, 300}); 4015 mGridView.setSelectedPosition(0); 4016 } 4017 }); 4018 assertEquals(0, mGridView.getSelectedPosition()); 4019 } 4020 4021 @Test 4022 public void testSelectViewTaskSmoothWithAdapterChange() throws Throwable { 4023 testSelectViewTaskWithAdapterChange(true /*smooth*/); 4024 } 4025 4026 @Test 4027 public void testSelectViewTaskWithAdapterChange() throws Throwable { 4028 testSelectViewTaskWithAdapterChange(false /*smooth*/); 4029 } 4030 4031 private void testSelectViewTaskWithAdapterChange(final boolean smooth) throws Throwable { 4032 Intent intent = new Intent(); 4033 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4034 R.layout.vertical_linear); 4035 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2); 4036 initActivity(intent); 4037 mOrientation = BaseGridView.HORIZONTAL; 4038 mNumRows = 1; 4039 4040 final View firstView = mGridView.getLayoutManager().findViewByPosition(0); 4041 final View[] selectedViewByTask = new View[1]; 4042 final ViewHolderTask task = new ViewHolderTask() { 4043 @Override 4044 public void run(RecyclerView.ViewHolder viewHolder) { 4045 selectedViewByTask[0] = viewHolder.itemView; 4046 } 4047 }; 4048 performAndWaitForAnimation(new Runnable() { 4049 @Override 4050 public void run() { 4051 mActivity.removeItems(0, 1); 4052 if (smooth) { 4053 mGridView.setSelectedPositionSmooth(0, task); 4054 } else { 4055 mGridView.setSelectedPosition(0, task); 4056 } 4057 } 4058 }); 4059 assertEquals(0, mGridView.getSelectedPosition()); 4060 assertNotNull(selectedViewByTask[0]); 4061 assertNotSame(firstView, selectedViewByTask[0]); 4062 assertSame(mGridView.getLayoutManager().findViewByPosition(0), selectedViewByTask[0]); 4063 } 4064 4065 @Test 4066 public void testNotifyItemTypeChangedSelectionEvent() throws Throwable { 4067 Intent intent = new Intent(); 4068 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4069 R.layout.vertical_linear); 4070 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10); 4071 intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS, 4072 ChangeableViewTypesProvider.class.getName()); 4073 ChangeableViewTypesProvider.clear(); 4074 initActivity(intent); 4075 mOrientation = BaseGridView.HORIZONTAL; 4076 mNumRows = 1; 4077 4078 final ArrayList<Integer> selectedLog = new ArrayList<Integer>(); 4079 mGridView.setOnChildSelectedListener(new OnChildSelectedListener() { 4080 @Override 4081 public void onChildSelected(ViewGroup parent, View view, int position, long id) { 4082 selectedLog.add(position); 4083 } 4084 }); 4085 4086 performAndWaitForAnimation(new Runnable() { 4087 @Override 4088 public void run() { 4089 ChangeableViewTypesProvider.setViewType(0, 1); 4090 mGridView.getAdapter().notifyItemChanged(0, 1); 4091 } 4092 }); 4093 assertEquals(0, mGridView.getSelectedPosition()); 4094 assertEquals(selectedLog.size(), 1); 4095 assertEquals((int) selectedLog.get(0), 0); 4096 } 4097 4098 @Test 4099 public void testNotifyItemChangedSelectionEvent() throws Throwable { 4100 Intent intent = new Intent(); 4101 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4102 R.layout.vertical_linear); 4103 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10); 4104 initActivity(intent); 4105 mOrientation = BaseGridView.HORIZONTAL; 4106 mNumRows = 1; 4107 4108 OnChildViewHolderSelectedListener listener = 4109 Mockito.mock(OnChildViewHolderSelectedListener.class); 4110 mGridView.setOnChildViewHolderSelectedListener(listener); 4111 4112 performAndWaitForAnimation(new Runnable() { 4113 @Override 4114 public void run() { 4115 mGridView.getAdapter().notifyItemChanged(0, 1); 4116 } 4117 }); 4118 Mockito.verify(listener, times(1)).onChildViewHolderSelected(any(RecyclerView.class), 4119 any(RecyclerView.ViewHolder.class), anyInt(), anyInt()); 4120 assertEquals(0, mGridView.getSelectedPosition()); 4121 } 4122 4123 @Test 4124 public void testSelectionSmoothAndAddItemInOneCycle() throws Throwable { 4125 Intent intent = new Intent(); 4126 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4127 R.layout.vertical_linear); 4128 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0); 4129 initActivity(intent); 4130 mOrientation = BaseGridView.HORIZONTAL; 4131 mNumRows = 1; 4132 4133 performAndWaitForAnimation(new Runnable() { 4134 @Override 4135 public void run() { 4136 mActivity.addItems(0, new int[]{300, 300}); 4137 mGridView.setSelectedPositionSmooth(0); 4138 } 4139 }); 4140 assertEquals(0, mGridView.getSelectedPosition()); 4141 } 4142 4143 @Test 4144 public void testExtraLayoutSpace() throws Throwable { 4145 Intent intent = new Intent(); 4146 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4147 R.layout.vertical_linear); 4148 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000); 4149 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 4150 initActivity(intent); 4151 4152 final int windowSize = mGridView.getHeight(); 4153 final int extraLayoutSize = windowSize; 4154 mOrientation = BaseGridView.VERTICAL; 4155 mNumRows = 1; 4156 4157 // add extra layout space 4158 startWaitLayout(); 4159 mActivityTestRule.runOnUiThread(new Runnable() { 4160 @Override 4161 public void run() { 4162 mGridView.setExtraLayoutSpace(extraLayoutSize); 4163 } 4164 }); 4165 waitForLayout(); 4166 View v; 4167 v = mGridView.getChildAt(mGridView.getChildCount() - 1); 4168 assertTrue(v.getTop() < windowSize + extraLayoutSize); 4169 assertTrue(v.getBottom() >= windowSize + extraLayoutSize - mGridView.getVerticalMargin()); 4170 4171 mGridView.setSelectedPositionSmooth(150); 4172 waitForScrollIdle(mVerifyLayout); 4173 v = mGridView.getChildAt(0); 4174 assertTrue(v.getBottom() > - extraLayoutSize); 4175 assertTrue(v.getTop() <= -extraLayoutSize + mGridView.getVerticalMargin()); 4176 4177 // clear extra layout space 4178 mActivityTestRule.runOnUiThread(new Runnable() { 4179 @Override 4180 public void run() { 4181 mGridView.setExtraLayoutSpace(0); 4182 verifyMargin(); 4183 } 4184 }); 4185 Thread.sleep(50); 4186 v = mGridView.getChildAt(mGridView.getChildCount() - 1); 4187 assertTrue(v.getTop() < windowSize); 4188 assertTrue(v.getBottom() >= windowSize - mGridView.getVerticalMargin()); 4189 } 4190 4191 @Test 4192 public void testFocusFinder() throws Throwable { 4193 Intent intent = new Intent(); 4194 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4195 R.layout.vertical_linear_with_button); 4196 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 3); 4197 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 4198 initActivity(intent); 4199 mOrientation = BaseGridView.VERTICAL; 4200 mNumRows = 1; 4201 4202 // test focus from button to vertical grid view 4203 final View button = mActivity.findViewById(R.id.button); 4204 assertTrue(button.isFocused()); 4205 sendKey(KeyEvent.KEYCODE_DPAD_DOWN); 4206 assertFalse(mGridView.isFocused()); 4207 assertTrue(mGridView.hasFocus()); 4208 4209 // FocusFinder should find last focused(2nd) item on DPAD_DOWN 4210 final View secondChild = mGridView.getChildAt(1); 4211 mActivityTestRule.runOnUiThread(new Runnable() { 4212 @Override 4213 public void run() { 4214 secondChild.requestFocus(); 4215 button.requestFocus(); 4216 } 4217 }); 4218 assertTrue(button.isFocused()); 4219 sendKey(KeyEvent.KEYCODE_DPAD_DOWN); 4220 assertTrue(secondChild.isFocused()); 4221 4222 // Bug 26918143 Even VerticalGridView is not focusable, FocusFinder should find last focused 4223 // (2nd) item on DPAD_DOWN. 4224 mActivityTestRule.runOnUiThread(new Runnable() { 4225 @Override 4226 public void run() { 4227 button.requestFocus(); 4228 } 4229 }); 4230 mGridView.setFocusable(false); 4231 mGridView.setFocusableInTouchMode(false); 4232 assertTrue(button.isFocused()); 4233 sendKey(KeyEvent.KEYCODE_DPAD_DOWN); 4234 assertTrue(secondChild.isFocused()); 4235 } 4236 4237 @Test 4238 public void testRestoreIndexAndAddItems() throws Throwable { 4239 Intent intent = new Intent(); 4240 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4241 R.layout.vertical_linear); 4242 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item); 4243 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 4); 4244 initActivity(intent); 4245 mOrientation = BaseGridView.VERTICAL; 4246 mNumRows = 1; 4247 4248 assertEquals(mGridView.getSelectedPosition(), 0); 4249 final SparseArray<Parcelable> states = new SparseArray<>(); 4250 mActivityTestRule.runOnUiThread(new Runnable() { 4251 @Override 4252 public void run() { 4253 mGridView.saveHierarchyState(states); 4254 mGridView.setAdapter(null); 4255 } 4256 4257 }); 4258 performAndWaitForAnimation(new Runnable() { 4259 @Override 4260 public void run() { 4261 mGridView.restoreHierarchyState(states); 4262 mActivity.attachToNewAdapter(new int[0]); 4263 mActivity.addItems(0, new int[]{100, 100, 100, 100}); 4264 } 4265 4266 }); 4267 assertEquals(mGridView.getSelectedPosition(), 0); 4268 } 4269 4270 @Test 4271 public void testRestoreIndexAndAddItemsSelect1() throws Throwable { 4272 Intent intent = new Intent(); 4273 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4274 R.layout.vertical_linear); 4275 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item); 4276 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 4); 4277 initActivity(intent); 4278 mOrientation = BaseGridView.VERTICAL; 4279 mNumRows = 1; 4280 4281 mActivityTestRule.runOnUiThread(new Runnable() { 4282 @Override 4283 public void run() { 4284 mGridView.setSelectedPosition(1); 4285 } 4286 4287 }); 4288 assertEquals(mGridView.getSelectedPosition(), 1); 4289 final SparseArray<Parcelable> states = new SparseArray<>(); 4290 mActivityTestRule.runOnUiThread(new Runnable() { 4291 @Override 4292 public void run() { 4293 mGridView.saveHierarchyState(states); 4294 mGridView.setAdapter(null); 4295 } 4296 4297 }); 4298 performAndWaitForAnimation(new Runnable() { 4299 @Override 4300 public void run() { 4301 mGridView.restoreHierarchyState(states); 4302 mActivity.attachToNewAdapter(new int[0]); 4303 mActivity.addItems(0, new int[]{100, 100, 100, 100}); 4304 } 4305 4306 }); 4307 assertEquals(mGridView.getSelectedPosition(), 1); 4308 } 4309 4310 @Test 4311 public void testRestoreStateAfterAdapterChange() throws Throwable { 4312 Intent intent = new Intent(); 4313 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4314 R.layout.vertical_linear); 4315 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.selectable_text_view); 4316 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{50, 50, 50, 50}); 4317 initActivity(intent); 4318 mOrientation = BaseGridView.VERTICAL; 4319 mNumRows = 1; 4320 4321 mActivityTestRule.runOnUiThread(new Runnable() { 4322 @Override 4323 public void run() { 4324 mGridView.setSelectedPosition(1); 4325 mGridView.setSaveChildrenPolicy(VerticalGridView.SAVE_ALL_CHILD); 4326 } 4327 4328 }); 4329 assertEquals(mGridView.getSelectedPosition(), 1); 4330 final SparseArray<Parcelable> states = new SparseArray<>(); 4331 mActivityTestRule.runOnUiThread(new Runnable() { 4332 @Override 4333 public void run() { 4334 Selection.setSelection((Spannable) (((TextView) mGridView.getChildAt(0)) 4335 .getText()), 1, 2); 4336 Selection.setSelection((Spannable) (((TextView) mGridView.getChildAt(1)) 4337 .getText()), 0, 1); 4338 mGridView.saveHierarchyState(states); 4339 mGridView.setAdapter(null); 4340 } 4341 4342 }); 4343 performAndWaitForAnimation(new Runnable() { 4344 @Override 4345 public void run() { 4346 mGridView.restoreHierarchyState(states); 4347 mActivity.attachToNewAdapter(new int[]{50, 50, 50, 50}); 4348 } 4349 4350 }); 4351 assertEquals(mGridView.getSelectedPosition(), 1); 4352 assertEquals(1, ((TextView) mGridView.getChildAt(0)).getSelectionStart()); 4353 assertEquals(2, ((TextView) mGridView.getChildAt(0)).getSelectionEnd()); 4354 assertEquals(0, ((TextView) mGridView.getChildAt(1)).getSelectionStart()); 4355 assertEquals(1, ((TextView) mGridView.getChildAt(1)).getSelectionEnd()); 4356 } 4357 4358 @Test 4359 public void test27766012() throws Throwable { 4360 Intent intent = new Intent(); 4361 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4362 R.layout.vertical_linear_with_button_onleft); 4363 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item); 4364 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2); 4365 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 4366 intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, false); 4367 initActivity(intent); 4368 mOrientation = BaseGridView.VERTICAL; 4369 mNumRows = 1; 4370 4371 // set remove animator two seconds 4372 mGridView.getItemAnimator().setRemoveDuration(2000); 4373 final View view = mGridView.getChildAt(1); 4374 mActivityTestRule.runOnUiThread(new Runnable() { 4375 @Override 4376 public void run() { 4377 view.requestFocus(); 4378 } 4379 }); 4380 assertTrue(view.hasFocus()); 4381 mActivityTestRule.runOnUiThread(new Runnable() { 4382 @Override 4383 public void run() { 4384 mActivity.removeItems(0, 2); 4385 } 4386 4387 }); 4388 // wait one second, removing second view is still attached to parent 4389 Thread.sleep(1000); 4390 assertSame(view.getParent(), mGridView); 4391 mActivityTestRule.runOnUiThread(new Runnable() { 4392 @Override 4393 public void run() { 4394 // refocus to the removed item and do a focus search. 4395 view.requestFocus(); 4396 view.focusSearch(View.FOCUS_UP); 4397 } 4398 4399 }); 4400 } 4401 4402 @Test 4403 public void testBug27258366() throws Throwable { 4404 Intent intent = new Intent(); 4405 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4406 R.layout.vertical_linear_with_button_onleft); 4407 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item); 4408 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10); 4409 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 4410 intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, false); 4411 initActivity(intent); 4412 mOrientation = BaseGridView.VERTICAL; 4413 mNumRows = 1; 4414 4415 // move item1 500 pixels right, when focus is on item1, default focus finder will pick 4416 // item0 and item2 for the best match of focusSearch(FOCUS_LEFT). The grid widget 4417 // must override default addFocusables(), not to add item0 or item2. 4418 mActivity.mAdapterListener = new GridActivity.AdapterListener() { 4419 @Override 4420 public void onBind(RecyclerView.ViewHolder vh, int position) { 4421 if (position == 1) { 4422 vh.itemView.setPaddingRelative(500, 0, 0, 0); 4423 } else { 4424 vh.itemView.setPaddingRelative(0, 0, 0, 0); 4425 } 4426 } 4427 }; 4428 mActivityTestRule.runOnUiThread(new Runnable() { 4429 @Override 4430 public void run() { 4431 mGridView.getAdapter().notifyDataSetChanged(); 4432 } 4433 }); 4434 Thread.sleep(100); 4435 4436 final ViewGroup secondChild = (ViewGroup) mGridView.getChildAt(1); 4437 mActivityTestRule.runOnUiThread(new Runnable() { 4438 @Override 4439 public void run() { 4440 secondChild.requestFocus(); 4441 } 4442 }); 4443 sendKey(KeyEvent.KEYCODE_DPAD_LEFT); 4444 Thread.sleep(100); 4445 final View button = mActivity.findViewById(R.id.button); 4446 assertTrue(button.isFocused()); 4447 } 4448 4449 @Test 4450 public void testUpdateHeightScrollHorizontal() throws Throwable { 4451 Intent intent = new Intent(); 4452 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4453 R.layout.horizontal_linear); 4454 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 30); 4455 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 4456 intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true); 4457 intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, false); 4458 intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE_SECONDARY, true); 4459 initActivity(intent); 4460 mOrientation = BaseGridView.HORIZONTAL; 4461 mNumRows = 1; 4462 4463 final int childTop = mGridView.getChildAt(0).getTop(); 4464 // scroll to end, all children's top should not change. 4465 scrollToEnd(new Runnable() { 4466 @Override 4467 public void run() { 4468 for (int i = 0; i < mGridView.getChildCount(); i++) { 4469 assertEquals(childTop, mGridView.getChildAt(i).getTop()); 4470 } 4471 } 4472 }); 4473 // sanity check last child has focus with a larger height. 4474 assertTrue(mGridView.getChildAt(0).getHeight() 4475 < mGridView.getChildAt(mGridView.getChildCount() - 1).getHeight()); 4476 } 4477 4478 @Test 4479 public void testUpdateWidthScrollHorizontal() throws Throwable { 4480 Intent intent = new Intent(); 4481 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4482 R.layout.horizontal_linear); 4483 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 30); 4484 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 4485 intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true); 4486 intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, true); 4487 intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE_SECONDARY, false); 4488 initActivity(intent); 4489 mOrientation = BaseGridView.HORIZONTAL; 4490 mNumRows = 1; 4491 4492 final int childTop = mGridView.getChildAt(0).getTop(); 4493 // scroll to end, all children's top should not change. 4494 scrollToEnd(new Runnable() { 4495 @Override 4496 public void run() { 4497 for (int i = 0; i < mGridView.getChildCount(); i++) { 4498 assertEquals(childTop, mGridView.getChildAt(i).getTop()); 4499 } 4500 } 4501 }); 4502 // sanity check last child has focus with a larger width. 4503 assertTrue(mGridView.getChildAt(0).getWidth() 4504 < mGridView.getChildAt(mGridView.getChildCount() - 1).getWidth()); 4505 if (mGridView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { 4506 assertEquals(mGridView.getPaddingLeft(), 4507 mGridView.getChildAt(mGridView.getChildCount() - 1).getLeft()); 4508 } else { 4509 assertEquals(mGridView.getWidth() - mGridView.getPaddingRight(), 4510 mGridView.getChildAt(mGridView.getChildCount() - 1).getRight()); 4511 } 4512 } 4513 4514 @Test 4515 public void testUpdateWidthScrollHorizontalRtl() throws Throwable { 4516 Intent intent = new Intent(); 4517 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4518 R.layout.horizontal_linear_rtl); 4519 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 30); 4520 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 4521 intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true); 4522 intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, true); 4523 intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE_SECONDARY, false); 4524 initActivity(intent); 4525 mOrientation = BaseGridView.HORIZONTAL; 4526 mNumRows = 1; 4527 4528 final int childTop = mGridView.getChildAt(0).getTop(); 4529 // scroll to end, all children's top should not change. 4530 scrollToEnd(new Runnable() { 4531 @Override 4532 public void run() { 4533 for (int i = 0; i < mGridView.getChildCount(); i++) { 4534 assertEquals(childTop, mGridView.getChildAt(i).getTop()); 4535 } 4536 } 4537 }); 4538 // sanity check last child has focus with a larger width. 4539 assertTrue(mGridView.getChildAt(0).getWidth() 4540 < mGridView.getChildAt(mGridView.getChildCount() - 1).getWidth()); 4541 assertEquals(mGridView.getPaddingLeft(), 4542 mGridView.getChildAt(mGridView.getChildCount() - 1).getLeft()); 4543 } 4544 4545 @Test 4546 public void testAccessibility() throws Throwable { 4547 Intent intent = new Intent(); 4548 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4549 R.layout.vertical_linear); 4550 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000); 4551 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 4552 initActivity(intent); 4553 mOrientation = BaseGridView.VERTICAL; 4554 mNumRows = 1; 4555 4556 assertTrue(0 == mGridView.getSelectedPosition()); 4557 4558 final RecyclerViewAccessibilityDelegate delegateCompat = mGridView 4559 .getCompatAccessibilityDelegate(); 4560 final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 4561 mActivityTestRule.runOnUiThread(new Runnable() { 4562 @Override 4563 public void run() { 4564 delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info); 4565 } 4566 }); 4567 assertTrue("test sanity", info.isScrollable()); 4568 mActivityTestRule.runOnUiThread(new Runnable() { 4569 @Override 4570 public void run() { 4571 delegateCompat.performAccessibilityAction(mGridView, 4572 AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD, null); 4573 } 4574 }); 4575 waitForScrollIdle(mVerifyLayout); 4576 int selectedPosition1 = mGridView.getSelectedPosition(); 4577 assertTrue(0 < selectedPosition1); 4578 4579 mActivityTestRule.runOnUiThread(new Runnable() { 4580 @Override 4581 public void run() { 4582 delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info); 4583 } 4584 }); 4585 assertTrue("test sanity", info.isScrollable()); 4586 mActivityTestRule.runOnUiThread(new Runnable() { 4587 @Override 4588 public void run() { 4589 delegateCompat.performAccessibilityAction(mGridView, 4590 AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD, null); 4591 } 4592 }); 4593 waitForScrollIdle(mVerifyLayout); 4594 int selectedPosition2 = mGridView.getSelectedPosition(); 4595 assertTrue(selectedPosition2 < selectedPosition1); 4596 } 4597 4598 @Test 4599 public void testAccessibilityScrollForwardHalfVisible() throws Throwable { 4600 Intent intent = new Intent(); 4601 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 4602 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.item_button_at_bottom); 4603 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{}); 4604 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 4605 initActivity(intent); 4606 mOrientation = BaseGridView.VERTICAL; 4607 mNumRows = 1; 4608 4609 int height = mGridView.getHeight() - mGridView.getPaddingTop() 4610 - mGridView.getPaddingBottom(); 4611 final int childHeight = height - mGridView.getVerticalSpacing() - 100; 4612 mActivityTestRule.runOnUiThread(new Runnable() { 4613 @Override 4614 public void run() { 4615 mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE); 4616 mGridView.setWindowAlignmentOffset(100); 4617 mGridView.setWindowAlignmentOffsetPercent(BaseGridView 4618 .WINDOW_ALIGN_OFFSET_PERCENT_DISABLED); 4619 mGridView.setItemAlignmentOffset(0); 4620 mGridView.setItemAlignmentOffsetPercent(BaseGridView 4621 .ITEM_ALIGN_OFFSET_PERCENT_DISABLED); 4622 } 4623 }); 4624 mActivity.addItems(0, new int[]{childHeight, childHeight}); 4625 waitForItemAnimation(); 4626 setSelectedPosition(0); 4627 4628 final RecyclerViewAccessibilityDelegate delegateCompat = mGridView 4629 .getCompatAccessibilityDelegate(); 4630 final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 4631 mActivityTestRule.runOnUiThread(new Runnable() { 4632 @Override 4633 public void run() { 4634 delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info); 4635 } 4636 }); 4637 assertTrue("test sanity", info.isScrollable()); 4638 mActivityTestRule.runOnUiThread(new Runnable() { 4639 @Override 4640 public void run() { 4641 delegateCompat.performAccessibilityAction(mGridView, 4642 AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD, null); 4643 } 4644 }); 4645 waitForScrollIdle(mVerifyLayout); 4646 assertEquals(1, mGridView.getSelectedPosition()); 4647 } 4648 4649 @Test 4650 public void testAccessibilityWhenScrollDisabled() throws Throwable { 4651 Intent intent = new Intent(); 4652 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 4653 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.item_button_at_bottom); 4654 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000); 4655 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 4656 initActivity(intent); 4657 mOrientation = BaseGridView.VERTICAL; 4658 mNumRows = 1; 4659 4660 setSelectedPosition(0); 4661 4662 final RecyclerViewAccessibilityDelegate delegateCompat = mGridView 4663 .getCompatAccessibilityDelegate(); 4664 final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 4665 mActivityTestRule.runOnUiThread(new Runnable() { 4666 @Override 4667 public void run() { 4668 delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info); 4669 } 4670 }); 4671 mGridView.setScrollEnabled(false); 4672 mActivityTestRule.runOnUiThread(new Runnable() { 4673 @Override 4674 public void run() { 4675 for (int i = 0; i < 100; i++) { 4676 delegateCompat.performAccessibilityAction(mGridView, 4677 AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD, null); 4678 } 4679 } 4680 }); 4681 assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState()); 4682 } 4683 4684 private boolean hasAction(AccessibilityNodeInfoCompat info, Object action) { 4685 if (Build.VERSION.SDK_INT >= 21) { 4686 AccessibilityNodeInfoCompat.AccessibilityActionCompat convertedAction = 4687 (AccessibilityNodeInfoCompat.AccessibilityActionCompat) action; 4688 return ((info.getActions() & convertedAction.getId()) != 0); 4689 } else { 4690 int convertedAction = (int) action; 4691 return ((info.getActions() & convertedAction) != 0); 4692 } 4693 } 4694 4695 private void setUpActivityForScrollingTest(final boolean isRTL, boolean isHorizontal, 4696 int numChildViews, boolean isSiblingViewVisible) throws Throwable { 4697 Intent intent = new Intent(); 4698 int layout; 4699 if (isHorizontal) { 4700 layout = isRTL ? R.layout.horizontal_linear_rtl : R.layout.horizontal_linear; 4701 } else { 4702 layout = R.layout.vertical_linear; 4703 } 4704 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, layout); 4705 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.item_button_at_bottom); 4706 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{}); 4707 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 4708 initActivity(intent); 4709 mOrientation = isHorizontal ? BaseGridView.HORIZONTAL : BaseGridView.VERTICAL; 4710 mNumRows = 1; 4711 4712 final int offset = (isSiblingViewVisible ? 2 : 1) * (isHorizontal 4713 ? mGridView.getHorizontalSpacing() : mGridView.getVerticalSpacing()); 4714 final int childSize = (isHorizontal ? mGridView.getWidth() : mGridView.getHeight()) 4715 - offset - (isHorizontal ? 2 * mGridView.getHorizontalSpacing() : 4716 mGridView.getVerticalSpacing()); 4717 mActivityTestRule.runOnUiThread(new Runnable() { 4718 @Override 4719 public void run() { 4720 if (isRTL) { 4721 mGridView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL); 4722 } 4723 mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE); 4724 mGridView.setWindowAlignmentOffset(offset); 4725 mGridView.setWindowAlignmentOffsetPercent(BaseGridView 4726 .WINDOW_ALIGN_OFFSET_PERCENT_DISABLED); 4727 mGridView.setItemAlignmentOffset(0); 4728 mGridView.setItemAlignmentOffsetPercent(BaseGridView 4729 .ITEM_ALIGN_OFFSET_PERCENT_DISABLED); 4730 } 4731 }); 4732 int[] widthArrays = new int[numChildViews]; 4733 Arrays.fill(widthArrays, childSize); 4734 mActivity.addItems(0, widthArrays); 4735 } 4736 4737 private void testScrollingAction(boolean isRTL, boolean isHorizontal) throws Throwable { 4738 waitForItemAnimation(); 4739 setSelectedPosition(1); 4740 final RecyclerViewAccessibilityDelegate delegateCompat = mGridView 4741 .getCompatAccessibilityDelegate(); 4742 final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 4743 mActivityTestRule.runOnUiThread(new Runnable() { 4744 @Override 4745 public void run() { 4746 delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info); 4747 } 4748 }); 4749 // We are currently focusing on item 1, calculating the direction to get me to item 0 4750 final AccessibilityNodeInfoCompat.AccessibilityActionCompat itemZeroDirection; 4751 if (isHorizontal) { 4752 itemZeroDirection = isRTL 4753 ? AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT : 4754 AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT; 4755 } else { 4756 itemZeroDirection = 4757 AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP; 4758 } 4759 final int translatedItemZeroDirection = AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD; 4760 4761 assertTrue("test sanity", info.isScrollable()); 4762 if (Build.VERSION.SDK_INT >= 23) { 4763 assertTrue("test sanity", hasAction(info, itemZeroDirection)); 4764 } else { 4765 assertTrue("test sanity", hasAction(info, translatedItemZeroDirection)); 4766 } 4767 4768 mActivityTestRule.runOnUiThread(new Runnable() { 4769 @Override 4770 public void run() { 4771 if (Build.VERSION.SDK_INT >= 23) { 4772 delegateCompat.performAccessibilityAction(mGridView, itemZeroDirection.getId(), 4773 null); 4774 } else { 4775 delegateCompat.performAccessibilityAction(mGridView, 4776 translatedItemZeroDirection, null); 4777 } 4778 } 4779 }); 4780 waitForScrollIdle(mVerifyLayout); 4781 assertEquals(0, mGridView.getSelectedPosition()); 4782 setSelectedPosition(0); 4783 // We are at item 0, calculate the direction that lead us to the item 1 4784 final AccessibilityNodeInfoCompat.AccessibilityActionCompat itemOneDirection; 4785 if (isHorizontal) { 4786 itemOneDirection = isRTL 4787 ? AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT 4788 : AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT; 4789 } else { 4790 itemOneDirection = 4791 AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN; 4792 } 4793 final int translatedItemOneDirection = AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD; 4794 4795 mActivityTestRule.runOnUiThread(new Runnable() { 4796 @Override 4797 public void run() { 4798 delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info); 4799 } 4800 }); 4801 if (Build.VERSION.SDK_INT >= 23) { 4802 assertTrue("test sanity", hasAction(info, itemOneDirection)); 4803 } else { 4804 assertTrue("test sanity", hasAction(info, translatedItemOneDirection)); 4805 } 4806 mActivityTestRule.runOnUiThread(new Runnable() { 4807 @Override 4808 public void run() { 4809 if (Build.VERSION.SDK_INT >= 23) { 4810 delegateCompat.performAccessibilityAction(mGridView, itemOneDirection.getId(), 4811 null); 4812 } else { 4813 delegateCompat.performAccessibilityAction(mGridView, translatedItemOneDirection, 4814 null); 4815 } 4816 } 4817 }); 4818 waitForScrollIdle(mVerifyLayout); 4819 assertEquals(1, mGridView.getSelectedPosition()); 4820 } 4821 4822 @Test 4823 public void testAccessibilityRespondToLeftRightInvisible() throws Throwable { 4824 boolean isRTL = false; 4825 boolean isHorizontal = true; 4826 setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */, 4827 false /* next child partially visible */); 4828 testScrollingAction(isRTL, isHorizontal); 4829 } 4830 4831 @Test 4832 public void testAccessibilityRespondToLeftRightPartiallyVisible() throws Throwable { 4833 boolean isRTL = false; 4834 boolean isHorizontal = true; 4835 setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */, 4836 true /* next child partially visible */); 4837 testScrollingAction(isRTL, isHorizontal); 4838 } 4839 4840 @Test 4841 public void testAccessibilityRespondToLeftRightRtlInvisible() 4842 throws Throwable { 4843 boolean isRTL = true; 4844 boolean isHorizontal = true; 4845 setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */, 4846 false /* next child partially visible */); 4847 testScrollingAction(isRTL, isHorizontal); 4848 } 4849 4850 @Test 4851 public void testAccessibilityRespondToLeftRightRtlPartiallyVisible() throws Throwable { 4852 boolean isRTL = true; 4853 boolean isHorizontal = true; 4854 setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */, 4855 true /* next child partially visible */); 4856 testScrollingAction(isRTL, isHorizontal); 4857 } 4858 4859 @Test 4860 public void testAccessibilityRespondToScrollUpDownActionInvisible() throws Throwable { 4861 boolean isRTL = false; 4862 boolean isHorizontal = false; 4863 setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */, 4864 false /* next child partially visible */); 4865 testScrollingAction(isRTL, isHorizontal); 4866 } 4867 4868 @Test 4869 public void testAccessibilityRespondToScrollUpDownActionPartiallyVisible() throws Throwable { 4870 boolean isRTL = false; 4871 boolean isHorizontal = false; 4872 setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */, 4873 true /* next child partially visible */); 4874 testScrollingAction(isRTL, isHorizontal); 4875 } 4876 4877 @Test 4878 public void testAccessibilityScrollBackwardHalfVisible() throws Throwable { 4879 Intent intent = new Intent(); 4880 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 4881 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.item_button_at_top); 4882 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{}); 4883 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 4884 initActivity(intent); 4885 mOrientation = BaseGridView.VERTICAL; 4886 mNumRows = 1; 4887 4888 int height = mGridView.getHeight() - mGridView.getPaddingTop() 4889 - mGridView.getPaddingBottom(); 4890 final int childHeight = height - mGridView.getVerticalSpacing() - 100; 4891 mActivityTestRule.runOnUiThread(new Runnable() { 4892 @Override 4893 public void run() { 4894 mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE); 4895 mGridView.setWindowAlignmentOffset(100); 4896 mGridView.setWindowAlignmentOffsetPercent(BaseGridView 4897 .WINDOW_ALIGN_OFFSET_PERCENT_DISABLED); 4898 mGridView.setItemAlignmentOffset(0); 4899 mGridView.setItemAlignmentOffsetPercent(BaseGridView 4900 .ITEM_ALIGN_OFFSET_PERCENT_DISABLED); 4901 } 4902 }); 4903 mActivity.addItems(0, new int[]{childHeight, childHeight}); 4904 waitForItemAnimation(); 4905 setSelectedPosition(1); 4906 4907 final RecyclerViewAccessibilityDelegate delegateCompat = mGridView 4908 .getCompatAccessibilityDelegate(); 4909 final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 4910 mActivityTestRule.runOnUiThread(new Runnable() { 4911 @Override 4912 public void run() { 4913 delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info); 4914 } 4915 }); 4916 assertTrue("test sanity", info.isScrollable()); 4917 mActivityTestRule.runOnUiThread(new Runnable() { 4918 @Override 4919 public void run() { 4920 delegateCompat.performAccessibilityAction(mGridView, 4921 AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD, null); 4922 } 4923 }); 4924 waitForScrollIdle(mVerifyLayout); 4925 assertEquals(0, mGridView.getSelectedPosition()); 4926 } 4927 4928 void slideInAndWaitIdle() throws Throwable { 4929 slideInAndWaitIdle(5000); 4930 } 4931 4932 void slideInAndWaitIdle(long timeout) throws Throwable { 4933 // animateIn() would reset position 4934 mActivityTestRule.runOnUiThread(new Runnable() { 4935 @Override 4936 public void run() { 4937 mGridView.animateIn(); 4938 } 4939 }); 4940 PollingCheck.waitFor(timeout, new PollingCheck.PollingCheckCondition() { 4941 @Override 4942 public boolean canProceed() { 4943 return !mGridView.getLayoutManager().isSmoothScrolling() 4944 && mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE; 4945 } 4946 }); 4947 } 4948 4949 @Test 4950 public void testAnimateOutBlockScrollTo() throws Throwable { 4951 Intent intent = new Intent(); 4952 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 4953 R.layout.vertical_linear_with_button_onleft); 4954 int[] items = new int[100]; 4955 for (int i = 0; i < items.length; i++) { 4956 items[i] = 300; 4957 } 4958 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 4959 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 4960 mOrientation = BaseGridView.VERTICAL; 4961 mNumRows = 1; 4962 4963 initActivity(intent); 4964 4965 assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(), 4966 mGridView.getChildAt(0).getTop()); 4967 4968 mActivityTestRule.runOnUiThread(new Runnable() { 4969 @Override 4970 public void run() { 4971 mGridView.animateOut(); 4972 } 4973 }); 4974 // wait until sliding out. 4975 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 4976 @Override 4977 public boolean canProceed() { 4978 return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop(); 4979 } 4980 }); 4981 // scrollToPosition() should not affect slideOut status 4982 mActivityTestRule.runOnUiThread(new Runnable() { 4983 @Override 4984 public void run() { 4985 mGridView.scrollToPosition(0); 4986 } 4987 }); 4988 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 4989 @Override 4990 public boolean canProceed() { 4991 return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE; 4992 } 4993 }); 4994 assertTrue("First view slided Out", mGridView.getChildAt(0).getTop() 4995 >= mGridView.getHeight()); 4996 4997 slideInAndWaitIdle(); 4998 assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(), 4999 mGridView.getChildAt(0).getTop()); 5000 } 5001 5002 @Test 5003 public void testAnimateOutBlockSmoothScrolling() throws Throwable { 5004 Intent intent = new Intent(); 5005 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 5006 R.layout.vertical_linear_with_button_onleft); 5007 int[] items = new int[30]; 5008 for (int i = 0; i < items.length; i++) { 5009 items[i] = 300; 5010 } 5011 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 5012 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5013 mOrientation = BaseGridView.VERTICAL; 5014 mNumRows = 1; 5015 5016 initActivity(intent); 5017 5018 assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(), 5019 mGridView.getChildAt(0).getTop()); 5020 5021 mActivityTestRule.runOnUiThread(new Runnable() { 5022 @Override 5023 public void run() { 5024 mGridView.animateOut(); 5025 } 5026 }); 5027 // wait until sliding out. 5028 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 5029 @Override 5030 public boolean canProceed() { 5031 return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop(); 5032 } 5033 }); 5034 // smoothScrollToPosition() should not affect slideOut status 5035 mActivityTestRule.runOnUiThread(new Runnable() { 5036 @Override 5037 public void run() { 5038 mGridView.smoothScrollToPosition(29); 5039 } 5040 }); 5041 PollingCheck.waitFor(10000, new PollingCheck.PollingCheckCondition() { 5042 @Override 5043 public boolean canProceed() { 5044 return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE; 5045 } 5046 }); 5047 assertTrue("First view slided Out", mGridView.getChildAt(0).getTop() 5048 >= mGridView.getHeight()); 5049 5050 slideInAndWaitIdle(); 5051 View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1); 5052 assertSame("Scrolled to last child", 5053 mGridView.findViewHolderForAdapterPosition(29).itemView, lastChild); 5054 } 5055 5056 @Test 5057 public void testAnimateOutBlockLongScrollTo() throws Throwable { 5058 Intent intent = new Intent(); 5059 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 5060 R.layout.vertical_linear_with_button_onleft); 5061 int[] items = new int[30]; 5062 for (int i = 0; i < items.length; i++) { 5063 items[i] = 300; 5064 } 5065 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 5066 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5067 mOrientation = BaseGridView.VERTICAL; 5068 mNumRows = 1; 5069 5070 initActivity(intent); 5071 5072 assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(), 5073 mGridView.getChildAt(0).getTop()); 5074 5075 mActivityTestRule.runOnUiThread(new Runnable() { 5076 @Override 5077 public void run() { 5078 mGridView.animateOut(); 5079 } 5080 }); 5081 // wait until sliding out. 5082 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 5083 @Override 5084 public boolean canProceed() { 5085 return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop(); 5086 } 5087 }); 5088 // smoothScrollToPosition() should not affect slideOut status 5089 mActivityTestRule.runOnUiThread(new Runnable() { 5090 @Override 5091 public void run() { 5092 mGridView.scrollToPosition(29); 5093 } 5094 }); 5095 PollingCheck.waitFor(10000, new PollingCheck.PollingCheckCondition() { 5096 @Override 5097 public boolean canProceed() { 5098 return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE; 5099 } 5100 }); 5101 assertTrue("First view slided Out", mGridView.getChildAt(0).getTop() 5102 >= mGridView.getHeight()); 5103 5104 slideInAndWaitIdle(); 5105 View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1); 5106 assertSame("Scrolled to last child", 5107 mGridView.findViewHolderForAdapterPosition(29).itemView, lastChild); 5108 } 5109 5110 @Test 5111 public void testAnimateOutBlockLayout() throws Throwable { 5112 Intent intent = new Intent(); 5113 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 5114 R.layout.vertical_linear_with_button_onleft); 5115 int[] items = new int[100]; 5116 for (int i = 0; i < items.length; i++) { 5117 items[i] = 300; 5118 } 5119 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 5120 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5121 mOrientation = BaseGridView.VERTICAL; 5122 mNumRows = 1; 5123 5124 initActivity(intent); 5125 5126 assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(), 5127 mGridView.getChildAt(0).getTop()); 5128 5129 mActivityTestRule.runOnUiThread(new Runnable() { 5130 @Override 5131 public void run() { 5132 mGridView.animateOut(); 5133 } 5134 }); 5135 // wait until sliding out. 5136 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 5137 @Override 5138 public boolean canProceed() { 5139 return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop(); 5140 } 5141 }); 5142 // change adapter should not affect slideOut status 5143 mActivityTestRule.runOnUiThread(new Runnable() { 5144 @Override 5145 public void run() { 5146 mActivity.changeItem(0, 200); 5147 } 5148 }); 5149 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 5150 @Override 5151 public boolean canProceed() { 5152 return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE; 5153 } 5154 }); 5155 assertTrue("First view slided Out", mGridView.getChildAt(0).getTop() 5156 >= mGridView.getHeight()); 5157 assertEquals("onLayout suppressed during slide out", 300, 5158 mGridView.getChildAt(0).getHeight()); 5159 5160 slideInAndWaitIdle(); 5161 assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(), 5162 mGridView.getChildAt(0).getTop()); 5163 // size of item should be updated immediately after slide in animation finishes: 5164 PollingCheck.waitFor(1000, new PollingCheck.PollingCheckCondition() { 5165 @Override 5166 public boolean canProceed() { 5167 return 200 == mGridView.getChildAt(0).getHeight(); 5168 } 5169 }); 5170 } 5171 5172 @Test 5173 public void testAnimateOutBlockFocusChange() throws Throwable { 5174 Intent intent = new Intent(); 5175 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 5176 R.layout.vertical_linear_with_button_onleft); 5177 int[] items = new int[100]; 5178 for (int i = 0; i < items.length; i++) { 5179 items[i] = 300; 5180 } 5181 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 5182 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5183 mOrientation = BaseGridView.VERTICAL; 5184 mNumRows = 1; 5185 5186 initActivity(intent); 5187 5188 assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(), 5189 mGridView.getChildAt(0).getTop()); 5190 5191 mActivityTestRule.runOnUiThread(new Runnable() { 5192 @Override 5193 public void run() { 5194 mGridView.animateOut(); 5195 mActivity.findViewById(R.id.button).requestFocus(); 5196 } 5197 }); 5198 assertTrue(mActivity.findViewById(R.id.button).hasFocus()); 5199 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 5200 @Override 5201 public boolean canProceed() { 5202 return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop(); 5203 } 5204 }); 5205 mActivityTestRule.runOnUiThread(new Runnable() { 5206 @Override 5207 public void run() { 5208 mGridView.requestFocus(); 5209 } 5210 }); 5211 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 5212 @Override 5213 public boolean canProceed() { 5214 return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE; 5215 } 5216 }); 5217 assertTrue("First view slided Out", mGridView.getChildAt(0).getTop() 5218 >= mGridView.getHeight()); 5219 5220 slideInAndWaitIdle(); 5221 assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(), 5222 mGridView.getChildAt(0).getTop()); 5223 } 5224 5225 @Test 5226 public void testHorizontalAnimateOutBlockScrollTo() throws Throwable { 5227 Intent intent = new Intent(); 5228 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 5229 R.layout.horizontal_linear); 5230 int[] items = new int[100]; 5231 for (int i = 0; i < items.length; i++) { 5232 items[i] = 300; 5233 } 5234 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 5235 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5236 mOrientation = BaseGridView.HORIZONTAL; 5237 mNumRows = 1; 5238 5239 initActivity(intent); 5240 5241 assertEquals("First view is aligned with padding left", mGridView.getPaddingLeft(), 5242 mGridView.getChildAt(0).getLeft()); 5243 5244 mActivityTestRule.runOnUiThread(new Runnable() { 5245 @Override 5246 public void run() { 5247 mGridView.animateOut(); 5248 } 5249 }); 5250 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 5251 @Override 5252 public boolean canProceed() { 5253 return mGridView.getChildAt(0).getLeft() > mGridView.getPaddingLeft(); 5254 } 5255 }); 5256 mActivityTestRule.runOnUiThread(new Runnable() { 5257 @Override 5258 public void run() { 5259 mGridView.scrollToPosition(0); 5260 } 5261 }); 5262 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 5263 @Override 5264 public boolean canProceed() { 5265 return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE; 5266 } 5267 }); 5268 5269 assertTrue("First view is slided out", mGridView.getChildAt(0).getLeft() 5270 > mGridView.getWidth()); 5271 5272 slideInAndWaitIdle(); 5273 assertEquals("First view is aligned with padding left", mGridView.getPaddingLeft(), 5274 mGridView.getChildAt(0).getLeft()); 5275 5276 } 5277 5278 @Test 5279 public void testHorizontalAnimateOutRtl() throws Throwable { 5280 Intent intent = new Intent(); 5281 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 5282 R.layout.horizontal_linear_rtl); 5283 int[] items = new int[100]; 5284 for (int i = 0; i < items.length; i++) { 5285 items[i] = 300; 5286 } 5287 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 5288 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5289 mOrientation = BaseGridView.HORIZONTAL; 5290 mNumRows = 1; 5291 5292 initActivity(intent); 5293 5294 assertEquals("First view is aligned with padding right", 5295 mGridView.getWidth() - mGridView.getPaddingRight(), 5296 mGridView.getChildAt(0).getRight()); 5297 5298 mActivityTestRule.runOnUiThread(new Runnable() { 5299 @Override 5300 public void run() { 5301 mGridView.animateOut(); 5302 } 5303 }); 5304 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 5305 @Override 5306 public boolean canProceed() { 5307 return mGridView.getChildAt(0).getRight() 5308 < mGridView.getWidth() - mGridView.getPaddingRight(); 5309 } 5310 }); 5311 mActivityTestRule.runOnUiThread(new Runnable() { 5312 @Override 5313 public void run() { 5314 mGridView.smoothScrollToPosition(0); 5315 } 5316 }); 5317 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 5318 @Override 5319 public boolean canProceed() { 5320 return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE; 5321 } 5322 }); 5323 5324 assertTrue("First view is slided out", mGridView.getChildAt(0).getRight() < 0); 5325 5326 slideInAndWaitIdle(); 5327 assertEquals("First view is aligned with padding right", 5328 mGridView.getWidth() - mGridView.getPaddingRight(), 5329 mGridView.getChildAt(0).getRight()); 5330 } 5331 5332 @Test 5333 public void testSmoothScrollerOutRange() throws Throwable { 5334 Intent intent = new Intent(); 5335 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 5336 R.layout.vertical_linear_with_button_onleft); 5337 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 5338 int[] items = new int[30]; 5339 for (int i = 0; i < items.length; i++) { 5340 items[i] = 680; 5341 } 5342 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 5343 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5344 mOrientation = BaseGridView.VERTICAL; 5345 mNumRows = 1; 5346 5347 initActivity(intent); 5348 5349 final View button = mActivity.findViewById(R.id.button); 5350 mActivityTestRule.runOnUiThread(new Runnable() { 5351 public void run() { 5352 button.requestFocus(); 5353 } 5354 }); 5355 5356 mGridView.setSelectedPositionSmooth(0); 5357 waitForScrollIdle(mVerifyLayout); 5358 5359 mActivityTestRule.runOnUiThread(new Runnable() { 5360 public void run() { 5361 mGridView.setSelectedPositionSmooth(120); 5362 } 5363 }); 5364 waitForScrollIdle(mVerifyLayout); 5365 assertTrue(button.hasFocus()); 5366 int key; 5367 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 5368 key = KeyEvent.KEYCODE_DPAD_LEFT; 5369 } else { 5370 key = KeyEvent.KEYCODE_DPAD_RIGHT; 5371 } 5372 sendKey(key); 5373 // the GridView should has focus in its children 5374 assertTrue(mGridView.hasFocus()); 5375 assertFalse(mGridView.isFocused()); 5376 assertEquals(29, mGridView.getSelectedPosition()); 5377 } 5378 5379 @Test 5380 public void testRemoveLastItemWithStableId() throws Throwable { 5381 Intent intent = new Intent(); 5382 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 5383 intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, true); 5384 int[] items = new int[1]; 5385 for (int i = 0; i < items.length; i++) { 5386 items[i] = 680; 5387 } 5388 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 5389 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5390 mOrientation = BaseGridView.VERTICAL; 5391 mNumRows = 1; 5392 5393 initActivity(intent); 5394 5395 mActivityTestRule.runOnUiThread(new Runnable() { 5396 @Override 5397 public void run() { 5398 mGridView.getItemAnimator().setRemoveDuration(2000); 5399 mActivity.removeItems(0, 1, false); 5400 mGridView.getAdapter().notifyDataSetChanged(); 5401 } 5402 }); 5403 Thread.sleep(500); 5404 assertEquals(-1, mGridView.getSelectedPosition()); 5405 } 5406 5407 @Test 5408 public void testUpdateAndSelect1() throws Throwable { 5409 Intent intent = new Intent(); 5410 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 5411 intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, false); 5412 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10); 5413 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5414 mOrientation = BaseGridView.VERTICAL; 5415 mNumRows = 1; 5416 5417 initActivity(intent); 5418 5419 mActivityTestRule.runOnUiThread(new Runnable() { 5420 @Override 5421 public void run() { 5422 mGridView.getAdapter().notifyDataSetChanged(); 5423 mGridView.setSelectedPosition(1); 5424 } 5425 }); 5426 waitOneUiCycle(); 5427 assertEquals(1, mGridView.getSelectedPosition()); 5428 } 5429 5430 @Test 5431 public void testUpdateAndSelect2() throws Throwable { 5432 Intent intent = new Intent(); 5433 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 5434 intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, false); 5435 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100); 5436 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5437 mOrientation = BaseGridView.VERTICAL; 5438 mNumRows = 1; 5439 5440 initActivity(intent); 5441 5442 mActivityTestRule.runOnUiThread(new Runnable() { 5443 @Override 5444 public void run() { 5445 mGridView.getAdapter().notifyDataSetChanged(); 5446 mGridView.setSelectedPosition(50); 5447 } 5448 }); 5449 waitOneUiCycle(); 5450 assertEquals(50, mGridView.getSelectedPosition()); 5451 } 5452 5453 @Test 5454 public void testUpdateAndSelect3() throws Throwable { 5455 Intent intent = new Intent(); 5456 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 5457 intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, false); 5458 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10); 5459 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5460 mOrientation = BaseGridView.VERTICAL; 5461 mNumRows = 1; 5462 5463 initActivity(intent); 5464 5465 mActivityTestRule.runOnUiThread(new Runnable() { 5466 @Override 5467 public void run() { 5468 int[] newItems = new int[100]; 5469 for (int i = 0; i < newItems.length; i++) { 5470 newItems[i] = mActivity.mItemLengths[0]; 5471 } 5472 mActivity.addItems(0, newItems, false); 5473 mGridView.getAdapter().notifyDataSetChanged(); 5474 mGridView.setSelectedPosition(50); 5475 } 5476 }); 5477 waitOneUiCycle(); 5478 assertEquals(50, mGridView.getSelectedPosition()); 5479 } 5480 5481 @Test 5482 public void testFocusedPositonAfterRemoved1() throws Throwable { 5483 Intent intent = new Intent(); 5484 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 5485 final int[] items = new int[2]; 5486 for (int i = 0; i < items.length; i++) { 5487 items[i] = 300; 5488 } 5489 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 5490 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5491 mOrientation = BaseGridView.VERTICAL; 5492 mNumRows = 1; 5493 5494 initActivity(intent); 5495 setSelectedPosition(1); 5496 assertEquals(1, mGridView.getSelectedPosition()); 5497 5498 final int[] newItems = new int[3]; 5499 for (int i = 0; i < newItems.length; i++) { 5500 newItems[i] = 300; 5501 } 5502 performAndWaitForAnimation(new Runnable() { 5503 @Override 5504 public void run() { 5505 mActivity.removeItems(0, 2, true); 5506 mActivity.addItems(0, newItems, true); 5507 } 5508 }); 5509 assertEquals(0, mGridView.getSelectedPosition()); 5510 } 5511 5512 @Test 5513 public void testFocusedPositonAfterRemoved2() throws Throwable { 5514 Intent intent = new Intent(); 5515 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 5516 final int[] items = new int[2]; 5517 for (int i = 0; i < items.length; i++) { 5518 items[i] = 300; 5519 } 5520 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 5521 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5522 mOrientation = BaseGridView.VERTICAL; 5523 mNumRows = 1; 5524 5525 initActivity(intent); 5526 setSelectedPosition(1); 5527 assertEquals(1, mGridView.getSelectedPosition()); 5528 5529 final int[] newItems = new int[3]; 5530 for (int i = 0; i < newItems.length; i++) { 5531 newItems[i] = 300; 5532 } 5533 performAndWaitForAnimation(new Runnable() { 5534 @Override 5535 public void run() { 5536 mActivity.removeItems(1, 1, true); 5537 mActivity.addItems(1, newItems, true); 5538 } 5539 }); 5540 assertEquals(1, mGridView.getSelectedPosition()); 5541 } 5542 5543 static void assertNoCollectionItemInfo(AccessibilityNodeInfoCompat info) { 5544 AccessibilityNodeInfoCompat.CollectionItemInfoCompat nodeInfoCompat = 5545 info.getCollectionItemInfo(); 5546 if (nodeInfoCompat == null) { 5547 return; 5548 } 5549 assertTrue(nodeInfoCompat.getRowIndex() < 0); 5550 assertTrue(nodeInfoCompat.getColumnIndex() < 0); 5551 } 5552 5553 /** 5554 * This test would need talkback on. 5555 */ 5556 @Test 5557 public void testAccessibilityOfItemsBeingPushedOut() throws Throwable { 5558 Intent intent = new Intent(); 5559 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid); 5560 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100); 5561 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5562 mOrientation = BaseGridView.HORIZONTAL; 5563 mNumRows = 3; 5564 5565 initActivity(intent); 5566 5567 final int lastPos = mGridView.getChildAdapterPosition( 5568 mGridView.getChildAt(mGridView.getChildCount() - 1)); 5569 mActivityTestRule.runOnUiThread(new Runnable() { 5570 @Override 5571 public void run() { 5572 mGridView.getLayoutManager().setItemPrefetchEnabled(false); 5573 } 5574 }); 5575 final int numItemsToPushOut = mNumRows; 5576 mActivityTestRule.runOnUiThread(new Runnable() { 5577 @Override 5578 public void run() { 5579 // set longer enough so that accessibility service will initialize node 5580 // within setImportantForAccessibility(). 5581 mGridView.getItemAnimator().setRemoveDuration(2000); 5582 mGridView.getItemAnimator().setAddDuration(2000); 5583 final int[] newItems = new int[numItemsToPushOut]; 5584 final int newItemValue = mActivity.mItemLengths[0]; 5585 for (int i = 0; i < newItems.length; i++) { 5586 newItems[i] = newItemValue; 5587 } 5588 mActivity.addItems(lastPos - numItemsToPushOut + 1, newItems); 5589 } 5590 }); 5591 waitForItemAnimation(); 5592 } 5593 5594 /** 5595 * This test simulates talkback by calling setImportanceForAccessibility at end of animation 5596 */ 5597 @Test 5598 public void simulatesAccessibilityOfItemsBeingPushedOut() throws Throwable { 5599 Intent intent = new Intent(); 5600 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid); 5601 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100); 5602 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5603 mOrientation = BaseGridView.HORIZONTAL; 5604 mNumRows = 3; 5605 5606 initActivity(intent); 5607 5608 final HashSet<View> moveAnimationViews = new HashSet(); 5609 mActivity.mImportantForAccessibilityListener = 5610 new GridActivity.ImportantForAccessibilityListener() { 5611 RecyclerView.LayoutManager mLM = mGridView.getLayoutManager(); 5612 @Override 5613 public void onImportantForAccessibilityChanged(View view, int newValue) { 5614 // simulates talkack, having setImportantForAccessibility to call 5615 // onInitializeAccessibilityNodeInfoForItem() for the DISAPPEARING items. 5616 if (moveAnimationViews.contains(view)) { 5617 AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 5618 mLM.onInitializeAccessibilityNodeInfoForItem( 5619 null, null, view, info); 5620 } 5621 } 5622 }; 5623 final int lastPos = mGridView.getChildAdapterPosition( 5624 mGridView.getChildAt(mGridView.getChildCount() - 1)); 5625 final int numItemsToPushOut = mNumRows; 5626 for (int i = 0; i < numItemsToPushOut; i++) { 5627 moveAnimationViews.add( 5628 mGridView.getChildAt(mGridView.getChildCount() - 1 - i)); 5629 } 5630 mActivityTestRule.runOnUiThread(new Runnable() { 5631 @Override 5632 public void run() { 5633 mGridView.setItemAnimator(new DefaultItemAnimator() { 5634 @Override 5635 public void onMoveFinished(RecyclerView.ViewHolder item) { 5636 moveAnimationViews.remove(item.itemView); 5637 } 5638 }); 5639 mGridView.getLayoutManager().setItemPrefetchEnabled(false); 5640 } 5641 }); 5642 mActivityTestRule.runOnUiThread(new Runnable() { 5643 @Override 5644 public void run() { 5645 final int[] newItems = new int[numItemsToPushOut]; 5646 final int newItemValue = mActivity.mItemLengths[0] + 1; 5647 for (int i = 0; i < newItems.length; i++) { 5648 newItems[i] = newItemValue; 5649 } 5650 mActivity.addItems(lastPos - numItemsToPushOut + 1, newItems); 5651 } 5652 }); 5653 while (moveAnimationViews.size() != 0) { 5654 Thread.sleep(100); 5655 } 5656 } 5657 5658 @Test 5659 public void testAccessibilityNodeInfoOnRemovedFirstItem() throws Throwable { 5660 Intent intent = new Intent(); 5661 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid); 5662 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 6); 5663 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5664 mOrientation = BaseGridView.HORIZONTAL; 5665 mNumRows = 3; 5666 5667 initActivity(intent); 5668 5669 final View lastView = mGridView.findViewHolderForAdapterPosition(0).itemView; 5670 mActivityTestRule.runOnUiThread(new Runnable() { 5671 @Override 5672 public void run() { 5673 mGridView.getItemAnimator().setRemoveDuration(20000); 5674 mActivity.removeItems(0, 1); 5675 } 5676 }); 5677 waitForItemAnimationStart(); 5678 AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(lastView); 5679 mGridView.getLayoutManager().onInitializeAccessibilityNodeInfoForItem(null, null, 5680 lastView, info); 5681 assertNoCollectionItemInfo(info); 5682 } 5683 5684 @Test 5685 public void testAccessibilityNodeInfoOnRemovedLastItem() throws Throwable { 5686 Intent intent = new Intent(); 5687 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid); 5688 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 6); 5689 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5690 mOrientation = BaseGridView.HORIZONTAL; 5691 mNumRows = 3; 5692 5693 initActivity(intent); 5694 5695 final View lastView = mGridView.findViewHolderForAdapterPosition(5).itemView; 5696 mActivityTestRule.runOnUiThread(new Runnable() { 5697 @Override 5698 public void run() { 5699 mGridView.getItemAnimator().setRemoveDuration(20000); 5700 mActivity.removeItems(5, 1); 5701 } 5702 }); 5703 waitForItemAnimationStart(); 5704 AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(lastView); 5705 mGridView.getLayoutManager().onInitializeAccessibilityNodeInfoForItem(null, null, 5706 lastView, info); 5707 assertNoCollectionItemInfo(info); 5708 } 5709 5710 static class FiveViewTypesProvider implements ViewTypeProvider { 5711 5712 @Override 5713 public int getViewType(int position) { 5714 switch (position) { 5715 case 0: 5716 return 0; 5717 case 1: 5718 return 1; 5719 case 2: 5720 return 2; 5721 case 3: 5722 return 3; 5723 case 4: 5724 return 4; 5725 } 5726 return 199; 5727 } 5728 } 5729 5730 // Used by testItemAlignmentVertical() testItemAlignmentHorizontal() 5731 static class ItemAlignmentWithPaddingFacetProvider implements 5732 ItemAlignmentFacetProvider { 5733 final ItemAlignmentFacet mFacet0; 5734 final ItemAlignmentFacet mFacet1; 5735 final ItemAlignmentFacet mFacet2; 5736 final ItemAlignmentFacet mFacet3; 5737 final ItemAlignmentFacet mFacet4; 5738 5739 ItemAlignmentWithPaddingFacetProvider() { 5740 ItemAlignmentFacet.ItemAlignmentDef[] defs; 5741 mFacet0 = new ItemAlignmentFacet(); 5742 defs = new ItemAlignmentFacet.ItemAlignmentDef[1]; 5743 defs[0] = new ItemAlignmentFacet.ItemAlignmentDef(); 5744 defs[0].setItemAlignmentViewId(R.id.t1); 5745 defs[0].setItemAlignmentOffsetPercent(0); 5746 defs[0].setItemAlignmentOffsetWithPadding(false); 5747 mFacet0.setAlignmentDefs(defs); 5748 mFacet1 = new ItemAlignmentFacet(); 5749 defs = new ItemAlignmentFacet.ItemAlignmentDef[1]; 5750 defs[0] = new ItemAlignmentFacet.ItemAlignmentDef(); 5751 defs[0].setItemAlignmentViewId(R.id.t1); 5752 defs[0].setItemAlignmentOffsetPercent(0); 5753 defs[0].setItemAlignmentOffsetWithPadding(true); 5754 mFacet1.setAlignmentDefs(defs); 5755 mFacet2 = new ItemAlignmentFacet(); 5756 defs = new ItemAlignmentFacet.ItemAlignmentDef[1]; 5757 defs[0] = new ItemAlignmentFacet.ItemAlignmentDef(); 5758 defs[0].setItemAlignmentViewId(R.id.t2); 5759 defs[0].setItemAlignmentOffsetPercent(100); 5760 defs[0].setItemAlignmentOffsetWithPadding(true); 5761 mFacet2.setAlignmentDefs(defs); 5762 mFacet3 = new ItemAlignmentFacet(); 5763 defs = new ItemAlignmentFacet.ItemAlignmentDef[1]; 5764 defs[0] = new ItemAlignmentFacet.ItemAlignmentDef(); 5765 defs[0].setItemAlignmentViewId(R.id.t2); 5766 defs[0].setItemAlignmentOffsetPercent(50); 5767 defs[0].setItemAlignmentOffsetWithPadding(true); 5768 mFacet3.setAlignmentDefs(defs); 5769 mFacet4 = new ItemAlignmentFacet(); 5770 defs = new ItemAlignmentFacet.ItemAlignmentDef[1]; 5771 defs[0] = new ItemAlignmentFacet.ItemAlignmentDef(); 5772 defs[0].setItemAlignmentViewId(R.id.t2); 5773 defs[0].setItemAlignmentOffsetPercent(50); 5774 defs[0].setItemAlignmentOffsetWithPadding(false); 5775 mFacet4.setAlignmentDefs(defs); 5776 } 5777 5778 @Override 5779 public ItemAlignmentFacet getItemAlignmentFacet(int viewType) { 5780 switch (viewType) { 5781 case 0: 5782 return mFacet0; 5783 case 1: 5784 return mFacet1; 5785 case 2: 5786 return mFacet2; 5787 case 3: 5788 return mFacet3; 5789 case 4: 5790 return mFacet4; 5791 } 5792 return null; 5793 } 5794 } 5795 5796 @Test 5797 public void testItemAlignmentVertical() throws Throwable { 5798 Intent intent = new Intent(); 5799 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 5800 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout2); 5801 int[] items = new int[5]; 5802 for (int i = 0; i < items.length; i++) { 5803 items[i] = 300; 5804 } 5805 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 5806 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5807 intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS, 5808 FiveViewTypesProvider.class.getName()); 5809 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS, 5810 ItemAlignmentWithPaddingFacetProvider.class.getName()); 5811 mOrientation = BaseGridView.VERTICAL; 5812 mNumRows = 1; 5813 5814 initActivity(intent); 5815 startWaitLayout(); 5816 mActivityTestRule.runOnUiThread(new Runnable() { 5817 @Override 5818 public void run() { 5819 mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE); 5820 mGridView.setWindowAlignmentOffsetPercent(50); 5821 mGridView.setWindowAlignmentOffset(0); 5822 } 5823 }); 5824 waitForLayout(); 5825 5826 final float windowAlignCenter = mGridView.getHeight() / 2f; 5827 Rect rect = new Rect(); 5828 View textView; 5829 5830 // test 1: does not include padding 5831 textView = mGridView.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.t1); 5832 rect.set(0, 0, textView.getWidth(), textView.getHeight()); 5833 mGridView.offsetDescendantRectToMyCoords(textView, rect); 5834 assertEquals(windowAlignCenter, rect.top, DELTA); 5835 5836 // test 2: including low padding 5837 setSelectedPosition(1); 5838 textView = mGridView.findViewHolderForAdapterPosition(1).itemView.findViewById(R.id.t1); 5839 assertTrue(textView.getPaddingTop() > 0); 5840 rect.set(0, textView.getPaddingTop(), textView.getWidth(), textView.getHeight()); 5841 mGridView.offsetDescendantRectToMyCoords(textView, rect); 5842 assertEquals(windowAlignCenter, rect.top, DELTA); 5843 5844 // test 3: including high padding 5845 setSelectedPosition(2); 5846 textView = mGridView.findViewHolderForAdapterPosition(2).itemView.findViewById(R.id.t2); 5847 assertTrue(textView.getPaddingBottom() > 0); 5848 rect.set(0, 0, textView.getWidth(), 5849 textView.getHeight() - textView.getPaddingBottom()); 5850 mGridView.offsetDescendantRectToMyCoords(textView, rect); 5851 assertEquals(windowAlignCenter, rect.bottom, DELTA); 5852 5853 // test 4: including padding will be ignored if offsetPercent is not 0 or 100 5854 setSelectedPosition(3); 5855 textView = mGridView.findViewHolderForAdapterPosition(3).itemView.findViewById(R.id.t2); 5856 assertTrue(textView.getPaddingTop() != textView.getPaddingBottom()); 5857 rect.set(0, 0, textView.getWidth(), textView.getHeight() / 2); 5858 mGridView.offsetDescendantRectToMyCoords(textView, rect); 5859 assertEquals(windowAlignCenter, rect.bottom, DELTA); 5860 5861 // test 5: does not include padding 5862 setSelectedPosition(4); 5863 textView = mGridView.findViewHolderForAdapterPosition(4).itemView.findViewById(R.id.t2); 5864 assertTrue(textView.getPaddingTop() != textView.getPaddingBottom()); 5865 rect.set(0, 0, textView.getWidth(), textView.getHeight() / 2); 5866 mGridView.offsetDescendantRectToMyCoords(textView, rect); 5867 assertEquals(windowAlignCenter, rect.bottom, DELTA); 5868 } 5869 5870 @Test 5871 public void testItemAlignmentHorizontal() throws Throwable { 5872 Intent intent = new Intent(); 5873 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear); 5874 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout3); 5875 int[] items = new int[5]; 5876 for (int i = 0; i < items.length; i++) { 5877 items[i] = 300; 5878 } 5879 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 5880 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5881 intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS, 5882 FiveViewTypesProvider.class.getName()); 5883 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS, 5884 ItemAlignmentWithPaddingFacetProvider.class.getName()); 5885 mOrientation = BaseGridView.VERTICAL; 5886 mNumRows = 1; 5887 5888 initActivity(intent); 5889 startWaitLayout(); 5890 mActivityTestRule.runOnUiThread(new Runnable() { 5891 @Override 5892 public void run() { 5893 mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE); 5894 mGridView.setWindowAlignmentOffsetPercent(50); 5895 mGridView.setWindowAlignmentOffset(0); 5896 } 5897 }); 5898 waitForLayout(); 5899 5900 final float windowAlignCenter = mGridView.getWidth() / 2f; 5901 Rect rect = new Rect(); 5902 View textView; 5903 5904 // test 1: does not include padding 5905 textView = mGridView.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.t1); 5906 rect.set(0, 0, textView.getWidth(), textView.getHeight()); 5907 mGridView.offsetDescendantRectToMyCoords(textView, rect); 5908 assertEquals(windowAlignCenter, rect.left, DELTA); 5909 5910 // test 2: including low padding 5911 setSelectedPosition(1); 5912 textView = mGridView.findViewHolderForAdapterPosition(1).itemView.findViewById(R.id.t1); 5913 assertTrue(textView.getPaddingLeft() > 0); 5914 rect.set(textView.getPaddingLeft(), 0, textView.getWidth(), textView.getHeight()); 5915 mGridView.offsetDescendantRectToMyCoords(textView, rect); 5916 assertEquals(windowAlignCenter, rect.left, DELTA); 5917 5918 // test 3: including high padding 5919 setSelectedPosition(2); 5920 textView = mGridView.findViewHolderForAdapterPosition(2).itemView.findViewById(R.id.t2); 5921 assertTrue(textView.getPaddingRight() > 0); 5922 rect.set(0, 0, textView.getWidth() - textView.getPaddingRight(), 5923 textView.getHeight()); 5924 mGridView.offsetDescendantRectToMyCoords(textView, rect); 5925 assertEquals(windowAlignCenter, rect.right, DELTA); 5926 5927 // test 4: including padding will be ignored if offsetPercent is not 0 or 100 5928 setSelectedPosition(3); 5929 textView = mGridView.findViewHolderForAdapterPosition(3).itemView.findViewById(R.id.t2); 5930 assertTrue(textView.getPaddingLeft() != textView.getPaddingRight()); 5931 rect.set(0, 0, textView.getWidth() / 2, textView.getHeight()); 5932 mGridView.offsetDescendantRectToMyCoords(textView, rect); 5933 assertEquals(windowAlignCenter, rect.right, DELTA); 5934 5935 // test 5: does not include padding 5936 setSelectedPosition(4); 5937 textView = mGridView.findViewHolderForAdapterPosition(4).itemView.findViewById(R.id.t2); 5938 assertTrue(textView.getPaddingLeft() != textView.getPaddingRight()); 5939 rect.set(0, 0, textView.getWidth() / 2, textView.getHeight()); 5940 mGridView.offsetDescendantRectToMyCoords(textView, rect); 5941 assertEquals(windowAlignCenter, rect.right, DELTA); 5942 } 5943 5944 @Test 5945 public void testItemAlignmentHorizontalRtl() throws Throwable { 5946 Intent intent = new Intent(); 5947 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear); 5948 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout3); 5949 int[] items = new int[5]; 5950 for (int i = 0; i < items.length; i++) { 5951 items[i] = 300; 5952 } 5953 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 5954 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 5955 intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS, 5956 FiveViewTypesProvider.class.getName()); 5957 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS, 5958 ItemAlignmentWithPaddingFacetProvider.class.getName()); 5959 mOrientation = BaseGridView.VERTICAL; 5960 mNumRows = 1; 5961 5962 initActivity(intent); 5963 startWaitLayout(); 5964 mActivityTestRule.runOnUiThread(new Runnable() { 5965 @Override 5966 public void run() { 5967 mGridView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL); 5968 mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE); 5969 mGridView.setWindowAlignmentOffsetPercent(50); 5970 mGridView.setWindowAlignmentOffset(0); 5971 } 5972 }); 5973 waitForLayout(); 5974 5975 final float windowAlignCenter = mGridView.getWidth() / 2f; 5976 Rect rect = new Rect(); 5977 View textView; 5978 5979 // test 1: does not include padding 5980 textView = mGridView.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.t1); 5981 rect.set(0, 0, textView.getWidth(), textView.getHeight()); 5982 mGridView.offsetDescendantRectToMyCoords(textView, rect); 5983 assertEquals(windowAlignCenter, rect.right, DELTA); 5984 5985 // test 2: including low padding 5986 setSelectedPosition(1); 5987 textView = mGridView.findViewHolderForAdapterPosition(1).itemView.findViewById(R.id.t1); 5988 assertTrue(textView.getPaddingRight() > 0); 5989 rect.set(0, 0, textView.getWidth() - textView.getPaddingRight(), 5990 textView.getHeight()); 5991 mGridView.offsetDescendantRectToMyCoords(textView, rect); 5992 assertEquals(windowAlignCenter, rect.right, DELTA); 5993 5994 // test 3: including high padding 5995 setSelectedPosition(2); 5996 textView = mGridView.findViewHolderForAdapterPosition(2).itemView.findViewById(R.id.t2); 5997 assertTrue(textView.getPaddingLeft() > 0); 5998 rect.set(textView.getPaddingLeft(), 0, textView.getWidth(), 5999 textView.getHeight()); 6000 mGridView.offsetDescendantRectToMyCoords(textView, rect); 6001 assertEquals(windowAlignCenter, rect.left, DELTA); 6002 6003 // test 4: including padding will be ignored if offsetPercent is not 0 or 100 6004 setSelectedPosition(3); 6005 textView = mGridView.findViewHolderForAdapterPosition(3).itemView.findViewById(R.id.t2); 6006 assertTrue(textView.getPaddingLeft() != textView.getPaddingRight()); 6007 rect.set(0, 0, textView.getWidth() / 2, textView.getHeight()); 6008 mGridView.offsetDescendantRectToMyCoords(textView, rect); 6009 assertEquals(windowAlignCenter, rect.right, DELTA); 6010 6011 // test 5: does not include padding 6012 setSelectedPosition(4); 6013 textView = mGridView.findViewHolderForAdapterPosition(4).itemView.findViewById(R.id.t2); 6014 assertTrue(textView.getPaddingLeft() != textView.getPaddingRight()); 6015 rect.set(0, 0, textView.getWidth() / 2, textView.getHeight()); 6016 mGridView.offsetDescendantRectToMyCoords(textView, rect); 6017 assertEquals(windowAlignCenter, rect.right, DELTA); 6018 } 6019 6020 enum ItemLocation { 6021 ITEM_AT_LOW, 6022 ITEM_AT_KEY_LINE, 6023 ITEM_AT_HIGH 6024 }; 6025 6026 static class ItemAt { 6027 final int mScrollPosition; 6028 final int mPosition; 6029 final ItemLocation mLocation; 6030 6031 ItemAt(int scrollPosition, int position, ItemLocation loc) { 6032 mScrollPosition = scrollPosition; 6033 mPosition = position; 6034 mLocation = loc; 6035 } 6036 6037 ItemAt(int position, ItemLocation loc) { 6038 mScrollPosition = position; 6039 mPosition = position; 6040 mLocation = loc; 6041 } 6042 } 6043 6044 /** 6045 * When scroll to position, item at position is expected at given location. 6046 */ 6047 static ItemAt itemAt(int position, ItemLocation location) { 6048 return new ItemAt(position, location); 6049 } 6050 6051 /** 6052 * When scroll to scrollPosition, item at position is expected at given location. 6053 */ 6054 static ItemAt itemAt(int scrollPosition, int position, ItemLocation location) { 6055 return new ItemAt(scrollPosition, position, location); 6056 } 6057 6058 void prepareKeyLineTest(int numItems) throws Throwable { 6059 Intent intent = new Intent(); 6060 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear); 6061 int[] items = new int[numItems]; 6062 for (int i = 0; i < items.length; i++) { 6063 items[i] = 32; 6064 } 6065 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 6066 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 6067 mOrientation = BaseGridView.HORIZONTAL; 6068 mNumRows = 1; 6069 6070 initActivity(intent); 6071 } 6072 6073 public void testPreferKeyLine(final int windowAlignment, 6074 final boolean preferKeyLineOverLow, 6075 final boolean preferKeyLineOverHigh, 6076 ItemLocation assertFirstItemLocation, 6077 ItemLocation assertLastItemLocation) throws Throwable { 6078 testPreferKeyLine(windowAlignment, preferKeyLineOverLow, preferKeyLineOverHigh, 6079 itemAt(0, assertFirstItemLocation), 6080 itemAt(mActivity.mNumItems - 1, assertLastItemLocation)); 6081 } 6082 6083 public void testPreferKeyLine(final int windowAlignment, 6084 final boolean preferKeyLineOverLow, 6085 final boolean preferKeyLineOverHigh, 6086 ItemLocation assertFirstItemLocation, 6087 ItemAt assertLastItemLocation) throws Throwable { 6088 testPreferKeyLine(windowAlignment, preferKeyLineOverLow, preferKeyLineOverHigh, 6089 itemAt(0, assertFirstItemLocation), 6090 assertLastItemLocation); 6091 } 6092 6093 public void testPreferKeyLine(final int windowAlignment, 6094 final boolean preferKeyLineOverLow, 6095 final boolean preferKeyLineOverHigh, 6096 ItemAt assertFirstItemLocation, 6097 ItemLocation assertLastItemLocation) throws Throwable { 6098 testPreferKeyLine(windowAlignment, preferKeyLineOverLow, preferKeyLineOverHigh, 6099 assertFirstItemLocation, 6100 itemAt(mActivity.mNumItems - 1, assertLastItemLocation)); 6101 } 6102 6103 public void testPreferKeyLine(final int windowAlignment, 6104 final boolean preferKeyLineOverLow, 6105 final boolean preferKeyLineOverHigh, 6106 ItemAt assertFirstItemLocation, 6107 ItemAt assertLastItemLocation) throws Throwable { 6108 TestPreferKeyLineOptions options = new TestPreferKeyLineOptions(); 6109 options.mAssertItemLocations = new ItemAt[] {assertFirstItemLocation, 6110 assertLastItemLocation}; 6111 options.mPreferKeyLineOverLow = preferKeyLineOverLow; 6112 options.mPreferKeyLineOverHigh = preferKeyLineOverHigh; 6113 options.mWindowAlignment = windowAlignment; 6114 6115 options.mRtl = false; 6116 testPreferKeyLine(options); 6117 6118 options.mRtl = true; 6119 testPreferKeyLine(options); 6120 } 6121 6122 static class TestPreferKeyLineOptions { 6123 int mWindowAlignment; 6124 boolean mPreferKeyLineOverLow; 6125 boolean mPreferKeyLineOverHigh; 6126 ItemAt[] mAssertItemLocations; 6127 boolean mRtl; 6128 } 6129 6130 public void testPreferKeyLine(final TestPreferKeyLineOptions options) throws Throwable { 6131 startWaitLayout(); 6132 mActivityTestRule.runOnUiThread(new Runnable() { 6133 @Override 6134 public void run() { 6135 if (options.mRtl) { 6136 mGridView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL); 6137 } else { 6138 mGridView.setLayoutDirection(View.LAYOUT_DIRECTION_LTR); 6139 } 6140 mGridView.setWindowAlignment(options.mWindowAlignment); 6141 mGridView.setWindowAlignmentOffsetPercent(50); 6142 mGridView.setWindowAlignmentOffset(0); 6143 mGridView.setWindowAlignmentPreferKeyLineOverLowEdge(options.mPreferKeyLineOverLow); 6144 mGridView.setWindowAlignmentPreferKeyLineOverHighEdge( 6145 options.mPreferKeyLineOverHigh); 6146 } 6147 }); 6148 waitForLayout(); 6149 6150 final int paddingStart = mGridView.getPaddingStart(); 6151 final int paddingEnd = mGridView.getPaddingEnd(); 6152 final int windowAlignCenter = mGridView.getWidth() / 2; 6153 6154 for (int i = 0; i < options.mAssertItemLocations.length; i++) { 6155 ItemAt assertItemLocation = options.mAssertItemLocations[i]; 6156 setSelectedPosition(assertItemLocation.mScrollPosition); 6157 View view = mGridView.findViewHolderForAdapterPosition(assertItemLocation.mPosition) 6158 .itemView; 6159 switch (assertItemLocation.mLocation) { 6160 case ITEM_AT_LOW: 6161 if (options.mRtl) { 6162 assertEquals(mGridView.getWidth() - paddingStart, view.getRight()); 6163 } else { 6164 assertEquals(paddingStart, view.getLeft()); 6165 } 6166 break; 6167 case ITEM_AT_HIGH: 6168 if (options.mRtl) { 6169 assertEquals(paddingEnd, view.getLeft()); 6170 } else { 6171 assertEquals(mGridView.getWidth() - paddingEnd, view.getRight()); 6172 } 6173 break; 6174 case ITEM_AT_KEY_LINE: 6175 assertEquals(windowAlignCenter, (view.getLeft() + view.getRight()) / 2, DELTA); 6176 break; 6177 } 6178 } 6179 } 6180 6181 @Test 6182 public void testPreferKeyLine1() throws Throwable { 6183 prepareKeyLineTest(1); 6184 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, false, 6185 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6186 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, true, 6187 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6188 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, false, 6189 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6190 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, true, 6191 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6192 6193 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, false, 6194 ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_LOW); 6195 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, true, 6196 ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_LOW); 6197 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, false, 6198 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6199 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, true, 6200 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6201 6202 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, false, 6203 ItemLocation.ITEM_AT_HIGH, ItemLocation.ITEM_AT_HIGH); 6204 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, true, 6205 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6206 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, false, 6207 ItemLocation.ITEM_AT_HIGH, ItemLocation.ITEM_AT_HIGH); 6208 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, true, 6209 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6210 6211 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, false, 6212 ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_LOW); 6213 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, true, 6214 ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_LOW); 6215 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, false, 6216 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6217 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, true, 6218 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6219 } 6220 6221 @Test 6222 public void testPreferKeyLine2() throws Throwable { 6223 prepareKeyLineTest(2); 6224 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, false, 6225 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6226 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, true, 6227 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6228 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, false, 6229 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6230 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, true, 6231 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6232 6233 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, false, 6234 ItemLocation.ITEM_AT_LOW, itemAt(1, 0, ItemLocation.ITEM_AT_LOW)); 6235 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, true, 6236 ItemLocation.ITEM_AT_LOW, itemAt(1, 0, ItemLocation.ITEM_AT_LOW)); 6237 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, false, 6238 itemAt(0, 1, ItemLocation.ITEM_AT_KEY_LINE), 6239 itemAt(1, 1, ItemLocation.ITEM_AT_KEY_LINE)); 6240 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, true, 6241 itemAt(0, 1, ItemLocation.ITEM_AT_KEY_LINE), 6242 itemAt(1, 1, ItemLocation.ITEM_AT_KEY_LINE)); 6243 6244 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, false, 6245 itemAt(0, 1, ItemLocation.ITEM_AT_HIGH), 6246 itemAt(1, 1, ItemLocation.ITEM_AT_HIGH)); 6247 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, true, 6248 itemAt(0, 0, ItemLocation.ITEM_AT_KEY_LINE), 6249 itemAt(1, 0, ItemLocation.ITEM_AT_KEY_LINE)); 6250 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, false, 6251 itemAt(0, 1, ItemLocation.ITEM_AT_HIGH), 6252 itemAt(1, 1, ItemLocation.ITEM_AT_HIGH)); 6253 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, true, 6254 itemAt(0, 0, ItemLocation.ITEM_AT_KEY_LINE), 6255 itemAt(1, 0, ItemLocation.ITEM_AT_KEY_LINE)); 6256 6257 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, false, 6258 ItemLocation.ITEM_AT_LOW, itemAt(1, 0, ItemLocation.ITEM_AT_LOW)); 6259 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, true, 6260 ItemLocation.ITEM_AT_LOW, itemAt(1, 0, ItemLocation.ITEM_AT_LOW)); 6261 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, false, 6262 itemAt(0, 1, ItemLocation.ITEM_AT_KEY_LINE), 6263 itemAt(1, 1, ItemLocation.ITEM_AT_KEY_LINE)); 6264 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, true, 6265 itemAt(0, 1, ItemLocation.ITEM_AT_KEY_LINE), 6266 itemAt(1, 1, ItemLocation.ITEM_AT_KEY_LINE)); 6267 } 6268 6269 @Test 6270 public void testPreferKeyLine10000() throws Throwable { 6271 prepareKeyLineTest(10000); 6272 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, false, 6273 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6274 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, true, 6275 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6276 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, false, 6277 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6278 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, true, 6279 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE); 6280 6281 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, false, 6282 ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_KEY_LINE); 6283 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, true, 6284 ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_KEY_LINE); 6285 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, false, 6286 ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_KEY_LINE); 6287 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, true, 6288 ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_KEY_LINE); 6289 6290 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, false, 6291 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_HIGH); 6292 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, true, 6293 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_HIGH); 6294 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, false, 6295 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_HIGH); 6296 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, true, 6297 ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_HIGH); 6298 6299 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, false, 6300 ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_HIGH); 6301 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, true, 6302 ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_HIGH); 6303 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, false, 6304 ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_HIGH); 6305 testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, true, 6306 ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_HIGH); 6307 } 6308} 6309