1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package android.support.v17.leanback.widget; 17 18import android.app.Instrumentation; 19import android.content.Intent; 20import android.graphics.Canvas; 21import android.graphics.Color; 22import android.graphics.Rect; 23import android.graphics.drawable.ColorDrawable; 24import android.os.Parcelable; 25import android.support.v17.leanback.test.R; 26import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 27import android.support.v7.widget.RecyclerView; 28import android.support.v7.widget.RecyclerViewAccessibilityDelegate; 29import android.test.ActivityInstrumentationTestCase2; 30import android.test.suitebuilder.annotation.MediumTest; 31import android.text.Selection; 32import android.text.Spannable; 33import android.util.SparseArray; 34import android.util.SparseIntArray; 35import android.view.KeyEvent; 36import android.view.View; 37import android.view.ViewGroup; 38import android.widget.TextView; 39 40import java.util.ArrayList; 41import java.util.Arrays; 42import java.util.Comparator; 43import java.util.HashMap; 44 45@MediumTest 46public class GridWidgetTest extends ActivityInstrumentationTestCase2<GridActivity> { 47 48 private static final boolean HUMAN_DELAY = false; 49 private static final long WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS = 60000; 50 51 protected GridActivity mActivity; 52 protected Instrumentation mInstrumentation; 53 protected BaseGridView mGridView; 54 protected GridLayoutManager mLayoutManager; 55 protected int mOrientation; 56 protected int mNumRows; 57 58 private final Comparator<View> mRowSortComparator = new Comparator<View>() { 59 public int compare(View lhs, View rhs) { 60 if (mOrientation == BaseGridView.HORIZONTAL) { 61 return lhs.getLeft() - rhs.getLeft(); 62 } else { 63 return lhs.getTop() - rhs.getTop(); 64 } 65 }; 66 }; 67 68 /** 69 * Verify margins between items on same row are same. 70 */ 71 private final Runnable mVerifyLayout = new Runnable() { 72 @Override 73 public void run() { 74 verifyMargin(); 75 } 76 }; 77 78 public GridWidgetTest() { 79 super("android.support.v17.leanback.test", GridActivity.class); 80 } 81 82 private void humanDelay(int delay) throws InterruptedException { 83 if (HUMAN_DELAY) Thread.sleep(delay); 84 } 85 /** 86 * Change size of the Adapter and notifyDataSetChanged. 87 */ 88 private void changeArraySize(final int size) throws Throwable { 89 runTestOnUiThread(new Runnable() { 90 public void run() { 91 mActivity.changeArraySize(size); 92 } 93 }); 94 Thread.sleep(500); 95 } 96 97 /** 98 * Change selected position. 99 */ 100 private void setSelectedPosition(final int position, final int scrollExtra) throws Throwable { 101 runTestOnUiThread(new Runnable() { 102 public void run() { 103 mGridView.setSelectedPosition(position, scrollExtra); 104 } 105 }); 106 Thread.sleep(500); 107 } 108 109 protected void waitForScrollIdleAndItemAnimation(Runnable verify) throws Throwable { 110 waitForScrollIdle(); 111 waitForItemAnimation(); 112 verify.run(); 113 } 114 115 protected void waitForItemAnimation() throws Throwable { 116 Thread.sleep(100); 117 while (mGridView.getItemAnimator() != null && mGridView.getItemAnimator().isRunning()) { 118 try { 119 Thread.sleep(100); 120 } catch (InterruptedException ex) { 121 break; 122 } 123 } 124 } 125 126 /** 127 * Wait for grid view stop scroll and optionally verify state of grid view. 128 */ 129 protected void waitForScrollIdle(Runnable verify) throws Throwable { 130 Thread.sleep(100); 131 int total = 0; 132 while (mGridView.getLayoutManager().isSmoothScrolling() || 133 mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE) { 134 if ((total += 100) >= WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS) { 135 throw new RuntimeException("waitForScrollIdle Timeout"); 136 } 137 try { 138 Thread.sleep(100); 139 } catch (InterruptedException ex) { 140 break; 141 } 142 if (verify != null) { 143 runTestOnUiThread(verify); 144 } 145 } 146 } 147 148 /** 149 * Wait for grid view stop animation and optionally verify state of grid view. 150 */ 151 protected void waitForTransientStateGone(Runnable verify) throws Throwable { 152 do { 153 try { 154 Thread.sleep(100); 155 } catch (InterruptedException ex) { 156 break; 157 } 158 if (verify != null) { 159 runTestOnUiThread(verify); 160 } 161 } while (mGridView.hasTransientState()); 162 } 163 164 /** 165 * Wait for grid view stop scroll. 166 */ 167 protected void waitForScrollIdle() throws Throwable { 168 waitForScrollIdle(null); 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 runTestOnUiThread(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 if (mOrientation == BaseGridView.HORIZONTAL) { 192 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 193 key = KeyEvent.KEYCODE_DPAD_RIGHT; 194 } else { 195 key = KeyEvent.KEYCODE_DPAD_LEFT; 196 } 197 } else { 198 key = KeyEvent.KEYCODE_DPAD_UP; 199 } 200 scroll(key, verify); 201 } 202 203 protected void scrollToEnd(Runnable verify) throws Throwable { 204 int key; 205 if (mOrientation == BaseGridView.HORIZONTAL) { 206 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 207 key = KeyEvent.KEYCODE_DPAD_LEFT; 208 } else { 209 key = KeyEvent.KEYCODE_DPAD_RIGHT; 210 } 211 } else { 212 key = KeyEvent.KEYCODE_DPAD_DOWN; 213 } 214 scroll(key, verify); 215 } 216 217 /** 218 * Group and sort children by their position on each row (HORIZONTAL) or column(VERTICAL). 219 */ 220 protected View[][] sortByRows() { 221 final HashMap<Integer, ArrayList<View>> rows = new HashMap<Integer, ArrayList<View>>(); 222 ArrayList<Integer> rowLocations = new ArrayList(); 223 for (int i = 0; i < mGridView.getChildCount(); i++) { 224 View v = mGridView.getChildAt(i); 225 int rowLocation; 226 if (mOrientation == BaseGridView.HORIZONTAL) { 227 rowLocation = v.getTop(); 228 } else { 229 rowLocation = mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL ? 230 v.getRight() : v.getLeft(); 231 } 232 ArrayList<View> views = rows.get(rowLocation); 233 if (views == null) { 234 views = new ArrayList<View>(); 235 rows.put(rowLocation, views); 236 rowLocations.add(rowLocation); 237 } 238 views.add(v); 239 } 240 Object[] sortedLocations = rowLocations.toArray(); 241 Arrays.sort(sortedLocations); 242 if (mNumRows != rows.size()) { 243 assertEquals("Dump Views by rows "+rows, mNumRows, rows.size()); 244 } 245 View[][] sorted = new View[rows.size()][]; 246 for (int i = 0; i < rowLocations.size(); i++) { 247 Integer rowLocation = rowLocations.get(i); 248 ArrayList<View> arr = rows.get(rowLocation); 249 View[] views = arr.toArray(new View[arr.size()]); 250 Arrays.sort(views, mRowSortComparator); 251 sorted[i] = views; 252 } 253 return sorted; 254 } 255 256 protected void verifyMargin() { 257 View[][] sorted = sortByRows(); 258 for (int row = 0; row < sorted.length; row++) { 259 View[] views = sorted[row]; 260 int margin = -1; 261 for (int i = 1; i < views.length; i++) { 262 if (mOrientation == BaseGridView.HORIZONTAL) { 263 assertEquals(mGridView.getHorizontalMargin(), 264 views[i].getLeft() - views[i - 1].getRight()); 265 } else { 266 assertEquals(mGridView.getVerticalMargin(), 267 views[i].getTop() - views[i - 1].getBottom()); 268 } 269 } 270 } 271 } 272 273 protected void verifyBeginAligned() { 274 View[][] sorted = sortByRows(); 275 int alignedLocation = 0; 276 if (mOrientation == BaseGridView.HORIZONTAL) { 277 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 278 for (int i = 0; i < sorted.length; i++) { 279 if (i == 0) { 280 alignedLocation = sorted[i][sorted[i].length - 1].getRight(); 281 } else { 282 assertEquals(alignedLocation, sorted[i][sorted[i].length - 1].getRight()); 283 } 284 } 285 } else { 286 for (int i = 0; i < sorted.length; i++) { 287 if (i == 0) { 288 alignedLocation = sorted[i][0].getLeft(); 289 } else { 290 assertEquals(alignedLocation, sorted[i][0].getLeft()); 291 } 292 } 293 } 294 } else { 295 for (int i = 0; i < sorted.length; i++) { 296 if (i == 0) { 297 alignedLocation = sorted[i][0].getTop(); 298 } else { 299 assertEquals(alignedLocation, sorted[i][0].getTop()); 300 } 301 } 302 } 303 } 304 305 protected int[] getEndEdges() { 306 View[][] sorted = sortByRows(); 307 int[] edges = new int[sorted.length]; 308 if (mOrientation == BaseGridView.HORIZONTAL) { 309 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 310 for (int i = 0; i < sorted.length; i++) { 311 edges[i] = sorted[i][0].getLeft(); 312 } 313 } else { 314 for (int i = 0; i < sorted.length; i++) { 315 edges[i] = sorted[i][sorted[i].length - 1].getRight(); 316 } 317 } 318 } else { 319 for (int i = 0; i < sorted.length; i++) { 320 edges[i] = sorted[i][sorted[i].length - 1].getBottom(); 321 } 322 } 323 return edges; 324 } 325 326 protected void verifyEdgesSame(int[] edges, int[] edges2) { 327 assertEquals(edges.length, edges2.length); 328 for (int i = 0; i < edges.length; i++) { 329 assertEquals(edges[i], edges2[i]); 330 } 331 } 332 333 protected void verifyBoundCount(int count) { 334 if (mActivity.getBoundCount() != count) { 335 StringBuffer b = new StringBuffer(); 336 b.append("ItemsLength: "); 337 for (int i = 0; i < mActivity.mItemLengths.length; i++) { 338 b.append(mActivity.mItemLengths[i]).append(","); 339 } 340 assertEquals("Bound count does not match, ItemsLengths: "+ b, 341 count, mActivity.getBoundCount()); 342 } 343 } 344 345 private static int getCenterY(View v) { 346 return (v.getTop() + v.getBottom())/2; 347 } 348 349 private static int getCenterX(View v) { 350 return (v.getLeft() + v.getRight())/2; 351 } 352 353 private void initActivity(Intent intent) { 354 setActivityIntent(intent); 355 mActivity = getActivity(); 356 final String testName = getName(); 357 try { 358 runTestOnUiThread(new Runnable() { 359 public void run() { 360 mActivity.setTitle(testName); 361 } 362 }); 363 Thread.sleep(1000); 364 } catch (Throwable t) { 365 t.printStackTrace(); 366 } 367 mGridView = mActivity.mGridView; 368 } 369 370 public void testThreeRowHorizontalBasic() throws Throwable { 371 mInstrumentation = getInstrumentation(); 372 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 373 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid); 374 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100); 375 initActivity(intent); 376 mOrientation = BaseGridView.HORIZONTAL; 377 mNumRows = 3; 378 379 scrollToEnd(mVerifyLayout); 380 verifyBoundCount(100); 381 382 scrollToBegin(mVerifyLayout); 383 384 verifyBeginAligned(); 385 } 386 387 static class DividerDecoration extends RecyclerView.ItemDecoration { 388 389 private ColorDrawable mTopDivider; 390 private ColorDrawable mBottomDivider; 391 private int mLeftOffset; 392 private int mRightOffset; 393 private int mTopOffset; 394 private int mBottomOffset; 395 396 DividerDecoration(int leftOffset, int topOffset, int rightOffset, int bottomOffset) { 397 mLeftOffset = leftOffset; 398 mTopOffset = topOffset; 399 mRightOffset = rightOffset; 400 mBottomOffset = bottomOffset; 401 } 402 403 @Override 404 public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { 405 if (mTopDivider == null) { 406 mTopDivider = new ColorDrawable(Color.RED); 407 } 408 if (mBottomDivider == null) { 409 mBottomDivider = new ColorDrawable(Color.BLUE); 410 } 411 final int childCount = parent.getChildCount(); 412 final int width = parent.getWidth(); 413 for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) { 414 final View view = parent.getChildAt(childViewIndex); 415 mTopDivider.setBounds(0, (int) view.getY() - mTopOffset, width, (int) view.getY()); 416 mTopDivider.draw(c); 417 mBottomDivider.setBounds(0, (int) view.getY() + view.getHeight(), width, 418 (int) view.getY() + view.getHeight() + mBottomOffset); 419 mBottomDivider.draw(c); 420 } 421 } 422 423 @Override 424 public void getItemOffsets(Rect outRect, View view, RecyclerView parent, 425 RecyclerView.State state) { 426 outRect.left = mLeftOffset; 427 outRect.top = mTopOffset; 428 outRect.right = mRightOffset; 429 outRect.bottom = mBottomOffset; 430 } 431 } 432 433 public void testItemDecorationAndMargins() throws Throwable { 434 435 final int leftMargin = 3; 436 final int topMargin = 4; 437 final int rightMargin = 7; 438 final int bottomMargin = 8; 439 final int itemHeight = 100; 440 441 mInstrumentation = getInstrumentation(); 442 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 443 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 444 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{itemHeight, itemHeight, itemHeight}); 445 intent.putExtra(GridActivity.EXTRA_LAYOUT_MARGINS, 446 new int[]{leftMargin, topMargin, rightMargin, bottomMargin}); 447 initActivity(intent); 448 mOrientation = BaseGridView.VERTICAL; 449 mNumRows = 1; 450 451 final int paddingLeft = mGridView.getPaddingLeft(); 452 final int paddingTop = mGridView.getPaddingTop(); 453 final int verticalSpace = mGridView.getVerticalMargin(); 454 final int decorationLeft = 17; 455 final int decorationTop = 1; 456 final int decorationRight = 19; 457 final int decorationBottom = 2; 458 459 runTestOnUiThread(new Runnable() { 460 public void run() { 461 mGridView.addItemDecoration(new DividerDecoration(decorationLeft, decorationTop, 462 decorationRight, decorationBottom)); 463 } 464 }); 465 waitForScrollIdle(); 466 467 View child0 = mGridView.getChildAt(0); 468 View child1 = mGridView.getChildAt(1); 469 View child2 = mGridView.getChildAt(2); 470 471 assertEquals(itemHeight, child0.getBottom() - child0.getTop()); 472 473 // verify left margins 474 assertEquals(paddingLeft + leftMargin + decorationLeft, child0.getLeft()); 475 assertEquals(paddingLeft + leftMargin + decorationLeft, child1.getLeft()); 476 assertEquals(paddingLeft + leftMargin + decorationLeft, child2.getLeft()); 477 // verify top bottom margins and decoration offset 478 assertEquals(paddingTop + topMargin + decorationTop, child0.getTop()); 479 assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin, 480 child1.getTop() - child0.getBottom()); 481 assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin, 482 child2.getTop() - child1.getBottom()); 483 484 } 485 486 public void testItemDecorationAndMarginsAndOpticalBounds() throws Throwable { 487 final int leftMargin = 3; 488 final int topMargin = 4; 489 final int rightMargin = 7; 490 final int bottomMargin = 8; 491 final int itemHeight = 100; 492 final int ninePatchDrawableResourceId = R.drawable.lb_card_shadow_focused; 493 494 mInstrumentation = getInstrumentation(); 495 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 496 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 497 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{itemHeight, itemHeight, itemHeight}); 498 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout); 499 intent.putExtra(GridActivity.EXTRA_LAYOUT_MARGINS, 500 new int[]{leftMargin, topMargin, rightMargin, bottomMargin}); 501 intent.putExtra(GridActivity.EXTRA_NINEPATCH_SHADOW, ninePatchDrawableResourceId); 502 initActivity(intent); 503 mOrientation = BaseGridView.VERTICAL; 504 mNumRows = 1; 505 506 final int paddingLeft = mGridView.getPaddingLeft(); 507 final int paddingTop = mGridView.getPaddingTop(); 508 final int verticalSpace = mGridView.getVerticalMargin(); 509 final int decorationLeft = 17; 510 final int decorationTop = 1; 511 final int decorationRight = 19; 512 final int decorationBottom = 2; 513 514 final Rect opticalPaddings = new Rect(); 515 mGridView.getContext().getDrawable(ninePatchDrawableResourceId).getPadding(opticalPaddings); 516 final int opticalInsetsLeft = opticalPaddings.left; 517 final int opticalInsetsTop = opticalPaddings.top; 518 final int opticalInsetsRight = opticalPaddings.right; 519 final int opticalInsetsBottom = opticalPaddings.bottom; 520 assertTrue(opticalInsetsLeft > 0); 521 assertTrue(opticalInsetsTop > 0); 522 assertTrue(opticalInsetsRight > 0); 523 assertTrue(opticalInsetsBottom > 0); 524 525 runTestOnUiThread(new Runnable() { 526 public void run() { 527 mGridView.addItemDecoration(new DividerDecoration(decorationLeft, decorationTop, 528 decorationRight, decorationBottom)); 529 } 530 }); 531 waitForScrollIdle(); 532 533 View child0 = mGridView.getChildAt(0); 534 View child1 = mGridView.getChildAt(1); 535 View child2 = mGridView.getChildAt(2); 536 537 assertEquals(itemHeight + opticalInsetsTop + opticalInsetsBottom, 538 child0.getBottom() - child0.getTop()); 539 540 // verify left margins decoration and optical insets 541 assertEquals(paddingLeft + leftMargin + decorationLeft - opticalInsetsLeft, 542 child0.getLeft()); 543 assertEquals(paddingLeft + leftMargin + decorationLeft - opticalInsetsLeft, 544 child1.getLeft()); 545 assertEquals(paddingLeft + leftMargin + decorationLeft - opticalInsetsLeft, 546 child2.getLeft()); 547 // verify top bottom margins decoration offset and optical insets 548 assertEquals(paddingTop + topMargin + decorationTop, child0.getTop() + opticalInsetsTop); 549 assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin, 550 (child1.getTop() + opticalInsetsTop) - (child0.getBottom() - opticalInsetsBottom)); 551 assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin, 552 (child2.getTop() + opticalInsetsTop) - (child1.getBottom() - opticalInsetsBottom)); 553 554 } 555 556 public void testThreeColumnVerticalBasic() throws Throwable { 557 558 mInstrumentation = getInstrumentation(); 559 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 560 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid); 561 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 562 initActivity(intent); 563 mOrientation = BaseGridView.VERTICAL; 564 mNumRows = 3; 565 566 scrollToEnd(mVerifyLayout); 567 verifyBoundCount(200); 568 569 scrollToBegin(mVerifyLayout); 570 571 verifyBeginAligned(); 572 } 573 574 public void testRedundantAppendRemove() throws Throwable { 575 mInstrumentation = getInstrumentation(); 576 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 577 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 578 R.layout.vertical_grid_testredundantappendremove); 579 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{ 580 149,177,128,234,227,187,163,223,146,210,228,148,227,193,182,197,177,142,225,207, 581 157,171,209,204,187,184,123,221,197,153,202,179,193,214,226,173,225,143,188,159, 582 139,193,233,143,227,203,222,124,228,223,164,131,228,126,211,160,165,152,235,184, 583 155,224,149,181,171,229,200,234,177,130,164,172,188,139,132,203,179,220,147,131, 584 226,127,230,239,183,203,206,227,123,170,239,234,200,149,237,204,160,133,202,234, 585 173,122,139,149,151,153,216,231,121,145,227,153,186,174,223,180,123,215,206,216, 586 239,222,219,207,193,218,140,133,171,153,183,132,233,138,159,174,189,171,143,128, 587 152,222,141,202,224,190,134,120,181,231,230,136,132,224,136,210,207,150,128,183, 588 221,194,179,220,126,221,137,205,223,193,172,132,226,209,133,191,227,127,159,171, 589 180,149,237,177,194,207,170,202,161,144,147,199,205,186,164,140,193,203,224,129}); 590 initActivity(intent); 591 mOrientation = BaseGridView.VERTICAL; 592 mNumRows = 3; 593 594 scrollToEnd(mVerifyLayout); 595 596 verifyBoundCount(200); 597 598 scrollToBegin(mVerifyLayout); 599 600 verifyBeginAligned(); 601 } 602 603 public void testRedundantAppendRemove2() throws Throwable { 604 mInstrumentation = getInstrumentation(); 605 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 606 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 607 R.layout.horizontal_grid_testredundantappendremove2); 608 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{ 609 318,333,199,224,246,273,269,289,340,313,265,306,349,269,185,282,257,354,316,252, 610 237,290,283,343,196,313,290,343,191,262,342,228,343,349,251,203,226,305,265,213, 611 216,333,295,188,187,281,288,311,244,232,224,332,290,181,267,276,226,261,335,355, 612 225,217,219,183,234,285,257,304,182,250,244,223,257,219,342,185,347,205,302,315, 613 299,309,292,237,192,309,228,250,347,227,337,298,299,185,185,331,223,284,265,351}); 614 initActivity(intent); 615 mOrientation = BaseGridView.HORIZONTAL; 616 mNumRows = 3; 617 mLayoutManager = (GridLayoutManager) mGridView.getLayoutManager(); 618 619 // test append without staggered result cache 620 scrollToEnd(mVerifyLayout); 621 622 verifyBoundCount(100); 623 int[] endEdges = getEndEdges(); 624 625 scrollToBegin(mVerifyLayout); 626 627 verifyBeginAligned(); 628 629 // now test append with staggered result cache 630 changeArraySize(3); 631 assertEquals("Staggerd cache should be kept as is when no item size change", 632 100, ((StaggeredGrid) mLayoutManager.mGrid).mLocations.size()); 633 634 mActivity.resetBoundCount(); 635 changeArraySize(100); 636 637 scrollToEnd(mVerifyLayout); 638 verifyBoundCount(100); 639 640 // we should get same aligned end edges 641 int[] endEdges2 = getEndEdges(); 642 verifyEdgesSame(endEdges, endEdges2); 643 } 644 645 public void testItemMovedHorizontal() throws Throwable { 646 647 mInstrumentation = getInstrumentation(); 648 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 649 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 650 R.layout.horizontal_grid); 651 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 652 initActivity(intent); 653 mOrientation = BaseGridView.HORIZONTAL; 654 mNumRows = 3; 655 656 mGridView.setSelectedPositionSmooth(150); 657 waitForScrollIdle(mVerifyLayout); 658 mActivity.swap(150, 152); 659 waitForTransientStateGone(null); 660 661 runTestOnUiThread(mVerifyLayout); 662 663 scrollToBegin(mVerifyLayout); 664 665 verifyBeginAligned(); 666 } 667 668 public void testItemMovedVertical() throws Throwable { 669 670 mInstrumentation = getInstrumentation(); 671 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 672 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 673 R.layout.vertical_grid); 674 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 675 initActivity(intent); 676 mOrientation = BaseGridView.VERTICAL; 677 mNumRows = 3; 678 679 mGridView.setSelectedPositionSmooth(150); 680 waitForScrollIdle(mVerifyLayout); 681 mActivity.swap(150, 152); 682 waitForTransientStateGone(null); 683 684 runTestOnUiThread(mVerifyLayout); 685 686 scrollToEnd(mVerifyLayout); 687 scrollToBegin(mVerifyLayout); 688 689 verifyBeginAligned(); 690 } 691 692 public void testItemAddRemoveHorizontal() throws Throwable { 693 694 mInstrumentation = getInstrumentation(); 695 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 696 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 697 R.layout.horizontal_grid); 698 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 699 initActivity(intent); 700 mOrientation = BaseGridView.HORIZONTAL; 701 mNumRows = 3; 702 703 scrollToEnd(mVerifyLayout); 704 int[] endEdges = getEndEdges(); 705 706 mGridView.setSelectedPositionSmooth(150); 707 waitForScrollIdle(mVerifyLayout); 708 int[] removedItems = mActivity.removeItems(151, 4); 709 waitForTransientStateGone(null); 710 711 scrollToEnd(mVerifyLayout); 712 mGridView.setSelectedPositionSmooth(150); 713 waitForScrollIdle(mVerifyLayout); 714 715 mActivity.addItems(151, removedItems); 716 waitForTransientStateGone(null); 717 scrollToEnd(mVerifyLayout); 718 719 // we should get same aligned end edges 720 int[] endEdges2 = getEndEdges(); 721 verifyEdgesSame(endEdges, endEdges2); 722 723 scrollToBegin(mVerifyLayout); 724 verifyBeginAligned(); 725 } 726 727 public void testSetSelectedPositionDetached() throws Throwable { 728 729 mInstrumentation = getInstrumentation(); 730 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 731 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 732 R.layout.horizontal_linear); 733 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50); 734 initActivity(intent); 735 mOrientation = BaseGridView.HORIZONTAL; 736 mNumRows = 1; 737 738 final int focusToIndex = 49; 739 final ViewGroup parent = (ViewGroup) mGridView.getParent(); 740 runTestOnUiThread(new Runnable() { 741 public void run() { 742 parent.removeView(mGridView); 743 } 744 }); 745 runTestOnUiThread(new Runnable() { 746 public void run() { 747 mGridView.setSelectedPositionSmooth(focusToIndex); 748 } 749 }); 750 runTestOnUiThread(new Runnable() { 751 public void run() { 752 parent.addView(mGridView); 753 mGridView.requestFocus(); 754 } 755 }); 756 waitForTransientStateGone(null); 757 waitForScrollIdle(); 758 assertEquals(mGridView.getSelectedPosition(), focusToIndex); 759 assertTrue(mGridView.getLayoutManager().findViewByPosition(focusToIndex).hasFocus()); 760 761 final int focusToIndex2 = 0; 762 runTestOnUiThread(new Runnable() { 763 public void run() { 764 parent.removeView(mGridView); 765 } 766 }); 767 runTestOnUiThread(new Runnable() { 768 public void run() { 769 mGridView.setSelectedPosition(focusToIndex2); 770 } 771 }); 772 runTestOnUiThread(new Runnable() { 773 public void run() { 774 parent.addView(mGridView); 775 mGridView.requestFocus(); 776 } 777 }); 778 assertEquals(mGridView.getSelectedPosition(), focusToIndex2); 779 waitForTransientStateGone(null); 780 waitForScrollIdle(); 781 assertTrue(mGridView.getLayoutManager().findViewByPosition(focusToIndex2).hasFocus()); 782 } 783 784 public void testBug22209986() throws Throwable { 785 786 mInstrumentation = getInstrumentation(); 787 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 788 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 789 R.layout.horizontal_linear); 790 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50); 791 initActivity(intent); 792 mOrientation = BaseGridView.HORIZONTAL; 793 mNumRows = 1; 794 795 final int focusToIndex = mGridView.getChildCount() - 1; 796 runTestOnUiThread(new Runnable() { 797 public void run() { 798 mGridView.setSelectedPositionSmooth(focusToIndex); 799 } 800 }); 801 802 waitForTransientStateGone(null); 803 waitForScrollIdle(); 804 runTestOnUiThread(new Runnable() { 805 public void run() { 806 mGridView.setSelectedPositionSmooth(focusToIndex + 1); 807 } 808 }); 809 // let the scroll running for a while and requestLayout during scroll 810 Thread.sleep(80); 811 runTestOnUiThread(new Runnable() { 812 public void run() { 813 assertEquals(mGridView.getScrollState(), BaseGridView.SCROLL_STATE_SETTLING); 814 mGridView.requestLayout(); 815 } 816 }); 817 waitForTransientStateGone(null); 818 waitForScrollIdle(); 819 820 int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft(); 821 822 runTestOnUiThread(new Runnable() { 823 public void run() { 824 mGridView.requestLayout(); 825 } 826 }); 827 waitForTransientStateGone(null); 828 waitForScrollIdle(); 829 assertEquals(leftEdge, 830 mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft()); 831 } 832 833 public void testScrollAndRemove() throws Throwable { 834 835 mInstrumentation = getInstrumentation(); 836 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 837 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 838 R.layout.horizontal_linear); 839 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50); 840 initActivity(intent); 841 mOrientation = BaseGridView.HORIZONTAL; 842 mNumRows = 1; 843 844 final int focusToIndex = mGridView.getChildCount() - 1; 845 runTestOnUiThread(new Runnable() { 846 public void run() { 847 mGridView.setSelectedPositionSmooth(focusToIndex); 848 } 849 }); 850 851 runTestOnUiThread(new Runnable() { 852 public void run() { 853 mActivity.removeItems(focusToIndex, 1); 854 } 855 }); 856 857 waitForTransientStateGone(null); 858 waitForScrollIdle(); 859 int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft(); 860 861 runTestOnUiThread(new Runnable() { 862 public void run() { 863 mGridView.requestLayout(); 864 } 865 }); 866 waitForTransientStateGone(null); 867 waitForScrollIdle(); 868 assertEquals(leftEdge, 869 mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft()); 870 } 871 872 public void testScrollAndInsert() throws Throwable { 873 874 mInstrumentation = getInstrumentation(); 875 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 876 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 877 R.layout.vertical_grid); 878 int[] items = new int[1000]; 879 for (int i = 0; i < items.length; i++) { 880 items[i] = 300 + (int)(Math.random() * 100); 881 } 882 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 883 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 884 mOrientation = BaseGridView.VERTICAL; 885 mNumRows = 3; 886 887 initActivity(intent); 888 889 runTestOnUiThread(new Runnable() { 890 public void run() { 891 mGridView.setSelectedPositionSmooth(150); 892 } 893 }); 894 waitForScrollIdle(mVerifyLayout); 895 896 View view = mGridView.getChildAt(mGridView.getChildCount() - 1); 897 final int focusToIndex = mGridView.getChildAdapterPosition(view); 898 runTestOnUiThread(new Runnable() { 899 public void run() { 900 mGridView.setSelectedPositionSmooth(focusToIndex); 901 } 902 }); 903 904 runTestOnUiThread(new Runnable() { 905 public void run() { 906 int[] newItems = new int[]{300, 300, 300}; 907 mActivity.addItems(0, newItems); 908 } 909 }); 910 911 waitForTransientStateGone(null); 912 waitForScrollIdle(); 913 } 914 915 public void testScrollAndInsertBeforeVisibleItem() throws Throwable { 916 917 mInstrumentation = getInstrumentation(); 918 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 919 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 920 R.layout.vertical_grid); 921 int[] items = new int[1000]; 922 for (int i = 0; i < items.length; i++) { 923 items[i] = 300 + (int)(Math.random() * 100); 924 } 925 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 926 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 927 mOrientation = BaseGridView.VERTICAL; 928 mNumRows = 3; 929 930 initActivity(intent); 931 932 runTestOnUiThread(new Runnable() { 933 public void run() { 934 mGridView.setSelectedPositionSmooth(150); 935 } 936 }); 937 waitForScrollIdle(mVerifyLayout); 938 939 View view = mGridView.getChildAt(mGridView.getChildCount() - 1); 940 final int focusToIndex = mGridView.getChildAdapterPosition(view); 941 runTestOnUiThread(new Runnable() { 942 public void run() { 943 mGridView.setSelectedPositionSmooth(focusToIndex); 944 } 945 }); 946 947 runTestOnUiThread(new Runnable() { 948 public void run() { 949 int[] newItems = new int[]{300, 300, 300}; 950 mActivity.addItems(focusToIndex, newItems); 951 } 952 }); 953 954 waitForTransientStateGone(null); 955 waitForScrollIdle(); 956 } 957 958 public void testSmoothScrollAndRemove() throws Throwable { 959 960 mInstrumentation = getInstrumentation(); 961 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 962 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 963 R.layout.horizontal_linear); 964 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50); 965 initActivity(intent); 966 mOrientation = BaseGridView.HORIZONTAL; 967 mNumRows = 1; 968 969 final int focusToIndex = 40; 970 runTestOnUiThread(new Runnable() { 971 public void run() { 972 mGridView.setSelectedPositionSmooth(focusToIndex); 973 } 974 }); 975 976 runTestOnUiThread(new Runnable() { 977 public void run() { 978 mActivity.removeItems(focusToIndex, 1); 979 } 980 }); 981 982 Thread.sleep(20); // wait for layout 983 assertTrue("removing the index of not attached child should not affect smooth scroller", 984 mGridView.getLayoutManager().isSmoothScrolling()); 985 waitForTransientStateGone(null); 986 waitForScrollIdle(); 987 int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft(); 988 989 runTestOnUiThread(new Runnable() { 990 public void run() { 991 mGridView.requestLayout(); 992 } 993 }); 994 waitForTransientStateGone(null); 995 waitForScrollIdle(); 996 assertEquals(leftEdge, 997 mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft()); 998 } 999 1000 public void testSmoothScrollAndRemove2() throws Throwable { 1001 1002 mInstrumentation = getInstrumentation(); 1003 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1004 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1005 R.layout.horizontal_linear); 1006 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50); 1007 initActivity(intent); 1008 mOrientation = BaseGridView.HORIZONTAL; 1009 mNumRows = 1; 1010 1011 final int focusToIndex = 40; 1012 runTestOnUiThread(new Runnable() { 1013 public void run() { 1014 mGridView.setSelectedPositionSmooth(focusToIndex); 1015 } 1016 }); 1017 1018 final int removeIndex = mGridView.getChildCount() - 1; 1019 runTestOnUiThread(new Runnable() { 1020 public void run() { 1021 mActivity.removeItems(removeIndex, 1); 1022 } 1023 }); 1024 1025 Thread.sleep(20); // wait for layout 1026 assertFalse("removing the index of attached child should kill smooth scroller", 1027 mGridView.getLayoutManager().isSmoothScrolling()); 1028 waitForTransientStateGone(null); 1029 waitForScrollIdle(); 1030 int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft(); 1031 1032 runTestOnUiThread(new Runnable() { 1033 public void run() { 1034 mGridView.requestLayout(); 1035 } 1036 }); 1037 waitForTransientStateGone(null); 1038 waitForScrollIdle(); 1039 assertEquals(leftEdge, 1040 mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft()); 1041 } 1042 1043 public void testPendingSmoothScrollAndRemove() throws Throwable { 1044 mInstrumentation = getInstrumentation(); 1045 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1046 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1047 R.layout.vertical_linear); 1048 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 1049 int[] items = new int[100]; 1050 for (int i = 0; i < items.length; i++) { 1051 items[i] = 630 + (int)(Math.random() * 100); 1052 } 1053 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1054 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 1055 mOrientation = BaseGridView.VERTICAL; 1056 mNumRows = 1; 1057 1058 initActivity(intent); 1059 1060 mGridView.setSelectedPositionSmooth(0); 1061 waitForScrollIdle(mVerifyLayout); 1062 assertTrue(mGridView.getChildAt(0).hasFocus()); 1063 1064 // Pressing lots of key to make sure smooth scroller is running 1065 for (int i = 0; i < 20; i++) { 1066 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 1067 } 1068 Thread.sleep(100); 1069 1070 assertTrue(mGridView.getLayoutManager().isSmoothScrolling()); 1071 final int removeIndex = mGridView.getChildCount() - 1; 1072 runTestOnUiThread(new Runnable() { 1073 public void run() { 1074 mActivity.removeItems(removeIndex, 1); 1075 } 1076 }); 1077 1078 Thread.sleep(20); // wait for layout 1079 assertFalse("removing the index of attached child should kill smooth scroller", 1080 mGridView.getLayoutManager().isSmoothScrolling()); 1081 1082 waitForTransientStateGone(null); 1083 waitForScrollIdle(); 1084 int focusIndex = mGridView.getSelectedPosition(); 1085 int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusIndex).getLeft(); 1086 1087 runTestOnUiThread(new Runnable() { 1088 public void run() { 1089 mGridView.requestLayout(); 1090 } 1091 }); 1092 waitForTransientStateGone(null); 1093 waitForScrollIdle(); 1094 assertEquals(leftEdge, 1095 mGridView.getLayoutManager().findViewByPosition(focusIndex).getLeft()); 1096 } 1097 1098 public void testFocusToFirstItem() throws Throwable { 1099 1100 mInstrumentation = getInstrumentation(); 1101 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1102 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1103 R.layout.horizontal_grid); 1104 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 1105 initActivity(intent); 1106 mOrientation = BaseGridView.HORIZONTAL; 1107 mNumRows = 3; 1108 1109 int[] removedItems = mActivity.removeItems(0, 200); 1110 1111 waitForTransientStateGone(null); 1112 humanDelay(500); 1113 mActivity.addItems(0, removedItems); 1114 1115 waitForTransientStateGone(null); 1116 humanDelay(500); 1117 assertTrue(mGridView.getLayoutManager().findViewByPosition(0).hasFocus()); 1118 1119 changeArraySize(0); 1120 1121 changeArraySize(200); 1122 assertTrue(mGridView.getLayoutManager().findViewByPosition(0).hasFocus()); 1123 } 1124 1125 public void testNonFocusableHorizontal() throws Throwable { 1126 final int numItems = 200; 1127 final int startPos = 45; 1128 final int skips = 20; 1129 final int numColumns = 3; 1130 final int endPos = startPos + numColumns * (skips + 1); 1131 1132 mInstrumentation = getInstrumentation(); 1133 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1134 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1135 R.layout.horizontal_grid); 1136 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 1137 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1138 mOrientation = BaseGridView.HORIZONTAL; 1139 mNumRows = numColumns; 1140 boolean[] focusable = new boolean[numItems]; 1141 for (int i = 0; i < focusable.length; i++) { 1142 focusable[i] = true; 1143 } 1144 for (int i = startPos + mNumRows, j = 0; j < skips; i += mNumRows, j++) { 1145 focusable[i] = false; 1146 } 1147 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 1148 initActivity(intent); 1149 1150 mGridView.setSelectedPositionSmooth(startPos); 1151 waitForScrollIdle(mVerifyLayout); 1152 1153 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 1154 sendKeys(KeyEvent.KEYCODE_DPAD_LEFT); 1155 } else { 1156 sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT); 1157 } 1158 waitForScrollIdle(mVerifyLayout); 1159 assertEquals(endPos, mGridView.getSelectedPosition()); 1160 1161 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 1162 sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT); 1163 } else { 1164 sendKeys(KeyEvent.KEYCODE_DPAD_LEFT); 1165 } 1166 waitForScrollIdle(mVerifyLayout); 1167 assertEquals(startPos, mGridView.getSelectedPosition()); 1168 1169 } 1170 1171 public void testNoInitialFocusable() throws Throwable { 1172 1173 mInstrumentation = getInstrumentation(); 1174 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1175 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1176 R.layout.horizontal_linear); 1177 final int numItems = 100; 1178 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 1179 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1180 mOrientation = BaseGridView.HORIZONTAL; 1181 mNumRows = 1; 1182 boolean[] focusable = new boolean[numItems]; 1183 final int firstFocusableIndex = 10; 1184 for (int i = 0; i < firstFocusableIndex; i++) { 1185 focusable[i] = false; 1186 } 1187 for (int i = firstFocusableIndex; i < focusable.length; i++) { 1188 focusable[i] = true; 1189 } 1190 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 1191 initActivity(intent); 1192 assertTrue(mGridView.isFocused()); 1193 1194 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 1195 sendKeys(KeyEvent.KEYCODE_DPAD_LEFT); 1196 } else { 1197 sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT); 1198 } 1199 waitForScrollIdle(mVerifyLayout); 1200 assertEquals(firstFocusableIndex, mGridView.getSelectedPosition()); 1201 assertTrue(mGridView.getLayoutManager().findViewByPosition(firstFocusableIndex).hasFocus()); 1202 } 1203 1204 public void testFocusOutOfEmptyListView() throws Throwable { 1205 1206 mInstrumentation = getInstrumentation(); 1207 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1208 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1209 R.layout.horizontal_linear); 1210 final int numItems = 100; 1211 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 1212 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1213 mOrientation = BaseGridView.HORIZONTAL; 1214 mNumRows = 1; 1215 initActivity(intent); 1216 1217 final View horizontalGridView = new HorizontalGridViewEx(mGridView.getContext()); 1218 runTestOnUiThread(new Runnable() { 1219 @Override 1220 public void run() { 1221 horizontalGridView.setFocusable(true); 1222 horizontalGridView.setFocusableInTouchMode(true); 1223 horizontalGridView.setLayoutParams(new ViewGroup.LayoutParams(100, 100)); 1224 ((ViewGroup) mGridView.getParent()).addView(horizontalGridView, 0); 1225 horizontalGridView.requestFocus(); 1226 } 1227 }); 1228 1229 assertTrue(horizontalGridView.isFocused()); 1230 1231 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 1232 1233 assertTrue(mGridView.hasFocus()); 1234 } 1235 1236 public void testTransferFocusToChildWhenGainFocus() throws Throwable { 1237 1238 mInstrumentation = getInstrumentation(); 1239 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1240 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1241 R.layout.horizontal_linear); 1242 final int numItems = 100; 1243 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 1244 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1245 mOrientation = BaseGridView.HORIZONTAL; 1246 mNumRows = 1; 1247 boolean[] focusable = new boolean[numItems]; 1248 final int firstFocusableIndex = 1; 1249 for (int i = 0; i < firstFocusableIndex; i++) { 1250 focusable[i] = false; 1251 } 1252 for (int i = firstFocusableIndex; i < focusable.length; i++) { 1253 focusable[i] = true; 1254 } 1255 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 1256 initActivity(intent); 1257 1258 assertEquals(firstFocusableIndex, mGridView.getSelectedPosition()); 1259 assertTrue(mGridView.getLayoutManager().findViewByPosition(firstFocusableIndex).hasFocus()); 1260 } 1261 1262 public void testFocusFromSecondChild() throws Throwable { 1263 1264 mInstrumentation = getInstrumentation(); 1265 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1266 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1267 R.layout.horizontal_linear); 1268 final int numItems = 100; 1269 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 1270 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1271 mOrientation = BaseGridView.HORIZONTAL; 1272 mNumRows = 1; 1273 boolean[] focusable = new boolean[numItems]; 1274 for (int i = 0; i < focusable.length; i++) { 1275 focusable[i] = false; 1276 } 1277 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 1278 initActivity(intent); 1279 1280 // switching Adapter to cause a full rebind, test if it will focus to second item. 1281 runTestOnUiThread(new Runnable() { 1282 @Override 1283 public void run() { 1284 mActivity.mNumItems = numItems; 1285 mActivity.mItemFocusables[1] = true; 1286 mActivity.rebindToNewAdapter(); 1287 } 1288 }); 1289 } 1290 1291 public void testNonFocusableVertical() throws Throwable { 1292 final int numItems = 200; 1293 final int startPos = 44; 1294 final int skips = 20; 1295 final int numColumns = 3; 1296 final int endPos = startPos + numColumns * (skips + 1); 1297 1298 mInstrumentation = getInstrumentation(); 1299 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1300 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1301 R.layout.vertical_grid); 1302 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 1303 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1304 mOrientation = BaseGridView.VERTICAL; 1305 mNumRows = numColumns; 1306 boolean[] focusable = new boolean[numItems]; 1307 for (int i = 0; i < focusable.length; i++) { 1308 focusable[i] = true; 1309 } 1310 for (int i = startPos + mNumRows, j = 0; j < skips; i += mNumRows, j++) { 1311 focusable[i] = false; 1312 } 1313 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 1314 initActivity(intent); 1315 1316 mGridView.setSelectedPositionSmooth(startPos); 1317 waitForScrollIdle(mVerifyLayout); 1318 1319 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 1320 waitForScrollIdle(mVerifyLayout); 1321 assertEquals(endPos, mGridView.getSelectedPosition()); 1322 1323 sendKeys(KeyEvent.KEYCODE_DPAD_UP); 1324 waitForScrollIdle(mVerifyLayout); 1325 assertEquals(startPos, mGridView.getSelectedPosition()); 1326 1327 } 1328 1329 public void testLtrFocusOutStartDisabled() throws Throwable { 1330 final int numItems = 200; 1331 1332 mInstrumentation = getInstrumentation(); 1333 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1334 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid_ltr); 1335 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 1336 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1337 mOrientation = BaseGridView.VERTICAL; 1338 mNumRows = 1; 1339 initActivity(intent); 1340 1341 runTestOnUiThread(new Runnable() { 1342 @Override 1343 public void run() { 1344 mGridView.requestFocus(); 1345 mGridView.setSelectedPositionSmooth(0); 1346 } 1347 }); 1348 waitForScrollIdle(mVerifyLayout); 1349 1350 sendKeys(KeyEvent.KEYCODE_DPAD_LEFT); 1351 waitForScrollIdle(mVerifyLayout); 1352 assertTrue(mGridView.hasFocus()); 1353 } 1354 1355 public void testRtlFocusOutStartDisabled() throws Throwable { 1356 final int numItems = 200; 1357 1358 mInstrumentation = getInstrumentation(); 1359 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1360 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid_rtl); 1361 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 1362 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1363 mOrientation = BaseGridView.VERTICAL; 1364 mNumRows = 1; 1365 initActivity(intent); 1366 1367 runTestOnUiThread(new Runnable() { 1368 @Override 1369 public void run() { 1370 mGridView.requestFocus(); 1371 mGridView.setSelectedPositionSmooth(0); 1372 } 1373 }); 1374 waitForScrollIdle(mVerifyLayout); 1375 1376 sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT); 1377 waitForScrollIdle(mVerifyLayout); 1378 assertTrue(mGridView.hasFocus()); 1379 } 1380 1381 public void testTransferFocusable() throws Throwable { 1382 final int numItems = 200; 1383 final int numColumns = 3; 1384 final int startPos = 1; 1385 1386 mInstrumentation = getInstrumentation(); 1387 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1388 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1389 R.layout.horizontal_grid); 1390 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 1391 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1392 mOrientation = BaseGridView.HORIZONTAL; 1393 mNumRows = numColumns; 1394 boolean[] focusable = new boolean[numItems]; 1395 for (int i = 0; i < focusable.length; i++) { 1396 focusable[i] = true; 1397 } 1398 for (int i = 0; i < startPos; i++) { 1399 focusable[i] = false; 1400 } 1401 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 1402 initActivity(intent); 1403 1404 changeArraySize(0); 1405 assertTrue(mGridView.isFocused()); 1406 1407 changeArraySize(numItems); 1408 assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus()); 1409 } 1410 1411 public void testTransferFocusable2() throws Throwable { 1412 final int numItems = 200; 1413 final int numColumns = 3; 1414 final int startPos = 10; 1415 1416 mInstrumentation = getInstrumentation(); 1417 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1418 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1419 R.layout.horizontal_grid); 1420 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 1421 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 1422 mOrientation = BaseGridView.HORIZONTAL; 1423 mNumRows = numColumns; 1424 boolean[] focusable = new boolean[numItems]; 1425 for (int i = 0; i < focusable.length; i++) { 1426 focusable[i] = true; 1427 } 1428 for (int i = 0; i < startPos; i++) { 1429 focusable[i] = false; 1430 } 1431 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 1432 initActivity(intent); 1433 1434 changeArraySize(0); 1435 assertTrue(mGridView.isFocused()); 1436 1437 changeArraySize(numItems); 1438 assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus()); 1439 } 1440 1441 public void testNonFocusableLoseInFastLayout() throws Throwable { 1442 mInstrumentation = getInstrumentation(); 1443 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1444 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1445 R.layout.vertical_linear); 1446 int[] items = new int[300]; 1447 for (int i = 0; i < items.length; i++) { 1448 items[i] = 480; 1449 } 1450 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1451 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1452 intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true); 1453 mOrientation = BaseGridView.VERTICAL; 1454 mNumRows = 1; 1455 int pressDown = 15; 1456 1457 initActivity(intent); 1458 1459 mGridView.setSelectedPositionSmooth(0); 1460 waitForScrollIdleAndItemAnimation(mVerifyLayout); 1461 1462 for (int i = 0; i < pressDown; i++) { 1463 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 1464 } 1465 waitForScrollIdleAndItemAnimation(mVerifyLayout); 1466 assertFalse(mGridView.isFocused()); 1467 1468 } 1469 1470 public void testFocusableViewAvailable() throws Throwable { 1471 mInstrumentation = getInstrumentation(); 1472 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1473 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1474 R.layout.vertical_linear); 1475 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0); 1476 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1477 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, 1478 new boolean[]{false, false, true, false, false}); 1479 mOrientation = BaseGridView.VERTICAL; 1480 mNumRows = 1; 1481 1482 initActivity(intent); 1483 1484 runTestOnUiThread(new Runnable() { 1485 @Override 1486 public void run() { 1487 // RecyclerView does not respect focusable and focusableInTouchMode flag, so 1488 // set flags in code. 1489 mGridView.setFocusableInTouchMode(false); 1490 mGridView.setFocusable(false); 1491 } 1492 }); 1493 1494 assertFalse(mGridView.isFocused()); 1495 1496 final boolean[] scrolled = new boolean[]{false}; 1497 mGridView.addOnScrollListener(new RecyclerView.OnScrollListener() { 1498 public void onScrolled(RecyclerView recyclerView, int dx, int dy){ 1499 if (dy > 0) { 1500 scrolled[0] = true; 1501 } 1502 } 1503 }); 1504 mActivity.addItems(0, new int[]{200, 300, 500, 500, 200}); 1505 waitForScrollIdleAndItemAnimation(mVerifyLayout); 1506 1507 assertFalse("GridView should not be scrolled", scrolled[0]); 1508 assertTrue(mGridView.getChildAt(1).hasFocus()); 1509 1510 } 1511 1512 public void testSetSelectionWithDelta() throws Throwable { 1513 mInstrumentation = getInstrumentation(); 1514 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1515 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1516 R.layout.vertical_linear); 1517 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 300); 1518 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1519 mOrientation = BaseGridView.VERTICAL; 1520 mNumRows = 1; 1521 1522 initActivity(intent); 1523 1524 runTestOnUiThread(new Runnable() { 1525 public void run() { 1526 mGridView.setSelectedPositionSmooth(3); 1527 } 1528 }); 1529 waitForScrollIdle(mVerifyLayout); 1530 int top1 = mGridView.getLayoutManager().findViewByPosition(3).getTop(); 1531 1532 humanDelay(1000); 1533 1534 // scroll to position with delta 1535 setSelectedPosition(3, 100); 1536 int top2 = mGridView.getLayoutManager().findViewByPosition(3).getTop(); 1537 assertEquals(top1 - 100, top2); 1538 1539 // scroll to same position without delta, it will be reset 1540 setSelectedPosition(3, 0); 1541 int top3 = mGridView.getLayoutManager().findViewByPosition(3).getTop(); 1542 assertEquals(top1, top3); 1543 1544 // scroll invisible item after last visible item 1545 final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 1546 .mGrid.getLastVisibleIndex(); 1547 setSelectedPosition(lastVisiblePos + 1, 100); 1548 int top4 = mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1).getTop(); 1549 assertEquals(top1 - 100, top4); 1550 1551 // scroll invisible item before first visible item 1552 final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 1553 .mGrid.getFirstVisibleIndex(); 1554 setSelectedPosition(firstVisiblePos - 1, 100); 1555 int top5 = mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1).getTop(); 1556 assertEquals(top1 - 100, top5); 1557 1558 // scroll to invisible item that is far away. 1559 setSelectedPosition(50, 100); 1560 int top6 = mGridView.getLayoutManager().findViewByPosition(50).getTop(); 1561 assertEquals(top1 - 100, top6); 1562 1563 // scroll to invisible item that is far away. 1564 runTestOnUiThread(new Runnable() { 1565 public void run() { 1566 mGridView.setSelectedPositionSmooth(100); 1567 } 1568 }); 1569 waitForScrollIdle(mVerifyLayout); 1570 int top7 = mGridView.getLayoutManager().findViewByPosition(100).getTop(); 1571 assertEquals(top1, top7); 1572 1573 // scroll to invisible item that is far away. 1574 setSelectedPosition(10, 50); 1575 int top8 = mGridView.getLayoutManager().findViewByPosition(10).getTop(); 1576 assertEquals(top1 - 50, top8); 1577 } 1578 1579 public void testSetSelectionWithDeltaInGrid() throws Throwable { 1580 mInstrumentation = getInstrumentation(); 1581 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1582 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1583 R.layout.vertical_grid); 1584 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500); 1585 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 1586 mOrientation = BaseGridView.VERTICAL; 1587 mNumRows = 3; 1588 1589 initActivity(intent); 1590 1591 runTestOnUiThread(new Runnable() { 1592 public void run() { 1593 mGridView.setSelectedPositionSmooth(10); 1594 } 1595 }); 1596 waitForScrollIdle(mVerifyLayout); 1597 int top1 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10)); 1598 1599 humanDelay(500); 1600 1601 // scroll to position with delta 1602 setSelectedPosition(20, 100); 1603 int top2 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20)); 1604 assertEquals(top1 - 100, top2); 1605 1606 // scroll to same position without delta, it will be reset 1607 setSelectedPosition(20, 0); 1608 int top3 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20)); 1609 assertEquals(top1, top3); 1610 1611 // scroll invisible item after last visible item 1612 final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 1613 .mGrid.getLastVisibleIndex(); 1614 setSelectedPosition(lastVisiblePos + 1, 100); 1615 int top4 = getCenterY(mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1)); 1616 verifyMargin(); 1617 assertEquals(top1 - 100, top4); 1618 1619 // scroll invisible item before first visible item 1620 final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 1621 .mGrid.getFirstVisibleIndex(); 1622 setSelectedPosition(firstVisiblePos - 1, 100); 1623 int top5 = getCenterY(mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1)); 1624 assertEquals(top1 - 100, top5); 1625 1626 // scroll to invisible item that is far away. 1627 setSelectedPosition(100, 100); 1628 int top6 = getCenterY(mGridView.getLayoutManager().findViewByPosition(100)); 1629 assertEquals(top1 - 100, top6); 1630 1631 // scroll to invisible item that is far away. 1632 runTestOnUiThread(new Runnable() { 1633 public void run() { 1634 mGridView.setSelectedPositionSmooth(200); 1635 } 1636 }); 1637 waitForScrollIdle(mVerifyLayout); 1638 Thread.sleep(500); 1639 int top7 = getCenterY(mGridView.getLayoutManager().findViewByPosition(200)); 1640 assertEquals(top1, top7); 1641 1642 // scroll to invisible item that is far away. 1643 setSelectedPosition(10, 50); 1644 int top8 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10)); 1645 assertEquals(top1 - 50, top8); 1646 } 1647 1648 1649 public void testSetSelectionWithDeltaInGrid1() throws Throwable { 1650 mInstrumentation = getInstrumentation(); 1651 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1652 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1653 R.layout.vertical_grid); 1654 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{ 1655 193,176,153,141,203,184,232,139,177,206,222,136,132,237,172,137, 1656 188,172,163,213,158,219,209,147,133,229,170,197,138,215,188,205, 1657 223,192,225,170,195,127,229,229,210,195,134,142,160,139,130,222, 1658 150,163,180,176,157,137,234,169,159,167,182,150,224,231,202,236, 1659 123,140,181,223,120,185,183,221,123,210,134,158,166,208,149,128, 1660 192,214,212,198,133,140,158,133,229,173,226,141,180,128,127,218, 1661 192,235,183,213,216,150,143,193,125,141,219,210,195,195,192,191, 1662 212,236,157,189,160,220,147,158,220,199,233,231,201,180,168,141, 1663 156,204,191,183,190,153,123,210,238,151,139,221,223,200,175,191, 1664 132,184,197,204,236,157,230,151,195,219,212,143,172,149,219,184, 1665 164,211,132,187,172,142,174,146,127,147,206,238,188,129,199,226, 1666 132,220,210,159,235,153,208,182,196,123,180,159,131,135,175,226, 1667 127,134,237,211,133,225,132,124,160,226,224,200,173,137,217,169, 1668 182,183,176,185,122,168,195,159,172,129,126,129,166,136,149,220, 1669 178,191,192,238,180,208,234,154,222,206,239,228,129,140,203,125, 1670 214,175,125,169,196,132,234,138,192,142,234,190,215,232,239,122, 1671 188,158,128,221,159,237,207,157,232,138,132,214,122,199,121,191, 1672 199,209,126,164,175,187,173,186,194,224,191,196,146,208,213,210, 1673 164,176,202,213,123,157,179,138,217,129,186,166,237,211,157,130, 1674 137,132,171,232,216,239,180,151,137,132,190,133,218,155,171,227, 1675 193,147,197,164,120,218,193,154,170,196,138,222,161,235,143,154, 1676 192,178,228,195,178,133,203,178,173,206,178,212,136,157,169,124, 1677 172,121,128,223,238,125,217,187,184,156,169,215,231,124,210,174, 1678 146,226,185,134,223,228,183,182,136,133,199,146,180,233,226,225, 1679 174,233,145,235,216,170,192,171,132,132,134,223,233,148,154,162, 1680 192,179,197,203,139,197,174,187,135,132,180,136,192,195,124,221, 1681 120,189,233,233,146,225,234,163,215,143,132,198,156,205,151,190, 1682 204,239,221,229,123,138,134,217,219,136,218,215,167,139,195,125, 1683 202,225,178,226,145,208,130,194,228,197,157,215,124,147,174,123, 1684 237,140,172,181,161,151,229,216,199,199,179,213,146,122,222,162, 1685 139,173,165,150,160,217,207,137,165,175,129,158,134,133,178,199, 1686 215,213,122,197 1687 }); 1688 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 1689 mOrientation = BaseGridView.VERTICAL; 1690 mNumRows = 3; 1691 1692 initActivity(intent); 1693 1694 runTestOnUiThread(new Runnable() { 1695 public void run() { 1696 mGridView.setSelectedPositionSmooth(10); 1697 } 1698 }); 1699 waitForScrollIdle(mVerifyLayout); 1700 int top1 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10)); 1701 1702 humanDelay(500); 1703 1704 // scroll to position with delta 1705 setSelectedPosition(20, 100); 1706 int top2 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20)); 1707 assertEquals(top1 - 100, top2); 1708 1709 // scroll to same position without delta, it will be reset 1710 setSelectedPosition(20, 0); 1711 int top3 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20)); 1712 assertEquals(top1, top3); 1713 1714 // scroll invisible item after last visible item 1715 final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 1716 .mGrid.getLastVisibleIndex(); 1717 setSelectedPosition(lastVisiblePos + 1, 100); 1718 int top4 = getCenterY(mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1)); 1719 verifyMargin(); 1720 assertEquals(top1 - 100, top4); 1721 1722 // scroll invisible item before first visible item 1723 final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 1724 .mGrid.getFirstVisibleIndex(); 1725 setSelectedPosition(firstVisiblePos - 1, 100); 1726 int top5 = getCenterY(mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1)); 1727 assertEquals(top1 - 100, top5); 1728 1729 // scroll to invisible item that is far away. 1730 setSelectedPosition(100, 100); 1731 int top6 = getCenterY(mGridView.getLayoutManager().findViewByPosition(100)); 1732 assertEquals(top1 - 100, top6); 1733 1734 // scroll to invisible item that is far away. 1735 runTestOnUiThread(new Runnable() { 1736 public void run() { 1737 mGridView.setSelectedPositionSmooth(200); 1738 } 1739 }); 1740 waitForScrollIdle(mVerifyLayout); 1741 Thread.sleep(500); 1742 int top7 = getCenterY(mGridView.getLayoutManager().findViewByPosition(200)); 1743 assertEquals(top1, top7); 1744 1745 // scroll to invisible item that is far away. 1746 setSelectedPosition(10, 50); 1747 int top8 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10)); 1748 assertEquals(top1 - 50, top8); 1749 } 1750 1751 public void testSmoothScrollSelectionEvents() throws Throwable { 1752 mInstrumentation = getInstrumentation(); 1753 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1754 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1755 R.layout.vertical_grid); 1756 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500); 1757 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1758 mOrientation = BaseGridView.VERTICAL; 1759 mNumRows = 3; 1760 initActivity(intent); 1761 1762 runTestOnUiThread(new Runnable() { 1763 public void run() { 1764 mGridView.setSelectedPositionSmooth(30); 1765 } 1766 }); 1767 waitForScrollIdle(mVerifyLayout); 1768 humanDelay(500); 1769 1770 final ArrayList<Integer> selectedPositions = new ArrayList<Integer>(); 1771 mGridView.setOnChildSelectedListener(new OnChildSelectedListener() { 1772 @Override 1773 public void onChildSelected(ViewGroup parent, View view, int position, long id) { 1774 selectedPositions.add(position); 1775 } 1776 }); 1777 1778 sendRepeatedKeys(10, KeyEvent.KEYCODE_DPAD_UP); 1779 humanDelay(500); 1780 waitForScrollIdle(mVerifyLayout); 1781 // should only get childselected event for item 0 once 1782 assertTrue(selectedPositions.size() > 0); 1783 assertEquals(0, selectedPositions.get(selectedPositions.size() - 1).intValue()); 1784 for (int i = selectedPositions.size() - 2; i >= 0; i--) { 1785 assertFalse(0 == selectedPositions.get(i).intValue()); 1786 } 1787 1788 } 1789 1790 public void testSmoothScrollSelectionEventsLinear() throws Throwable { 1791 mInstrumentation = getInstrumentation(); 1792 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1793 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1794 R.layout.vertical_linear); 1795 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500); 1796 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1797 mOrientation = BaseGridView.VERTICAL; 1798 mNumRows = 1; 1799 initActivity(intent); 1800 1801 runTestOnUiThread(new Runnable() { 1802 public void run() { 1803 mGridView.setSelectedPositionSmooth(10); 1804 } 1805 }); 1806 waitForScrollIdle(mVerifyLayout); 1807 humanDelay(500); 1808 1809 final ArrayList<Integer> selectedPositions = new ArrayList<Integer>(); 1810 mGridView.setOnChildSelectedListener(new OnChildSelectedListener() { 1811 @Override 1812 public void onChildSelected(ViewGroup parent, View view, int position, long id) { 1813 selectedPositions.add(position); 1814 } 1815 }); 1816 1817 sendRepeatedKeys(10, KeyEvent.KEYCODE_DPAD_UP); 1818 humanDelay(500); 1819 waitForScrollIdle(mVerifyLayout); 1820 // should only get childselected event for item 0 once 1821 assertTrue(selectedPositions.size() > 0); 1822 assertEquals(0, selectedPositions.get(selectedPositions.size() - 1).intValue()); 1823 for (int i = selectedPositions.size() - 2; i >= 0; i--) { 1824 assertFalse(0 == selectedPositions.get(i).intValue()); 1825 } 1826 1827 } 1828 1829 public void testScrollToNoneExisting() throws Throwable { 1830 mInstrumentation = getInstrumentation(); 1831 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1832 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1833 R.layout.vertical_grid); 1834 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100); 1835 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1836 mOrientation = BaseGridView.VERTICAL; 1837 mNumRows = 3; 1838 initActivity(intent); 1839 1840 runTestOnUiThread(new Runnable() { 1841 public void run() { 1842 mGridView.setSelectedPositionSmooth(99); 1843 } 1844 }); 1845 waitForScrollIdle(mVerifyLayout); 1846 humanDelay(500); 1847 1848 1849 runTestOnUiThread(new Runnable() { 1850 public void run() { 1851 mGridView.setSelectedPositionSmooth(50); 1852 } 1853 }); 1854 Thread.sleep(100); 1855 runTestOnUiThread(new Runnable() { 1856 public void run() { 1857 mGridView.requestLayout(); 1858 mGridView.setSelectedPositionSmooth(0); 1859 } 1860 }); 1861 waitForScrollIdle(mVerifyLayout); 1862 humanDelay(500); 1863 1864 } 1865 1866 public void testSmoothscrollerInterrupted() throws Throwable { 1867 mInstrumentation = getInstrumentation(); 1868 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1869 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1870 R.layout.vertical_linear); 1871 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 1872 int[] items = new int[100]; 1873 for (int i = 0; i < items.length; i++) { 1874 items[i] = 680; 1875 } 1876 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1877 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1878 mOrientation = BaseGridView.VERTICAL; 1879 mNumRows = 1; 1880 1881 initActivity(intent); 1882 1883 mGridView.setSelectedPositionSmooth(0); 1884 waitForScrollIdle(mVerifyLayout); 1885 assertTrue(mGridView.getChildAt(0).hasFocus()); 1886 1887 // Pressing lots of key to make sure smooth scroller is running 1888 for (int i = 0; i < 20; i++) { 1889 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 1890 } 1891 Thread.sleep(100); 1892 int total = 0; 1893 while (mGridView.getLayoutManager().isSmoothScrolling() || 1894 mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE) { 1895 if ((total += 10) >= WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS) { 1896 throw new RuntimeException("waitForScrollIdle Timeout"); 1897 } 1898 try { 1899 // Repeatedly pressing to make sure pending keys does not drop to zero. 1900 Thread.sleep(10); 1901 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 1902 } catch (InterruptedException ex) { 1903 break; 1904 } 1905 } 1906 1907 assertTrue("LinearSmoothScroller would not use many RV.smoothScrollBy() calls", 1908 ((VerticalGridViewEx) mGridView).mSmoothScrollByCalled < 10); 1909 } 1910 1911 public void testSmoothscrollerCancelled() throws Throwable { 1912 mInstrumentation = getInstrumentation(); 1913 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1914 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1915 R.layout.vertical_linear); 1916 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 1917 int[] items = new int[100]; 1918 for (int i = 0; i < items.length; i++) { 1919 items[i] = 680; 1920 } 1921 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1922 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1923 mOrientation = BaseGridView.VERTICAL; 1924 mNumRows = 1; 1925 1926 initActivity(intent); 1927 1928 mGridView.setSelectedPositionSmooth(0); 1929 waitForScrollIdle(mVerifyLayout); 1930 assertTrue(mGridView.getChildAt(0).hasFocus()); 1931 1932 int targetPosition = items.length - 1; 1933 mGridView.setSelectedPositionSmooth(targetPosition); 1934 runTestOnUiThread(new Runnable() { 1935 public void run() { 1936 mGridView.stopScroll(); 1937 } 1938 }); 1939 Thread.sleep(100); 1940 assertEquals(mGridView.getSelectedPosition(), targetPosition); 1941 assertSame(mGridView.getLayoutManager().findViewByPosition(targetPosition), 1942 mGridView.findFocus()); 1943 } 1944 1945 public void testSetNumRowsAndAddItem() throws Throwable { 1946 mInstrumentation = getInstrumentation(); 1947 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1948 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1949 R.layout.vertical_linear); 1950 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 1951 int[] items = new int[2]; 1952 for (int i = 0; i < items.length; i++) { 1953 items[i] = 300; 1954 } 1955 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1956 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1957 mOrientation = BaseGridView.VERTICAL; 1958 mNumRows = 1; 1959 1960 initActivity(intent); 1961 1962 mGridView.setSelectedPositionSmooth(0); 1963 waitForScrollIdle(mVerifyLayout); 1964 1965 mActivity.addItems(items.length, new int[]{300}); 1966 1967 runTestOnUiThread(new Runnable() { 1968 public void run() { 1969 ((VerticalGridView) mGridView).setNumColumns(2); 1970 } 1971 }); 1972 Thread.sleep(1000); 1973 assertTrue(mGridView.getChildAt(2).getLeft() != mGridView.getChildAt(1).getLeft()); 1974 } 1975 1976 1977 public void testRequestLayoutBugInLayout() throws Throwable { 1978 mInstrumentation = getInstrumentation(); 1979 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1980 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1981 R.layout.vertical_linear); 1982 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout); 1983 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 1984 int[] items = new int[100]; 1985 for (int i = 0; i < items.length; i++) { 1986 items[i] = 300; 1987 } 1988 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1989 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1990 mOrientation = BaseGridView.VERTICAL; 1991 mNumRows = 1; 1992 1993 initActivity(intent); 1994 1995 runTestOnUiThread(new Runnable() { 1996 public void run() { 1997 mGridView.setSelectedPositionSmooth(1); 1998 } 1999 }); 2000 waitForScrollIdle(mVerifyLayout); 2001 2002 sendKeys(KeyEvent.KEYCODE_DPAD_UP); 2003 waitForScrollIdle(mVerifyLayout); 2004 2005 assertEquals("Line 2", ((TextView) mGridView.findFocus()).getText().toString()); 2006 } 2007 2008 2009 public void testChangeLayoutInChild() throws Throwable { 2010 mInstrumentation = getInstrumentation(); 2011 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2012 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2013 R.layout.vertical_linear_wrap_content); 2014 intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true); 2015 int[] items = new int[2]; 2016 for (int i = 0; i < items.length; i++) { 2017 items[i] = 300; 2018 } 2019 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 2020 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2021 mOrientation = BaseGridView.VERTICAL; 2022 mNumRows = 1; 2023 2024 initActivity(intent); 2025 2026 runTestOnUiThread(new Runnable() { 2027 public void run() { 2028 mGridView.setSelectedPositionSmooth(0); 2029 } 2030 }); 2031 waitForScrollIdleAndItemAnimation(mVerifyLayout); 2032 verifyMargin(); 2033 2034 runTestOnUiThread(new Runnable() { 2035 public void run() { 2036 mGridView.setSelectedPositionSmooth(1); 2037 } 2038 }); 2039 waitForScrollIdleAndItemAnimation(mVerifyLayout); 2040 verifyMargin(); 2041 } 2042 2043 public void testWrapContent() throws Throwable { 2044 mInstrumentation = getInstrumentation(); 2045 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2046 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2047 R.layout.horizontal_grid_wrap); 2048 int[] items = new int[200]; 2049 for (int i = 0; i < items.length; i++) { 2050 items[i] = 300; 2051 } 2052 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 2053 mOrientation = BaseGridView.HORIZONTAL; 2054 mNumRows = 1; 2055 2056 initActivity(intent); 2057 2058 runTestOnUiThread(new Runnable() { 2059 public void run() { 2060 mActivity.attachToNewAdapter(new int[0]); 2061 } 2062 }); 2063 2064 } 2065 2066 2067 public void testZeroFixedSecondarySize() throws Throwable { 2068 mInstrumentation = getInstrumentation(); 2069 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2070 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2071 R.layout.vertical_linear_measured_with_zero); 2072 intent.putExtra(GridActivity.EXTRA_SECONDARY_SIZE_ZERO, true); 2073 int[] items = new int[2]; 2074 for (int i = 0; i < items.length; i++) { 2075 items[i] = 0; 2076 } 2077 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 2078 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2079 mOrientation = BaseGridView.VERTICAL; 2080 mNumRows = 1; 2081 2082 initActivity(intent); 2083 2084 } 2085 2086 public void testChildStates() throws Throwable { 2087 mInstrumentation = getInstrumentation(); 2088 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2089 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 2090 int[] items = new int[100]; 2091 for (int i = 0; i < items.length; i++) { 2092 items[i] = 200; 2093 } 2094 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 2095 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2096 intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true); 2097 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.selectable_text_view); 2098 mOrientation = BaseGridView.VERTICAL; 2099 mNumRows = 1; 2100 2101 initActivity(intent); 2102 mGridView.setSaveChildrenPolicy(VerticalGridView.SAVE_ALL_CHILD); 2103 2104 final SparseArray<Parcelable> container = new SparseArray<Parcelable>(); 2105 2106 // 1 Save view states 2107 runTestOnUiThread(new Runnable() { 2108 public void run() { 2109 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(0)) 2110 .getText()), 0, 1); 2111 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(1)) 2112 .getText()), 0, 1); 2113 mGridView.saveHierarchyState(container); 2114 } 2115 }); 2116 2117 // 2 Change view states 2118 runTestOnUiThread(new Runnable() { 2119 public void run() { 2120 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(0)) 2121 .getText()), 1, 2); 2122 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(1)) 2123 .getText()), 1, 2); 2124 } 2125 }); 2126 2127 // 3 Detached and re-attached, should still maintain state of (2) 2128 runTestOnUiThread(new Runnable() { 2129 public void run() { 2130 mGridView.setSelectedPositionSmooth(1); 2131 } 2132 }); 2133 waitForScrollIdleAndItemAnimation(mVerifyLayout); 2134 assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionStart(), 1); 2135 assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionEnd(), 2); 2136 assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionStart(), 1); 2137 assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionEnd(), 2); 2138 2139 // 4 Recycled and rebound, should load state from (2) 2140 runTestOnUiThread(new Runnable() { 2141 public void run() { 2142 mGridView.setSelectedPositionSmooth(20); 2143 } 2144 }); 2145 waitForScrollIdle(mVerifyLayout); 2146 runTestOnUiThread(new Runnable() { 2147 public void run() { 2148 mGridView.setSelectedPositionSmooth(0); 2149 } 2150 }); 2151 waitForScrollIdleAndItemAnimation(mVerifyLayout); 2152 assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionStart(), 1); 2153 assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionEnd(), 2); 2154 assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionStart(), 1); 2155 assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionEnd(), 2); 2156 } 2157 2158 2159 public void testNoDispatchSaveChildState() throws Throwable { 2160 mInstrumentation = getInstrumentation(); 2161 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2162 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 2163 int[] items = new int[100]; 2164 for (int i = 0; i < items.length; i++) { 2165 items[i] = 200; 2166 } 2167 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 2168 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2169 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.selectable_text_view); 2170 mOrientation = BaseGridView.VERTICAL; 2171 mNumRows = 1; 2172 2173 initActivity(intent); 2174 mGridView.setSaveChildrenPolicy(VerticalGridView.SAVE_NO_CHILD); 2175 2176 final SparseArray<Parcelable> container = new SparseArray<Parcelable>(); 2177 2178 // 1. Set text selection, save view states should do nothing on child 2179 runTestOnUiThread(new Runnable() { 2180 public void run() { 2181 for (int i = 0; i < mGridView.getChildCount(); i++) { 2182 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(i)) 2183 .getText()), 0, 1); 2184 } 2185 mGridView.saveHierarchyState(container); 2186 } 2187 }); 2188 2189 // 2. clear the text selection 2190 runTestOnUiThread(new Runnable() { 2191 public void run() { 2192 for (int i = 0; i < mGridView.getChildCount(); i++) { 2193 Selection.removeSelection((Spannable)(((TextView) mGridView.getChildAt(i)) 2194 .getText())); 2195 } 2196 } 2197 }); 2198 2199 // 3. Restore view states should be a no-op for child 2200 runTestOnUiThread(new Runnable() { 2201 public void run() { 2202 mGridView.restoreHierarchyState(container); 2203 for (int i = 0; i < mGridView.getChildCount(); i++) { 2204 assertEquals(-1, ((TextView) mGridView.getChildAt(i)).getSelectionStart()); 2205 assertEquals(-1, ((TextView) mGridView.getChildAt(i)).getSelectionEnd()); 2206 } 2207 } 2208 }); 2209 } 2210 2211 2212 static interface ViewTypeProvider { 2213 public int getViewType(int position); 2214 } 2215 2216 static interface ItemAlignmentFacetProvider { 2217 public ItemAlignmentFacet getItemAlignmentFacet(int viewType); 2218 } 2219 2220 static class TwoViewTypesProvider implements ViewTypeProvider { 2221 static int VIEW_TYPE_FIRST = 1; 2222 static int VIEW_TYPE_DEFAULT = 0; 2223 @Override 2224 public int getViewType(int position) { 2225 if (position == 0) { 2226 return VIEW_TYPE_FIRST; 2227 } else { 2228 return VIEW_TYPE_DEFAULT; 2229 } 2230 } 2231 } 2232 2233 static class ChangeableViewTypesProvider implements ViewTypeProvider { 2234 static SparseIntArray sViewTypes = new SparseIntArray(); 2235 @Override 2236 public int getViewType(int position) { 2237 return sViewTypes.get(position); 2238 } 2239 public static void clear() { 2240 sViewTypes.clear(); 2241 } 2242 public static void setViewType(int position, int type) { 2243 sViewTypes.put(position, type); 2244 } 2245 } 2246 2247 static class PositionItemAlignmentFacetProviderForRelativeLayout1 2248 implements ItemAlignmentFacetProvider { 2249 ItemAlignmentFacet mMultipleFacet; 2250 2251 PositionItemAlignmentFacetProviderForRelativeLayout1() { 2252 mMultipleFacet = new ItemAlignmentFacet(); 2253 ItemAlignmentFacet.ItemAlignmentDef[] defs = 2254 new ItemAlignmentFacet.ItemAlignmentDef[2]; 2255 defs[0] = new ItemAlignmentFacet.ItemAlignmentDef(); 2256 defs[0].setItemAlignmentViewId(R.id.t1); 2257 defs[1] = new ItemAlignmentFacet.ItemAlignmentDef(); 2258 defs[1].setItemAlignmentViewId(R.id.t2); 2259 defs[1].setItemAlignmentOffsetPercent(100); 2260 defs[1].setItemAlignmentOffset(-10); 2261 mMultipleFacet.setAlignmentDefs(defs); 2262 } 2263 2264 @Override 2265 public ItemAlignmentFacet getItemAlignmentFacet(int position) { 2266 if (position == 0) { 2267 return mMultipleFacet; 2268 } else { 2269 return null; 2270 } 2271 } 2272 } 2273 2274 public void testMultipleScrollPosition1() throws Throwable { 2275 mInstrumentation = getInstrumentation(); 2276 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2277 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2278 R.layout.vertical_linear); 2279 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout); 2280 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 2281 int[] items = new int[100]; 2282 for (int i = 0; i < items.length; i++) { 2283 items[i] = 300; 2284 } 2285 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 2286 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2287 intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS, 2288 TwoViewTypesProvider.class.getName()); 2289 // Set ItemAlignment for each ViewHolder and view type, ViewHolder should 2290 // override the view type settings. 2291 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS, 2292 PositionItemAlignmentFacetProviderForRelativeLayout1.class.getName()); 2293 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_VIEWTYPE_CLASS, 2294 ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2.class.getName()); 2295 mOrientation = BaseGridView.VERTICAL; 2296 mNumRows = 1; 2297 2298 initActivity(intent); 2299 2300 assertEquals("First view is aligned with padding top", 2301 mGridView.getPaddingTop(), mGridView.getChildAt(0).getTop()); 2302 2303 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 2304 waitForScrollIdle(mVerifyLayout); 2305 2306 final View v = mGridView.getChildAt(0); 2307 View t1 = v.findViewById(R.id.t1); 2308 int t1align = (t1.getTop() + t1.getBottom()) / 2; 2309 View t2 = v.findViewById(R.id.t2); 2310 int t2align = t2.getBottom() - 10; 2311 assertEquals("Expected alignment for 2nd textview", 2312 mGridView.getPaddingTop() - (t2align - t1align), 2313 v.getTop()); 2314 } 2315 2316 static class PositionItemAlignmentFacetProviderForRelativeLayout2 implements 2317 ItemAlignmentFacetProvider { 2318 ItemAlignmentFacet mMultipleFacet; 2319 2320 PositionItemAlignmentFacetProviderForRelativeLayout2() { 2321 mMultipleFacet = new ItemAlignmentFacet(); 2322 ItemAlignmentFacet.ItemAlignmentDef[] defs = new ItemAlignmentFacet.ItemAlignmentDef[2]; 2323 defs[0] = new ItemAlignmentFacet.ItemAlignmentDef(); 2324 defs[0].setItemAlignmentViewId(R.id.t1); 2325 defs[0].setItemAlignmentOffsetPercent(0); 2326 defs[1] = new ItemAlignmentFacet.ItemAlignmentDef(); 2327 defs[1].setItemAlignmentViewId(R.id.t2); 2328 defs[1].setItemAlignmentOffsetPercent(ItemAlignmentFacet.ITEM_ALIGN_OFFSET_PERCENT_DISABLED); 2329 defs[1].setItemAlignmentOffset(-10); 2330 mMultipleFacet.setAlignmentDefs(defs); 2331 } 2332 2333 @Override 2334 public ItemAlignmentFacet getItemAlignmentFacet(int position) { 2335 if (position == 0) { 2336 return mMultipleFacet; 2337 } else { 2338 return null; 2339 } 2340 } 2341 } 2342 2343 public void testMultipleScrollPosition2() throws Throwable { 2344 mInstrumentation = getInstrumentation(); 2345 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2346 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 2347 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout); 2348 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 2349 int[] items = new int[100]; 2350 for (int i = 0; i < items.length; i++) { 2351 items[i] = 300; 2352 } 2353 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 2354 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2355 intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS, 2356 TwoViewTypesProvider.class.getName()); 2357 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS, 2358 PositionItemAlignmentFacetProviderForRelativeLayout2.class.getName()); 2359 mOrientation = BaseGridView.VERTICAL; 2360 mNumRows = 1; 2361 2362 initActivity(intent); 2363 2364 assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(), 2365 mGridView.getChildAt(0).getTop()); 2366 2367 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 2368 waitForScrollIdle(mVerifyLayout); 2369 2370 final View v = mGridView.getChildAt(0); 2371 View t1 = v.findViewById(R.id.t1); 2372 int t1align = t1.getTop(); 2373 View t2 = v.findViewById(R.id.t2); 2374 int t2align = t2.getTop() - 10; 2375 assertEquals("Expected alignment for 2nd textview", 2376 mGridView.getPaddingTop() - (t2align - t1align), v.getTop()); 2377 } 2378 2379 static class ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2 implements 2380 ItemAlignmentFacetProvider { 2381 ItemAlignmentFacet mMultipleFacet; 2382 2383 ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2() { 2384 mMultipleFacet = new ItemAlignmentFacet(); 2385 ItemAlignmentFacet.ItemAlignmentDef[] defs = new ItemAlignmentFacet.ItemAlignmentDef[2]; 2386 defs[0] = new ItemAlignmentFacet.ItemAlignmentDef(); 2387 defs[0].setItemAlignmentViewId(R.id.t1); 2388 defs[0].setItemAlignmentOffsetPercent(0); 2389 defs[1] = new ItemAlignmentFacet.ItemAlignmentDef(); 2390 defs[1].setItemAlignmentViewId(R.id.t2); 2391 defs[1].setItemAlignmentOffsetPercent(100); 2392 defs[1].setItemAlignmentOffset(-10); 2393 mMultipleFacet.setAlignmentDefs(defs); 2394 } 2395 2396 @Override 2397 public ItemAlignmentFacet getItemAlignmentFacet(int viewType) { 2398 if (viewType == TwoViewTypesProvider.VIEW_TYPE_FIRST) { 2399 return mMultipleFacet; 2400 } else { 2401 return null; 2402 } 2403 } 2404 } 2405 2406 public void testMultipleScrollPosition3() throws Throwable { 2407 mInstrumentation = getInstrumentation(); 2408 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2409 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 2410 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout); 2411 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 2412 int[] items = new int[100]; 2413 for (int i = 0; i < items.length; i++) { 2414 items[i] = 300; 2415 } 2416 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 2417 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2418 intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS, 2419 TwoViewTypesProvider.class.getName()); 2420 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_VIEWTYPE_CLASS, 2421 ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2.class.getName()); 2422 mOrientation = BaseGridView.VERTICAL; 2423 mNumRows = 1; 2424 2425 initActivity(intent); 2426 2427 assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(), 2428 mGridView.getChildAt(0).getTop()); 2429 2430 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 2431 waitForScrollIdle(mVerifyLayout); 2432 2433 final View v = mGridView.getChildAt(0); 2434 View t1 = v.findViewById(R.id.t1); 2435 int t1align = t1.getTop(); 2436 View t2 = v.findViewById(R.id.t2); 2437 int t2align = t2.getBottom() - 10; 2438 assertEquals("Expected alignment for 2nd textview", 2439 mGridView.getPaddingTop() - (t2align - t1align), v.getTop()); 2440 } 2441 2442 public void testSelectionAndAddItemInOneCycle() throws Throwable { 2443 mInstrumentation = getInstrumentation(); 2444 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2445 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2446 R.layout.vertical_linear); 2447 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0); 2448 initActivity(intent); 2449 mOrientation = BaseGridView.HORIZONTAL; 2450 mNumRows = 1; 2451 2452 runTestOnUiThread(new Runnable() { 2453 public void run() { 2454 mActivity.addItems(0, new int[]{300, 300}); 2455 mGridView.setSelectedPosition(0); 2456 } 2457 }); 2458 waitForTransientStateGone(null); 2459 assertEquals(0, mGridView.getSelectedPosition()); 2460 } 2461 2462 public void testSelectViewTaskSmoothWithAdapterChange() throws Throwable { 2463 testSelectViewTaskWithAdapterChange(true /*smooth*/); 2464 } 2465 2466 public void testSelectViewTaskWithAdapterChange() throws Throwable { 2467 testSelectViewTaskWithAdapterChange(false /*smooth*/); 2468 } 2469 2470 private void testSelectViewTaskWithAdapterChange(final boolean smooth) throws Throwable { 2471 mInstrumentation = getInstrumentation(); 2472 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2473 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2474 R.layout.vertical_linear); 2475 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2); 2476 initActivity(intent); 2477 mOrientation = BaseGridView.HORIZONTAL; 2478 mNumRows = 1; 2479 2480 final View firstView = mGridView.getLayoutManager().findViewByPosition(0); 2481 final View[] selectedViewByTask = new View[1]; 2482 final ViewHolderTask task = new ViewHolderTask() { 2483 public void run(RecyclerView.ViewHolder viewHolder) { 2484 selectedViewByTask[0] = viewHolder.itemView; 2485 } 2486 }; 2487 runTestOnUiThread(new Runnable() { 2488 public void run() { 2489 mActivity.removeItems(0, 1); 2490 if (smooth) { 2491 mGridView.setSelectedPositionSmooth(0, task); 2492 } else { 2493 mGridView.setSelectedPosition(0, task); 2494 } 2495 } 2496 }); 2497 waitForTransientStateGone(null); 2498 assertEquals(0, mGridView.getSelectedPosition()); 2499 assertNotNull(selectedViewByTask[0]); 2500 assertNotSame(firstView, selectedViewByTask[0]); 2501 assertSame(mGridView.getLayoutManager().findViewByPosition(0), selectedViewByTask[0]); 2502 } 2503 2504 public void testNotifyItemTypeChangedSelectionEvent() throws Throwable { 2505 mInstrumentation = getInstrumentation(); 2506 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2507 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2508 R.layout.vertical_linear); 2509 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10); 2510 intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS, 2511 ChangeableViewTypesProvider.class.getName()); 2512 ChangeableViewTypesProvider.clear(); 2513 initActivity(intent); 2514 mOrientation = BaseGridView.HORIZONTAL; 2515 mNumRows = 1; 2516 2517 final ArrayList<Integer> selectedLog = new ArrayList<Integer>(); 2518 mGridView.setOnChildSelectedListener(new OnChildSelectedListener() { 2519 public void onChildSelected(ViewGroup parent, View view, int position, long id) { 2520 selectedLog.add(position); 2521 } 2522 }); 2523 2524 runTestOnUiThread(new Runnable() { 2525 public void run() { 2526 ChangeableViewTypesProvider.setViewType(0, 1); 2527 mGridView.getAdapter().notifyItemChanged(0, 1); 2528 } 2529 }); 2530 waitForTransientStateGone(null); 2531 assertEquals(0, mGridView.getSelectedPosition()); 2532 assertEquals(selectedLog.size(), 1); 2533 assertEquals((int) selectedLog.get(0), 0); 2534 } 2535 2536 public void testSelectionSmoothAndAddItemInOneCycle() throws Throwable { 2537 mInstrumentation = getInstrumentation(); 2538 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2539 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2540 R.layout.vertical_linear); 2541 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0); 2542 initActivity(intent); 2543 mOrientation = BaseGridView.HORIZONTAL; 2544 mNumRows = 1; 2545 2546 runTestOnUiThread(new Runnable() { 2547 public void run() { 2548 mActivity.addItems(0, new int[]{300, 300}); 2549 mGridView.setSelectedPositionSmooth(0); 2550 } 2551 }); 2552 waitForTransientStateGone(null); 2553 assertEquals(0, mGridView.getSelectedPosition()); 2554 } 2555 2556 public void testExtraLayoutSpace() throws Throwable { 2557 mInstrumentation = getInstrumentation(); 2558 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2559 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2560 R.layout.vertical_linear); 2561 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000); 2562 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2563 initActivity(intent); 2564 2565 final int windowSize = mGridView.getHeight(); 2566 final int extraLayoutSize = windowSize; 2567 int itemLength = mActivity.mItemLengths[0]; 2568 mOrientation = BaseGridView.VERTICAL; 2569 mNumRows = 1; 2570 2571 // add extra layout space 2572 runTestOnUiThread(new Runnable() { 2573 public void run() { 2574 mGridView.setExtraLayoutSpace(extraLayoutSize); 2575 } 2576 }); 2577 Thread.sleep(50); 2578 View v; 2579 v = mGridView.getChildAt(mGridView.getChildCount() - 1); 2580 assertTrue(v.getTop() < windowSize + extraLayoutSize); 2581 assertTrue(v.getBottom() >= windowSize + extraLayoutSize - 2582 mGridView.getVerticalMargin()); 2583 2584 mGridView.setSelectedPositionSmooth(150); 2585 waitForScrollIdle(mVerifyLayout); 2586 v = mGridView.getChildAt(0); 2587 assertTrue(v.getBottom() > - extraLayoutSize); 2588 assertTrue(v.getTop() <= -extraLayoutSize + mGridView.getVerticalMargin()); 2589 2590 // clear extra layout space 2591 runTestOnUiThread(new Runnable() { 2592 public void run() { 2593 mGridView.setExtraLayoutSpace(0); 2594 verifyMargin(); 2595 } 2596 }); 2597 Thread.sleep(50); 2598 v = mGridView.getChildAt(mGridView.getChildCount() - 1); 2599 assertTrue(v.getTop() < windowSize); 2600 assertTrue(v.getBottom() >= windowSize - mGridView.getVerticalMargin()); 2601 } 2602 2603 public void testFocusFinder() throws Throwable { 2604 mInstrumentation = getInstrumentation(); 2605 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2606 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2607 R.layout.vertical_linear_with_button); 2608 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 3); 2609 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2610 initActivity(intent); 2611 mOrientation = BaseGridView.VERTICAL; 2612 mNumRows = 1; 2613 2614 // test focus from button to vertical grid view 2615 final View button = mActivity.findViewById(R.id.button); 2616 assertTrue(button.isFocused()); 2617 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 2618 assertFalse(mGridView.isFocused()); 2619 assertTrue(mGridView.hasFocus()); 2620 2621 // FocusFinder should find last focused(2nd) item on DPAD_DOWN 2622 final View secondChild = mGridView.getChildAt(1); 2623 runTestOnUiThread(new Runnable() { 2624 @Override 2625 public void run() { 2626 secondChild.requestFocus(); 2627 button.requestFocus(); 2628 } 2629 }); 2630 assertTrue(button.isFocused()); 2631 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 2632 assertTrue(secondChild.isFocused()); 2633 2634 // Bug 26918143 Even VerticalGridView is not focusable, FocusFinder should find last focused 2635 // (2nd) item on DPAD_DOWN. 2636 runTestOnUiThread(new Runnable() { 2637 @Override 2638 public void run() { 2639 button.requestFocus(); 2640 } 2641 }); 2642 mGridView.setFocusable(false); 2643 mGridView.setFocusableInTouchMode(false); 2644 assertTrue(button.isFocused()); 2645 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 2646 assertTrue(secondChild.isFocused()); 2647 } 2648 2649 public void testRestoreIndexAndAddItems() throws Throwable { 2650 mInstrumentation = getInstrumentation(); 2651 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2652 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2653 R.layout.vertical_linear); 2654 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item); 2655 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 4); 2656 initActivity(intent); 2657 mOrientation = BaseGridView.VERTICAL; 2658 mNumRows = 1; 2659 2660 assertEquals(mGridView.getSelectedPosition(), 0); 2661 final SparseArray states = new SparseArray(); 2662 runTestOnUiThread(new Runnable() { 2663 @Override 2664 public void run() { 2665 mGridView.saveHierarchyState(states); 2666 mGridView.setAdapter(null); 2667 } 2668 2669 }); 2670 runTestOnUiThread(new Runnable() { 2671 @Override 2672 public void run() { 2673 mGridView.restoreHierarchyState(states); 2674 mActivity.attachToNewAdapter(new int[0]); 2675 mActivity.addItems(0, new int[]{100, 100, 100, 100}); 2676 } 2677 2678 }); 2679 waitForTransientStateGone(null); 2680 assertEquals(mGridView.getSelectedPosition(), 0); 2681 } 2682 2683 public void test27766012() throws Throwable { 2684 mInstrumentation = getInstrumentation(); 2685 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2686 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2687 R.layout.vertical_linear_with_button_onleft); 2688 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item); 2689 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2); 2690 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2691 intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, false); 2692 initActivity(intent); 2693 mOrientation = BaseGridView.VERTICAL; 2694 mNumRows = 1; 2695 2696 // set remove animator two seconds 2697 mGridView.getItemAnimator().setRemoveDuration(2000); 2698 final View view = mGridView.getChildAt(1); 2699 runTestOnUiThread(new Runnable() { 2700 @Override 2701 public void run() { 2702 view.requestFocus(); 2703 } 2704 }); 2705 assertTrue(view.hasFocus()); 2706 runTestOnUiThread(new Runnable() { 2707 @Override 2708 public void run() { 2709 mActivity.removeItems(0, 2); 2710 } 2711 2712 }); 2713 // wait one second, removing second view is still attached to parent 2714 Thread.sleep(1000); 2715 assertSame(view.getParent(), mGridView); 2716 runTestOnUiThread(new Runnable() { 2717 @Override 2718 public void run() { 2719 // refocus to the removed item and do a focus search. 2720 view.requestFocus(); 2721 view.focusSearch(View.FOCUS_UP); 2722 } 2723 2724 }); 2725 } 2726 2727 public void testBug27258366() throws Throwable { 2728 mInstrumentation = getInstrumentation(); 2729 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2730 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2731 R.layout.vertical_linear_with_button_onleft); 2732 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item); 2733 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10); 2734 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2735 intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, false); 2736 initActivity(intent); 2737 mOrientation = BaseGridView.VERTICAL; 2738 mNumRows = 1; 2739 2740 // move item1 500 pixels right, when focus is on item1, default focus finder will pick 2741 // item0 and item2 for the best match of focusSearch(FOCUS_LEFT). The grid widget 2742 // must override default addFocusables(), not to add item0 or item2. 2743 mActivity.mAdapterListener = new GridActivity.AdapterListener() { 2744 public void onBind(RecyclerView.ViewHolder vh, int position) { 2745 if (position == 1) { 2746 vh.itemView.setPaddingRelative(500, 0, 0, 0); 2747 } else { 2748 vh.itemView.setPaddingRelative(0, 0, 0, 0); 2749 } 2750 } 2751 }; 2752 runTestOnUiThread(new Runnable() { 2753 @Override 2754 public void run() { 2755 mGridView.getAdapter().notifyDataSetChanged(); 2756 } 2757 }); 2758 Thread.sleep(100); 2759 2760 final ViewGroup secondChild = (ViewGroup) mGridView.getChildAt(1); 2761 runTestOnUiThread(new Runnable() { 2762 @Override 2763 public void run() { 2764 secondChild.requestFocus(); 2765 } 2766 }); 2767 sendKeys(KeyEvent.KEYCODE_DPAD_LEFT); 2768 Thread.sleep(100); 2769 final View button = mActivity.findViewById(R.id.button); 2770 assertTrue(button.isFocused()); 2771 } 2772 2773 public void testAccessibility() throws Throwable { 2774 mInstrumentation = getInstrumentation(); 2775 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 2776 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 2777 R.layout.vertical_linear); 2778 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000); 2779 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 2780 initActivity(intent); 2781 mOrientation = BaseGridView.VERTICAL; 2782 mNumRows = 1; 2783 2784 assertTrue(0 == mGridView.getSelectedPosition()); 2785 2786 final RecyclerViewAccessibilityDelegate delegateCompat = mGridView 2787 .getCompatAccessibilityDelegate(); 2788 final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 2789 runTestOnUiThread(new Runnable() { 2790 @Override 2791 public void run() { 2792 delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info); 2793 } 2794 }); 2795 assertTrue("test sanity", info.isScrollable()); 2796 runTestOnUiThread(new Runnable() { 2797 @Override 2798 public void run() { 2799 delegateCompat.performAccessibilityAction(mGridView, 2800 AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD, null); 2801 } 2802 }); 2803 waitForScrollIdle(mVerifyLayout); 2804 int selectedPosition1 = mGridView.getSelectedPosition(); 2805 assertTrue(0 < selectedPosition1); 2806 2807 runTestOnUiThread(new Runnable() { 2808 @Override 2809 public void run() { 2810 delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info); 2811 } 2812 }); 2813 assertTrue("test sanity", info.isScrollable()); 2814 runTestOnUiThread(new Runnable() { 2815 @Override 2816 public void run() { 2817 delegateCompat.performAccessibilityAction(mGridView, 2818 AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD, null); 2819 } 2820 }); 2821 waitForScrollIdle(mVerifyLayout); 2822 int selectedPosition2 = mGridView.getSelectedPosition(); 2823 assertTrue(selectedPosition2 < selectedPosition1); 2824 } 2825 2826} 2827