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