GridWidgetTest.java revision db0b1afb71440b79923692d58adee982b5954838
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.support.v17.leanback.tests.R; 19import android.test.ActivityInstrumentationTestCase2; 20import android.text.Selection; 21import android.text.Spannable; 22import android.util.Log; 23import android.util.SparseArray; 24import android.view.KeyEvent; 25import android.view.View; 26import android.view.ViewGroup; 27import android.widget.TextView; 28import android.app.Instrumentation; 29import android.content.Intent; 30import android.os.Parcelable; 31 32import java.util.ArrayList; 33import java.util.Arrays; 34import java.util.Comparator; 35import java.util.HashMap; 36import java.util.Iterator; 37 38/** 39 * @hide from javadoc 40 */ 41public class GridWidgetTest extends ActivityInstrumentationTestCase2<GridActivity> { 42 43 private static final boolean HUMAN_DELAY = false; 44 private static final long WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS = 60000; 45 46 protected GridActivity mActivity; 47 protected Instrumentation mInstrumentation; 48 protected BaseGridView mGridView; 49 protected GridLayoutManager mLayoutManager; 50 protected int mOrientation; 51 protected int mNumRows; 52 53 private final Comparator<View> mRowSortComparator = new Comparator<View>() { 54 public int compare(View lhs, View rhs) { 55 if (mOrientation == BaseGridView.HORIZONTAL) { 56 return lhs.getLeft() - rhs.getLeft(); 57 } else { 58 return lhs.getTop() - rhs.getTop(); 59 } 60 }; 61 }; 62 63 /** 64 * Verify margins between items on same row are same. 65 */ 66 private final Runnable mVerifyLayout = new Runnable() { 67 @Override 68 public void run() { 69 verifyMargin(); 70 } 71 }; 72 73 public GridWidgetTest() { 74 super("android.support.v17.leanback.tests", GridActivity.class); 75 } 76 77 private void humanDelay(int delay) throws InterruptedException { 78 if (HUMAN_DELAY) Thread.sleep(delay); 79 } 80 /** 81 * Change size of the Adapter and notifyDataSetChanged. 82 */ 83 private void changeArraySize(final int size) throws Throwable { 84 runTestOnUiThread(new Runnable() { 85 public void run() { 86 mActivity.changeArraySize(size); 87 } 88 }); 89 Thread.sleep(500); 90 } 91 92 /** 93 * Change selected position. 94 */ 95 private void setSelectedPosition(final int position, final int scrollExtra) throws Throwable { 96 runTestOnUiThread(new Runnable() { 97 public void run() { 98 mGridView.setSelectedPosition(position, scrollExtra); 99 } 100 }); 101 Thread.sleep(500); 102 } 103 104 /** 105 * Wait for grid view stop scroll and optionally verify state of grid view. 106 */ 107 protected void waitForScrollIdle(Runnable verify) throws Throwable { 108 Thread.sleep(100); 109 int total = 0; 110 while (mGridView.getLayoutManager().isSmoothScrolling() || 111 mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE) { 112 if ((total += 100) >= WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS) { 113 throw new RuntimeException("waitForScrollIdle Timeout"); 114 } 115 try { 116 Thread.sleep(100); 117 } catch (InterruptedException ex) { 118 break; 119 } 120 if (verify != null) { 121 runTestOnUiThread(verify); 122 } 123 } 124 } 125 126 /** 127 * Wait for grid view stop animation and optionally verify state of grid view. 128 */ 129 protected void waitForTransientStateGone(Runnable verify) throws Throwable { 130 do { 131 try { 132 Thread.sleep(100); 133 } catch (InterruptedException ex) { 134 break; 135 } 136 if (verify != null) { 137 runTestOnUiThread(verify); 138 } 139 } while (mGridView.hasTransientState()); 140 } 141 142 /** 143 * Wait for grid view stop scroll. 144 */ 145 protected void waitForScrollIdle() throws Throwable { 146 waitForScrollIdle(null); 147 } 148 149 /** 150 * Scrolls using given key. 151 */ 152 protected void scroll(int key, Runnable verify) throws Throwable { 153 do { 154 if (verify != null) { 155 runTestOnUiThread(verify); 156 } 157 sendRepeatedKeys(10, key); 158 try { 159 Thread.sleep(300); 160 } catch (InterruptedException ex) { 161 break; 162 } 163 } while (mGridView.getLayoutManager().isSmoothScrolling() || 164 mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE); 165 } 166 167 protected void scrollToBegin(Runnable verify) throws Throwable { 168 int key; 169 if (mOrientation == BaseGridView.HORIZONTAL) { 170 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 171 key = KeyEvent.KEYCODE_DPAD_RIGHT; 172 } else { 173 key = KeyEvent.KEYCODE_DPAD_LEFT; 174 } 175 } else { 176 key = KeyEvent.KEYCODE_DPAD_UP; 177 } 178 scroll(key, verify); 179 } 180 181 protected void scrollToEnd(Runnable verify) throws Throwable { 182 int key; 183 if (mOrientation == BaseGridView.HORIZONTAL) { 184 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 185 key = KeyEvent.KEYCODE_DPAD_LEFT; 186 } else { 187 key = KeyEvent.KEYCODE_DPAD_RIGHT; 188 } 189 } else { 190 key = KeyEvent.KEYCODE_DPAD_DOWN; 191 } 192 scroll(key, verify); 193 } 194 195 /** 196 * Group and sort children by their position on each row (HORIZONTAL) or column(VERTICAL). 197 */ 198 protected View[][] sortByRows() { 199 final HashMap<Integer, ArrayList<View>> rows = new HashMap<Integer, ArrayList<View>>(); 200 ArrayList<Integer> rowLocations = new ArrayList(); 201 for (int i = 0; i < mGridView.getChildCount(); i++) { 202 View v = mGridView.getChildAt(i); 203 int rowLocation; 204 if (mOrientation == BaseGridView.HORIZONTAL) { 205 rowLocation = v.getTop(); 206 } else { 207 rowLocation = mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL ? 208 v.getRight() : v.getLeft(); 209 } 210 ArrayList<View> views = rows.get(rowLocation); 211 if (views == null) { 212 views = new ArrayList<View>(); 213 rows.put(rowLocation, views); 214 rowLocations.add(rowLocation); 215 } 216 views.add(v); 217 } 218 Object[] sortedLocations = rowLocations.toArray(); 219 Arrays.sort(sortedLocations); 220 if (mNumRows != rows.size()) { 221 assertEquals("Dump Views by rows "+rows, mNumRows, rows.size()); 222 } 223 View[][] sorted = new View[rows.size()][]; 224 for (int i = 0; i < rowLocations.size(); i++) { 225 Integer rowLocation = rowLocations.get(i); 226 ArrayList<View> arr = rows.get(rowLocation); 227 View[] views = arr.toArray(new View[arr.size()]); 228 Arrays.sort(views, mRowSortComparator); 229 sorted[i] = views; 230 } 231 return sorted; 232 } 233 234 protected void verifyMargin() { 235 View[][] sorted = sortByRows(); 236 for (int row = 0; row < sorted.length; row++) { 237 View[] views = sorted[row]; 238 int margin = -1; 239 for (int i = 1; i < views.length; i++) { 240 if (mOrientation == BaseGridView.HORIZONTAL) { 241 assertEquals(mGridView.getHorizontalMargin(), 242 views[i].getLeft() - views[i - 1].getRight()); 243 } else { 244 assertEquals(mGridView.getVerticalMargin(), 245 views[i].getTop() - views[i - 1].getBottom()); 246 } 247 } 248 } 249 } 250 251 protected void verifyBeginAligned() { 252 View[][] sorted = sortByRows(); 253 int alignedLocation = 0; 254 if (mOrientation == BaseGridView.HORIZONTAL) { 255 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 256 for (int i = 0; i < sorted.length; i++) { 257 if (i == 0) { 258 alignedLocation = sorted[i][sorted[i].length - 1].getRight(); 259 } else { 260 assertEquals(alignedLocation, sorted[i][sorted[i].length - 1].getRight()); 261 } 262 } 263 } else { 264 for (int i = 0; i < sorted.length; i++) { 265 if (i == 0) { 266 alignedLocation = sorted[i][0].getLeft(); 267 } else { 268 assertEquals(alignedLocation, sorted[i][0].getLeft()); 269 } 270 } 271 } 272 } else { 273 for (int i = 0; i < sorted.length; i++) { 274 if (i == 0) { 275 alignedLocation = sorted[i][0].getTop(); 276 } else { 277 assertEquals(alignedLocation, sorted[i][0].getTop()); 278 } 279 } 280 } 281 } 282 283 protected int[] getEndEdges() { 284 View[][] sorted = sortByRows(); 285 int[] edges = new int[sorted.length]; 286 if (mOrientation == BaseGridView.HORIZONTAL) { 287 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 288 for (int i = 0; i < sorted.length; i++) { 289 edges[i] = sorted[i][0].getLeft(); 290 } 291 } else { 292 for (int i = 0; i < sorted.length; i++) { 293 edges[i] = sorted[i][sorted[i].length - 1].getRight(); 294 } 295 } 296 } else { 297 for (int i = 0; i < sorted.length; i++) { 298 edges[i] = sorted[i][sorted[i].length - 1].getBottom(); 299 } 300 } 301 return edges; 302 } 303 304 protected void verifyEdgesSame(int[] edges, int[] edges2) { 305 assertEquals(edges.length, edges2.length); 306 for (int i = 0; i < edges.length; i++) { 307 assertEquals(edges[i], edges2[i]); 308 } 309 } 310 311 protected void verifyBoundCount(int count) { 312 if (mActivity.getBoundCount() != count) { 313 StringBuffer b = new StringBuffer(); 314 b.append("ItemsLength: "); 315 for (int i = 0; i < mActivity.mItemLengths.length; i++) { 316 b.append(mActivity.mItemLengths[i]).append(","); 317 } 318 assertEquals("Bound count does not match, ItemsLengths: "+ b, 319 count, mActivity.getBoundCount()); 320 } 321 } 322 323 private static int getCenterY(View v) { 324 return (v.getTop() + v.getBottom())/2; 325 } 326 327 private static int getCenterX(View v) { 328 return (v.getLeft() + v.getRight())/2; 329 } 330 331 private void initActivity(Intent intent) { 332 setActivityIntent(intent); 333 mActivity = getActivity(); 334 final String testName = getName(); 335 try { 336 runTestOnUiThread(new Runnable() { 337 public void run() { 338 mActivity.setTitle(testName); 339 } 340 }); 341 Thread.sleep(1000); 342 } catch (Throwable t) { 343 t.printStackTrace(); 344 } 345 mGridView = mActivity.mGridView; 346 } 347 348 public void testThreeRowHorizontalBasic() throws Throwable { 349 mInstrumentation = getInstrumentation(); 350 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 351 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid); 352 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100); 353 initActivity(intent); 354 mOrientation = BaseGridView.HORIZONTAL; 355 mNumRows = 3; 356 357 scrollToEnd(mVerifyLayout); 358 verifyBoundCount(100); 359 360 scrollToBegin(mVerifyLayout); 361 362 verifyBeginAligned(); 363 } 364 365 public void testThreeColumnVerticalBasic() throws Throwable { 366 367 mInstrumentation = getInstrumentation(); 368 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 369 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid); 370 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 371 initActivity(intent); 372 mOrientation = BaseGridView.VERTICAL; 373 mNumRows = 3; 374 375 scrollToEnd(mVerifyLayout); 376 verifyBoundCount(200); 377 378 scrollToBegin(mVerifyLayout); 379 380 verifyBeginAligned(); 381 } 382 383 public void testRedundantAppendRemove() throws Throwable { 384 mInstrumentation = getInstrumentation(); 385 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 386 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 387 R.layout.vertical_grid_testredundantappendremove); 388 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{ 389 149,177,128,234,227,187,163,223,146,210,228,148,227,193,182,197,177,142,225,207, 390 157,171,209,204,187,184,123,221,197,153,202,179,193,214,226,173,225,143,188,159, 391 139,193,233,143,227,203,222,124,228,223,164,131,228,126,211,160,165,152,235,184, 392 155,224,149,181,171,229,200,234,177,130,164,172,188,139,132,203,179,220,147,131, 393 226,127,230,239,183,203,206,227,123,170,239,234,200,149,237,204,160,133,202,234, 394 173,122,139,149,151,153,216,231,121,145,227,153,186,174,223,180,123,215,206,216, 395 239,222,219,207,193,218,140,133,171,153,183,132,233,138,159,174,189,171,143,128, 396 152,222,141,202,224,190,134,120,181,231,230,136,132,224,136,210,207,150,128,183, 397 221,194,179,220,126,221,137,205,223,193,172,132,226,209,133,191,227,127,159,171, 398 180,149,237,177,194,207,170,202,161,144,147,199,205,186,164,140,193,203,224,129}); 399 initActivity(intent); 400 mOrientation = BaseGridView.VERTICAL; 401 mNumRows = 3; 402 403 scrollToEnd(mVerifyLayout); 404 405 verifyBoundCount(200); 406 407 scrollToBegin(mVerifyLayout); 408 409 verifyBeginAligned(); 410 } 411 412 public void testRedundantAppendRemove2() throws Throwable { 413 mInstrumentation = getInstrumentation(); 414 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 415 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 416 R.layout.horizontal_grid_testredundantappendremove2); 417 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{ 418 318,333,199,224,246,273,269,289,340,313,265,306,349,269,185,282,257,354,316,252, 419 237,290,283,343,196,313,290,343,191,262,342,228,343,349,251,203,226,305,265,213, 420 216,333,295,188,187,281,288,311,244,232,224,332,290,181,267,276,226,261,335,355, 421 225,217,219,183,234,285,257,304,182,250,244,223,257,219,342,185,347,205,302,315, 422 299,309,292,237,192,309,228,250,347,227,337,298,299,185,185,331,223,284,265,351}); 423 initActivity(intent); 424 mOrientation = BaseGridView.HORIZONTAL; 425 mNumRows = 3; 426 mLayoutManager = (GridLayoutManager) mGridView.getLayoutManager(); 427 428 // test append without staggered result cache 429 scrollToEnd(mVerifyLayout); 430 431 verifyBoundCount(100); 432 int[] endEdges = getEndEdges(); 433 434 scrollToBegin(mVerifyLayout); 435 436 verifyBeginAligned(); 437 438 // now test append with staggered result cache 439 changeArraySize(3); 440 assertEquals("Staggerd cache should be kept as is when no item size change", 441 100, ((StaggeredGrid) mLayoutManager.mGrid).mLocations.size()); 442 443 mActivity.resetBoundCount(); 444 changeArraySize(100); 445 446 scrollToEnd(mVerifyLayout); 447 verifyBoundCount(100); 448 449 // we should get same aligned end edges 450 int[] endEdges2 = getEndEdges(); 451 verifyEdgesSame(endEdges, endEdges2); 452 } 453 454 public void testItemMovedHorizontal() throws Throwable { 455 456 mInstrumentation = getInstrumentation(); 457 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 458 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 459 R.layout.horizontal_grid); 460 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 461 initActivity(intent); 462 mOrientation = BaseGridView.HORIZONTAL; 463 mNumRows = 3; 464 465 mGridView.setSelectedPositionSmooth(150); 466 waitForScrollIdle(mVerifyLayout); 467 mActivity.swap(150, 152); 468 waitForTransientStateGone(null); 469 470 runTestOnUiThread(mVerifyLayout); 471 472 scrollToBegin(mVerifyLayout); 473 474 verifyBeginAligned(); 475 } 476 477 public void testItemMovedVertical() throws Throwable { 478 479 mInstrumentation = getInstrumentation(); 480 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 481 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 482 R.layout.vertical_grid); 483 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 484 initActivity(intent); 485 mOrientation = BaseGridView.VERTICAL; 486 mNumRows = 3; 487 488 mGridView.setSelectedPositionSmooth(150); 489 waitForScrollIdle(mVerifyLayout); 490 mActivity.swap(150, 152); 491 waitForTransientStateGone(null); 492 493 runTestOnUiThread(mVerifyLayout); 494 495 scrollToEnd(mVerifyLayout); 496 scrollToBegin(mVerifyLayout); 497 498 verifyBeginAligned(); 499 } 500 501 public void testItemAddRemoveHorizontal() throws Throwable { 502 503 mInstrumentation = getInstrumentation(); 504 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 505 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 506 R.layout.horizontal_grid); 507 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 508 initActivity(intent); 509 mOrientation = BaseGridView.HORIZONTAL; 510 mNumRows = 3; 511 512 scrollToEnd(mVerifyLayout); 513 int[] endEdges = getEndEdges(); 514 515 mGridView.setSelectedPositionSmooth(150); 516 waitForScrollIdle(mVerifyLayout); 517 int[] removedItems = mActivity.removeItems(151, 4); 518 waitForTransientStateGone(null); 519 520 scrollToEnd(mVerifyLayout); 521 mGridView.setSelectedPositionSmooth(150); 522 waitForScrollIdle(mVerifyLayout); 523 524 mActivity.addItems(151, removedItems); 525 waitForTransientStateGone(null); 526 scrollToEnd(mVerifyLayout); 527 528 // we should get same aligned end edges 529 int[] endEdges2 = getEndEdges(); 530 verifyEdgesSame(endEdges, endEdges2); 531 532 scrollToBegin(mVerifyLayout); 533 verifyBeginAligned(); 534 } 535 536 public void testFocusToFirstItem() throws Throwable { 537 538 mInstrumentation = getInstrumentation(); 539 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 540 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 541 R.layout.horizontal_grid); 542 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200); 543 initActivity(intent); 544 mOrientation = BaseGridView.HORIZONTAL; 545 mNumRows = 3; 546 547 int[] removedItems = mActivity.removeItems(0, 200); 548 549 waitForTransientStateGone(null); 550 humanDelay(500); 551 mActivity.addItems(0, removedItems); 552 553 waitForTransientStateGone(null); 554 humanDelay(500); 555 assertTrue(mGridView.getLayoutManager().findViewByPosition(0).hasFocus()); 556 557 changeArraySize(0); 558 559 changeArraySize(200); 560 assertTrue(mGridView.getLayoutManager().findViewByPosition(0).hasFocus()); 561 } 562 563 public void testNonFocusableHorizontal() throws Throwable { 564 final int numItems = 200; 565 final int startPos = 45; 566 final int skips = 20; 567 final int numColumns = 3; 568 final int endPos = startPos + numColumns * (skips + 1); 569 570 mInstrumentation = getInstrumentation(); 571 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 572 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 573 R.layout.horizontal_grid); 574 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 575 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 576 mOrientation = BaseGridView.HORIZONTAL; 577 mNumRows = numColumns; 578 boolean[] focusable = new boolean[numItems]; 579 for (int i = 0; i < focusable.length; i++) { 580 focusable[i] = true; 581 } 582 for (int i = startPos + mNumRows, j = 0; j < skips; i += mNumRows, j++) { 583 focusable[i] = false; 584 } 585 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 586 initActivity(intent); 587 588 mGridView.setSelectedPositionSmooth(startPos); 589 waitForScrollIdle(mVerifyLayout); 590 591 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 592 sendKeys(KeyEvent.KEYCODE_DPAD_LEFT); 593 } else { 594 sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT); 595 } 596 waitForScrollIdle(mVerifyLayout); 597 assertEquals(endPos, mGridView.getSelectedPosition()); 598 599 if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) { 600 sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT); 601 } else { 602 sendKeys(KeyEvent.KEYCODE_DPAD_LEFT); 603 } 604 waitForScrollIdle(mVerifyLayout); 605 assertEquals(startPos, mGridView.getSelectedPosition()); 606 607 } 608 609 610 public void testNonFocusableVertical() throws Throwable { 611 final int numItems = 200; 612 final int startPos = 44; 613 final int skips = 20; 614 final int numColumns = 3; 615 final int endPos = startPos + numColumns * (skips + 1); 616 617 mInstrumentation = getInstrumentation(); 618 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 619 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 620 R.layout.vertical_grid); 621 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 622 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 623 mOrientation = BaseGridView.VERTICAL; 624 mNumRows = numColumns; 625 boolean[] focusable = new boolean[numItems]; 626 for (int i = 0; i < focusable.length; i++) { 627 focusable[i] = true; 628 } 629 for (int i = startPos + mNumRows, j = 0; j < skips; i += mNumRows, j++) { 630 focusable[i] = false; 631 } 632 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 633 initActivity(intent); 634 635 mGridView.setSelectedPositionSmooth(startPos); 636 waitForScrollIdle(mVerifyLayout); 637 638 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 639 waitForScrollIdle(mVerifyLayout); 640 assertEquals(endPos, mGridView.getSelectedPosition()); 641 642 sendKeys(KeyEvent.KEYCODE_DPAD_UP); 643 waitForScrollIdle(mVerifyLayout); 644 assertEquals(startPos, mGridView.getSelectedPosition()); 645 646 } 647 648 public void testTransferFocusable() throws Throwable { 649 final int numItems = 200; 650 final int numColumns = 3; 651 final int startPos = 1; 652 653 mInstrumentation = getInstrumentation(); 654 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 655 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 656 R.layout.horizontal_grid); 657 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 658 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 659 mOrientation = BaseGridView.HORIZONTAL; 660 mNumRows = numColumns; 661 boolean[] focusable = new boolean[numItems]; 662 for (int i = 0; i < focusable.length; i++) { 663 focusable[i] = true; 664 } 665 for (int i = 0; i < startPos; i++) { 666 focusable[i] = false; 667 } 668 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 669 initActivity(intent); 670 671 changeArraySize(0); 672 assertTrue(mGridView.isFocused()); 673 674 changeArraySize(numItems); 675 assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus()); 676 } 677 678 public void testTransferFocusable2() throws Throwable { 679 final int numItems = 200; 680 final int numColumns = 3; 681 final int startPos = 10; 682 683 mInstrumentation = getInstrumentation(); 684 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 685 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 686 R.layout.horizontal_grid); 687 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems); 688 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 689 mOrientation = BaseGridView.HORIZONTAL; 690 mNumRows = numColumns; 691 boolean[] focusable = new boolean[numItems]; 692 for (int i = 0; i < focusable.length; i++) { 693 focusable[i] = true; 694 } 695 for (int i = 0; i < startPos; i++) { 696 focusable[i] = false; 697 } 698 intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable); 699 initActivity(intent); 700 701 changeArraySize(0); 702 assertTrue(mGridView.isFocused()); 703 704 changeArraySize(numItems); 705 assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus()); 706 } 707 708 public void testNonFocusableLoseInFastLayout() throws Throwable { 709 mInstrumentation = getInstrumentation(); 710 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 711 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 712 R.layout.vertical_linear); 713 int[] items = new int[300]; 714 for (int i = 0; i < items.length; i++) { 715 items[i] = 480; 716 } 717 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 718 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 719 intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true); 720 mOrientation = BaseGridView.VERTICAL; 721 mNumRows = 1; 722 int pressDown = 15; 723 724 initActivity(intent); 725 726 mGridView.setSelectedPositionSmooth(0); 727 waitForScrollIdle(mVerifyLayout); 728 729 for (int i = 0; i < pressDown; i++) { 730 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 731 } 732 waitForScrollIdle(mVerifyLayout); 733 assertFalse(mGridView.isFocused()); 734 735 } 736 737 public void testSetSelectionWithDelta() throws Throwable { 738 mInstrumentation = getInstrumentation(); 739 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 740 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 741 R.layout.vertical_linear); 742 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 300); 743 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 744 mOrientation = BaseGridView.VERTICAL; 745 mNumRows = 1; 746 747 initActivity(intent); 748 749 runTestOnUiThread(new Runnable() { 750 public void run() { 751 mGridView.setSelectedPositionSmooth(3); 752 } 753 }); 754 waitForScrollIdle(mVerifyLayout); 755 int top1 = mGridView.getLayoutManager().findViewByPosition(3).getTop(); 756 757 humanDelay(1000); 758 759 // scroll to position with delta 760 setSelectedPosition(3, 100); 761 int top2 = mGridView.getLayoutManager().findViewByPosition(3).getTop(); 762 assertEquals(top1 - 100, top2); 763 764 // scroll to same position without delta, it will be reset 765 setSelectedPosition(3, 0); 766 int top3 = mGridView.getLayoutManager().findViewByPosition(3).getTop(); 767 assertEquals(top1, top3); 768 769 // scroll invisible item after last visible item 770 final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 771 .mGrid.getLastVisibleIndex(); 772 setSelectedPosition(lastVisiblePos + 1, 100); 773 int top4 = mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1).getTop(); 774 assertEquals(top1 - 100, top4); 775 776 // scroll invisible item before first visible item 777 final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 778 .mGrid.getFirstVisibleIndex(); 779 setSelectedPosition(firstVisiblePos - 1, 100); 780 int top5 = mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1).getTop(); 781 assertEquals(top1 - 100, top5); 782 783 // scroll to invisible item that is far away. 784 setSelectedPosition(50, 100); 785 int top6 = mGridView.getLayoutManager().findViewByPosition(50).getTop(); 786 assertEquals(top1 - 100, top6); 787 788 // scroll to invisible item that is far away. 789 runTestOnUiThread(new Runnable() { 790 public void run() { 791 mGridView.setSelectedPositionSmooth(100); 792 } 793 }); 794 waitForScrollIdle(mVerifyLayout); 795 int top7 = mGridView.getLayoutManager().findViewByPosition(100).getTop(); 796 assertEquals(top1, top7); 797 798 // scroll to invisible item that is far away. 799 setSelectedPosition(10, 50); 800 int top8 = mGridView.getLayoutManager().findViewByPosition(10).getTop(); 801 assertEquals(top1 - 50, top8); 802 } 803 804 public void testSetSelectionWithDeltaInGrid() throws Throwable { 805 mInstrumentation = getInstrumentation(); 806 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 807 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 808 R.layout.vertical_grid); 809 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500); 810 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 811 mOrientation = BaseGridView.VERTICAL; 812 mNumRows = 3; 813 814 initActivity(intent); 815 816 runTestOnUiThread(new Runnable() { 817 public void run() { 818 mGridView.setSelectedPositionSmooth(10); 819 } 820 }); 821 waitForScrollIdle(mVerifyLayout); 822 int top1 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10)); 823 824 humanDelay(500); 825 826 // scroll to position with delta 827 setSelectedPosition(20, 100); 828 int top2 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20)); 829 assertEquals(top1 - 100, top2); 830 831 // scroll to same position without delta, it will be reset 832 setSelectedPosition(20, 0); 833 int top3 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20)); 834 assertEquals(top1, top3); 835 836 // scroll invisible item after last visible item 837 final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 838 .mGrid.getLastVisibleIndex(); 839 setSelectedPosition(lastVisiblePos + 1, 100); 840 int top4 = getCenterY(mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1)); 841 verifyMargin(); 842 assertEquals(top1 - 100, top4); 843 844 // scroll invisible item before first visible item 845 final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 846 .mGrid.getFirstVisibleIndex(); 847 setSelectedPosition(firstVisiblePos - 1, 100); 848 int top5 = getCenterY(mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1)); 849 assertEquals(top1 - 100, top5); 850 851 // scroll to invisible item that is far away. 852 setSelectedPosition(100, 100); 853 int top6 = getCenterY(mGridView.getLayoutManager().findViewByPosition(100)); 854 assertEquals(top1 - 100, top6); 855 856 // scroll to invisible item that is far away. 857 runTestOnUiThread(new Runnable() { 858 public void run() { 859 mGridView.setSelectedPositionSmooth(200); 860 } 861 }); 862 waitForScrollIdle(mVerifyLayout); 863 Thread.sleep(500); 864 int top7 = getCenterY(mGridView.getLayoutManager().findViewByPosition(200)); 865 assertEquals(top1, top7); 866 867 // scroll to invisible item that is far away. 868 setSelectedPosition(10, 50); 869 int top8 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10)); 870 assertEquals(top1 - 50, top8); 871 } 872 873 874 public void testSetSelectionWithDeltaInGrid1() throws Throwable { 875 mInstrumentation = getInstrumentation(); 876 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 877 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 878 R.layout.vertical_grid); 879 intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{ 880 193,176,153,141,203,184,232,139,177,206,222,136,132,237,172,137, 881 188,172,163,213,158,219,209,147,133,229,170,197,138,215,188,205, 882 223,192,225,170,195,127,229,229,210,195,134,142,160,139,130,222, 883 150,163,180,176,157,137,234,169,159,167,182,150,224,231,202,236, 884 123,140,181,223,120,185,183,221,123,210,134,158,166,208,149,128, 885 192,214,212,198,133,140,158,133,229,173,226,141,180,128,127,218, 886 192,235,183,213,216,150,143,193,125,141,219,210,195,195,192,191, 887 212,236,157,189,160,220,147,158,220,199,233,231,201,180,168,141, 888 156,204,191,183,190,153,123,210,238,151,139,221,223,200,175,191, 889 132,184,197,204,236,157,230,151,195,219,212,143,172,149,219,184, 890 164,211,132,187,172,142,174,146,127,147,206,238,188,129,199,226, 891 132,220,210,159,235,153,208,182,196,123,180,159,131,135,175,226, 892 127,134,237,211,133,225,132,124,160,226,224,200,173,137,217,169, 893 182,183,176,185,122,168,195,159,172,129,126,129,166,136,149,220, 894 178,191,192,238,180,208,234,154,222,206,239,228,129,140,203,125, 895 214,175,125,169,196,132,234,138,192,142,234,190,215,232,239,122, 896 188,158,128,221,159,237,207,157,232,138,132,214,122,199,121,191, 897 199,209,126,164,175,187,173,186,194,224,191,196,146,208,213,210, 898 164,176,202,213,123,157,179,138,217,129,186,166,237,211,157,130, 899 137,132,171,232,216,239,180,151,137,132,190,133,218,155,171,227, 900 193,147,197,164,120,218,193,154,170,196,138,222,161,235,143,154, 901 192,178,228,195,178,133,203,178,173,206,178,212,136,157,169,124, 902 172,121,128,223,238,125,217,187,184,156,169,215,231,124,210,174, 903 146,226,185,134,223,228,183,182,136,133,199,146,180,233,226,225, 904 174,233,145,235,216,170,192,171,132,132,134,223,233,148,154,162, 905 192,179,197,203,139,197,174,187,135,132,180,136,192,195,124,221, 906 120,189,233,233,146,225,234,163,215,143,132,198,156,205,151,190, 907 204,239,221,229,123,138,134,217,219,136,218,215,167,139,195,125, 908 202,225,178,226,145,208,130,194,228,197,157,215,124,147,174,123, 909 237,140,172,181,161,151,229,216,199,199,179,213,146,122,222,162, 910 139,173,165,150,160,217,207,137,165,175,129,158,134,133,178,199, 911 215,213,122,197 912 }); 913 intent.putExtra(GridActivity.EXTRA_STAGGERED, true); 914 mOrientation = BaseGridView.VERTICAL; 915 mNumRows = 3; 916 917 initActivity(intent); 918 919 runTestOnUiThread(new Runnable() { 920 public void run() { 921 mGridView.setSelectedPositionSmooth(10); 922 } 923 }); 924 waitForScrollIdle(mVerifyLayout); 925 int top1 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10)); 926 927 humanDelay(500); 928 929 // scroll to position with delta 930 setSelectedPosition(20, 100); 931 int top2 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20)); 932 assertEquals(top1 - 100, top2); 933 934 // scroll to same position without delta, it will be reset 935 setSelectedPosition(20, 0); 936 int top3 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20)); 937 assertEquals(top1, top3); 938 939 // scroll invisible item after last visible item 940 final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 941 .mGrid.getLastVisibleIndex(); 942 setSelectedPosition(lastVisiblePos + 1, 100); 943 int top4 = getCenterY(mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1)); 944 verifyMargin(); 945 assertEquals(top1 - 100, top4); 946 947 // scroll invisible item before first visible item 948 final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager()) 949 .mGrid.getFirstVisibleIndex(); 950 setSelectedPosition(firstVisiblePos - 1, 100); 951 int top5 = getCenterY(mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1)); 952 assertEquals(top1 - 100, top5); 953 954 // scroll to invisible item that is far away. 955 setSelectedPosition(100, 100); 956 int top6 = getCenterY(mGridView.getLayoutManager().findViewByPosition(100)); 957 assertEquals(top1 - 100, top6); 958 959 // scroll to invisible item that is far away. 960 runTestOnUiThread(new Runnable() { 961 public void run() { 962 mGridView.setSelectedPositionSmooth(200); 963 } 964 }); 965 waitForScrollIdle(mVerifyLayout); 966 Thread.sleep(500); 967 int top7 = getCenterY(mGridView.getLayoutManager().findViewByPosition(200)); 968 assertEquals(top1, top7); 969 970 // scroll to invisible item that is far away. 971 setSelectedPosition(10, 50); 972 int top8 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10)); 973 assertEquals(top1 - 50, top8); 974 } 975 976 public void testSmoothScrollSelectionEvents() throws Throwable { 977 mInstrumentation = getInstrumentation(); 978 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 979 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 980 R.layout.vertical_grid); 981 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500); 982 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 983 mOrientation = BaseGridView.VERTICAL; 984 mNumRows = 3; 985 initActivity(intent); 986 987 runTestOnUiThread(new Runnable() { 988 public void run() { 989 mGridView.setSelectedPositionSmooth(30); 990 } 991 }); 992 waitForScrollIdle(mVerifyLayout); 993 humanDelay(500); 994 995 final ArrayList<Integer> selectedPositions = new ArrayList<Integer>(); 996 mGridView.setOnChildSelectedListener(new OnChildSelectedListener() { 997 @Override 998 public void onChildSelected(ViewGroup parent, View view, int position, long id) { 999 selectedPositions.add(position); 1000 } 1001 }); 1002 1003 sendRepeatedKeys(10, KeyEvent.KEYCODE_DPAD_UP); 1004 humanDelay(500); 1005 waitForScrollIdle(mVerifyLayout); 1006 // should only get childselected event for item 0 once 1007 assertTrue(selectedPositions.size() > 0); 1008 assertEquals(0, selectedPositions.get(selectedPositions.size() - 1).intValue()); 1009 for (int i = selectedPositions.size() - 2; i >= 0; i--) { 1010 assertFalse(0 == selectedPositions.get(i).intValue()); 1011 } 1012 1013 } 1014 1015 public void testSmoothScrollSelectionEventsLinear() throws Throwable { 1016 mInstrumentation = getInstrumentation(); 1017 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1018 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1019 R.layout.vertical_linear); 1020 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500); 1021 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1022 mOrientation = BaseGridView.VERTICAL; 1023 mNumRows = 1; 1024 initActivity(intent); 1025 1026 runTestOnUiThread(new Runnable() { 1027 public void run() { 1028 mGridView.setSelectedPositionSmooth(10); 1029 } 1030 }); 1031 waitForScrollIdle(mVerifyLayout); 1032 humanDelay(500); 1033 1034 final ArrayList<Integer> selectedPositions = new ArrayList<Integer>(); 1035 mGridView.setOnChildSelectedListener(new OnChildSelectedListener() { 1036 @Override 1037 public void onChildSelected(ViewGroup parent, View view, int position, long id) { 1038 selectedPositions.add(position); 1039 } 1040 }); 1041 1042 sendRepeatedKeys(10, KeyEvent.KEYCODE_DPAD_UP); 1043 humanDelay(500); 1044 waitForScrollIdle(mVerifyLayout); 1045 // should only get childselected event for item 0 once 1046 assertTrue(selectedPositions.size() > 0); 1047 assertEquals(0, selectedPositions.get(selectedPositions.size() - 1).intValue()); 1048 for (int i = selectedPositions.size() - 2; i >= 0; i--) { 1049 assertFalse(0 == selectedPositions.get(i).intValue()); 1050 } 1051 1052 } 1053 1054 public void testScrollToNoneExisting() throws Throwable { 1055 mInstrumentation = getInstrumentation(); 1056 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1057 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1058 R.layout.vertical_grid); 1059 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100); 1060 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1061 mOrientation = BaseGridView.VERTICAL; 1062 mNumRows = 3; 1063 initActivity(intent); 1064 1065 runTestOnUiThread(new Runnable() { 1066 public void run() { 1067 mGridView.setSelectedPositionSmooth(99); 1068 } 1069 }); 1070 waitForScrollIdle(mVerifyLayout); 1071 humanDelay(500); 1072 1073 1074 runTestOnUiThread(new Runnable() { 1075 public void run() { 1076 mGridView.setSelectedPositionSmooth(50); 1077 } 1078 }); 1079 Thread.sleep(100); 1080 runTestOnUiThread(new Runnable() { 1081 public void run() { 1082 mGridView.requestLayout(); 1083 mGridView.setSelectedPositionSmooth(0); 1084 } 1085 }); 1086 waitForScrollIdle(mVerifyLayout); 1087 humanDelay(500); 1088 1089 } 1090 1091 public void testSmoothscrollerInterrupted() throws Throwable { 1092 mInstrumentation = getInstrumentation(); 1093 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1094 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1095 R.layout.vertical_linear); 1096 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 1097 int[] items = new int[100]; 1098 for (int i = 0; i < items.length; i++) { 1099 items[i] = 680; 1100 } 1101 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1102 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1103 mOrientation = BaseGridView.VERTICAL; 1104 mNumRows = 1; 1105 1106 initActivity(intent); 1107 1108 mGridView.setSelectedPositionSmooth(0); 1109 waitForScrollIdle(mVerifyLayout); 1110 assertTrue(mGridView.getChildAt(0).hasFocus()); 1111 1112 // Pressing lots of key to make sure smooth scroller is running 1113 for (int i = 0; i < 20; i++) { 1114 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 1115 } 1116 Thread.sleep(100); 1117 int total = 0; 1118 while (mGridView.getLayoutManager().isSmoothScrolling() || 1119 mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE) { 1120 if ((total += 10) >= WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS) { 1121 throw new RuntimeException("waitForScrollIdle Timeout"); 1122 } 1123 try { 1124 // Repeatedly pressing to make sure pending keys does not drop to zero. 1125 Thread.sleep(10); 1126 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 1127 } catch (InterruptedException ex) { 1128 break; 1129 } 1130 } 1131 1132 assertTrue("LinearSmoothScroller would not use many RV.smoothScrollBy() calls", 1133 ((VerticalGridViewEx) mGridView).mSmoothScrollByCalled < 10); 1134 } 1135 1136 public void testSetNumRowsAndAddItem() throws Throwable { 1137 mInstrumentation = getInstrumentation(); 1138 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1139 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1140 R.layout.vertical_linear); 1141 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 1142 int[] items = new int[2]; 1143 for (int i = 0; i < items.length; i++) { 1144 items[i] = 300; 1145 } 1146 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1147 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1148 mOrientation = BaseGridView.VERTICAL; 1149 mNumRows = 1; 1150 1151 initActivity(intent); 1152 1153 mGridView.setSelectedPositionSmooth(0); 1154 waitForScrollIdle(mVerifyLayout); 1155 1156 mActivity.addItems(items.length, new int[]{300}); 1157 1158 runTestOnUiThread(new Runnable() { 1159 public void run() { 1160 ((VerticalGridView) mGridView).setNumColumns(2); 1161 } 1162 }); 1163 Thread.sleep(1000); 1164 assertTrue(mGridView.getChildAt(2).getLeft() != mGridView.getChildAt(1).getLeft()); 1165 } 1166 1167 1168 public void testRequestLayoutBugInLayout() throws Throwable { 1169 mInstrumentation = getInstrumentation(); 1170 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1171 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1172 R.layout.vertical_linear); 1173 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout); 1174 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 1175 int[] items = new int[100]; 1176 for (int i = 0; i < items.length; i++) { 1177 items[i] = 300; 1178 } 1179 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1180 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1181 mOrientation = BaseGridView.VERTICAL; 1182 mNumRows = 1; 1183 1184 initActivity(intent); 1185 1186 runTestOnUiThread(new Runnable() { 1187 public void run() { 1188 mGridView.setSelectedPositionSmooth(1); 1189 } 1190 }); 1191 waitForScrollIdle(mVerifyLayout); 1192 1193 sendKeys(KeyEvent.KEYCODE_DPAD_UP); 1194 waitForScrollIdle(mVerifyLayout); 1195 1196 assertEquals("Line 2", ((TextView) mGridView.findFocus()).getText().toString()); 1197 } 1198 1199 1200 public void testChangeLayoutInChild() throws Throwable { 1201 mInstrumentation = getInstrumentation(); 1202 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1203 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1204 R.layout.vertical_linear_wrap_content); 1205 intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true); 1206 int[] items = new int[2]; 1207 for (int i = 0; i < items.length; i++) { 1208 items[i] = 300; 1209 } 1210 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1211 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1212 mOrientation = BaseGridView.VERTICAL; 1213 mNumRows = 1; 1214 1215 initActivity(intent); 1216 1217 runTestOnUiThread(new Runnable() { 1218 public void run() { 1219 mGridView.setSelectedPositionSmooth(0); 1220 } 1221 }); 1222 waitForScrollIdle(mVerifyLayout); 1223 verifyMargin(); 1224 1225 runTestOnUiThread(new Runnable() { 1226 public void run() { 1227 mGridView.setSelectedPositionSmooth(1); 1228 } 1229 }); 1230 waitForScrollIdle(mVerifyLayout); 1231 verifyMargin(); 1232 } 1233 1234 1235 public void testZeroFixedSecondarySize() throws Throwable { 1236 mInstrumentation = getInstrumentation(); 1237 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1238 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1239 R.layout.vertical_linear_measured_with_zero); 1240 intent.putExtra(GridActivity.EXTRA_SECONDARY_SIZE_ZERO, true); 1241 int[] items = new int[2]; 1242 for (int i = 0; i < items.length; i++) { 1243 items[i] = 0; 1244 } 1245 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1246 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1247 mOrientation = BaseGridView.VERTICAL; 1248 mNumRows = 1; 1249 1250 initActivity(intent); 1251 1252 } 1253 1254 public void testChildStates() throws Throwable { 1255 mInstrumentation = getInstrumentation(); 1256 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1257 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 1258 int[] items = new int[100]; 1259 for (int i = 0; i < items.length; i++) { 1260 items[i] = 200; 1261 } 1262 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1263 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1264 intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true); 1265 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.selectable_text_view); 1266 mOrientation = BaseGridView.VERTICAL; 1267 mNumRows = 1; 1268 1269 initActivity(intent); 1270 mGridView.setSaveChildrenPolicy(VerticalGridView.SAVE_ALL_CHILD); 1271 1272 final SparseArray<Parcelable> container = new SparseArray<Parcelable>(); 1273 1274 // 1 Save view states 1275 runTestOnUiThread(new Runnable() { 1276 public void run() { 1277 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(0)) 1278 .getText()), 0, 1); 1279 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(1)) 1280 .getText()), 0, 1); 1281 mGridView.saveHierarchyState(container); 1282 } 1283 }); 1284 1285 // 2 Change view states 1286 runTestOnUiThread(new Runnable() { 1287 public void run() { 1288 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(0)) 1289 .getText()), 1, 2); 1290 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(1)) 1291 .getText()), 1, 2); 1292 } 1293 }); 1294 1295 // 3 Detached and re-attached, should still maintain state of (2) 1296 runTestOnUiThread(new Runnable() { 1297 public void run() { 1298 mGridView.setSelectedPositionSmooth(1); 1299 } 1300 }); 1301 waitForScrollIdle(mVerifyLayout); 1302 assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionStart(), 1); 1303 assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionEnd(), 2); 1304 assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionStart(), 1); 1305 assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionEnd(), 2); 1306 1307 // 4 Recycled and rebound, should load state from (2) 1308 runTestOnUiThread(new Runnable() { 1309 public void run() { 1310 mGridView.setSelectedPositionSmooth(20); 1311 } 1312 }); 1313 waitForScrollIdle(mVerifyLayout); 1314 runTestOnUiThread(new Runnable() { 1315 public void run() { 1316 mGridView.setSelectedPositionSmooth(0); 1317 } 1318 }); 1319 waitForScrollIdle(mVerifyLayout); 1320 assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionStart(), 1); 1321 assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionEnd(), 2); 1322 assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionStart(), 1); 1323 assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionEnd(), 2); 1324 } 1325 1326 1327 public void testNoDispatchSaveChildState() throws Throwable { 1328 mInstrumentation = getInstrumentation(); 1329 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1330 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 1331 int[] items = new int[100]; 1332 for (int i = 0; i < items.length; i++) { 1333 items[i] = 200; 1334 } 1335 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1336 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1337 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.selectable_text_view); 1338 mOrientation = BaseGridView.VERTICAL; 1339 mNumRows = 1; 1340 1341 initActivity(intent); 1342 mGridView.setSaveChildrenPolicy(VerticalGridView.SAVE_NO_CHILD); 1343 1344 final SparseArray<Parcelable> container = new SparseArray<Parcelable>(); 1345 1346 // 1. Set text selection, save view states should do nothing on child 1347 runTestOnUiThread(new Runnable() { 1348 public void run() { 1349 for (int i = 0; i < mGridView.getChildCount(); i++) { 1350 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(i)) 1351 .getText()), 0, 1); 1352 } 1353 mGridView.saveHierarchyState(container); 1354 } 1355 }); 1356 1357 // 2. clear the text selection 1358 runTestOnUiThread(new Runnable() { 1359 public void run() { 1360 for (int i = 0; i < mGridView.getChildCount(); i++) { 1361 Selection.removeSelection((Spannable)(((TextView) mGridView.getChildAt(i)) 1362 .getText())); 1363 } 1364 } 1365 }); 1366 1367 // 3. Restore view states should be a no-op for child 1368 runTestOnUiThread(new Runnable() { 1369 public void run() { 1370 mGridView.restoreHierarchyState(container); 1371 for (int i = 0; i < mGridView.getChildCount(); i++) { 1372 assertEquals(-1, ((TextView) mGridView.getChildAt(i)).getSelectionStart()); 1373 assertEquals(-1, ((TextView) mGridView.getChildAt(i)).getSelectionEnd()); 1374 } 1375 } 1376 }); 1377 } 1378 1379 1380 static interface ViewTypeProvider { 1381 public int getViewType(int position); 1382 } 1383 1384 static interface ItemAlignmentFacetProvider { 1385 public ItemAlignmentFacet getItemAlignmentFacet(int viewType); 1386 } 1387 1388 static class TwoViewTypesProvider implements ViewTypeProvider { 1389 static int VIEW_TYPE_FIRST = 1; 1390 static int VIEW_TYPE_DEFAULT = 0; 1391 @Override 1392 public int getViewType(int position) { 1393 if (position == 0) { 1394 return VIEW_TYPE_FIRST; 1395 } else { 1396 return VIEW_TYPE_DEFAULT; 1397 } 1398 } 1399 } 1400 1401 static class PositionItemAlignmentFacetProviderForRelativeLayout1 1402 implements ItemAlignmentFacetProvider { 1403 ItemAlignmentFacet mMultipleFacet; 1404 1405 PositionItemAlignmentFacetProviderForRelativeLayout1() { 1406 mMultipleFacet = new ItemAlignmentFacet(); 1407 ItemAlignmentFacet.ItemAlignmentDef[] defs = 1408 new ItemAlignmentFacet.ItemAlignmentDef[2]; 1409 defs[0] = new ItemAlignmentFacet.ItemAlignmentDef(); 1410 defs[0].setItemAlignmentViewId(R.id.t1); 1411 defs[1] = new ItemAlignmentFacet.ItemAlignmentDef(); 1412 defs[1].setItemAlignmentViewId(R.id.t2); 1413 defs[1].setItemAlignmentOffsetPercent(100); 1414 defs[1].setItemAlignmentOffset(-10); 1415 mMultipleFacet.setAlignmentDefs(defs); 1416 } 1417 1418 @Override 1419 public ItemAlignmentFacet getItemAlignmentFacet(int position) { 1420 if (position == 0) { 1421 return mMultipleFacet; 1422 } else { 1423 return null; 1424 } 1425 } 1426 } 1427 1428 public void testMultipleScrollPosition1() throws Throwable { 1429 mInstrumentation = getInstrumentation(); 1430 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1431 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1432 R.layout.vertical_linear); 1433 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout); 1434 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 1435 int[] items = new int[100]; 1436 for (int i = 0; i < items.length; i++) { 1437 items[i] = 300; 1438 } 1439 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1440 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1441 intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS, 1442 TwoViewTypesProvider.class.getName()); 1443 // Set ItemAlignment for each ViewHolder and view type, ViewHolder should 1444 // override the view type settings. 1445 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS, 1446 PositionItemAlignmentFacetProviderForRelativeLayout1.class.getName()); 1447 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_VIEWTYPE_CLASS, 1448 ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2.class.getName()); 1449 mOrientation = BaseGridView.VERTICAL; 1450 mNumRows = 1; 1451 1452 initActivity(intent); 1453 1454 assertEquals("First view is aligned with padding top", 1455 mGridView.getPaddingTop(), mGridView.getChildAt(0).getTop()); 1456 1457 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 1458 waitForScrollIdle(mVerifyLayout); 1459 1460 final View v = mGridView.getChildAt(0); 1461 View t1 = v.findViewById(R.id.t1); 1462 int t1align = (t1.getTop() + t1.getBottom()) / 2; 1463 View t2 = v.findViewById(R.id.t2); 1464 int t2align = t2.getBottom() - 10; 1465 assertEquals("Expected alignment for 2nd textview", 1466 mGridView.getPaddingTop() - (t2align - t1align), 1467 v.getTop()); 1468 } 1469 1470 static class PositionItemAlignmentFacetProviderForRelativeLayout2 implements 1471 ItemAlignmentFacetProvider { 1472 ItemAlignmentFacet mMultipleFacet; 1473 1474 PositionItemAlignmentFacetProviderForRelativeLayout2() { 1475 mMultipleFacet = new ItemAlignmentFacet(); 1476 ItemAlignmentFacet.ItemAlignmentDef[] defs = new ItemAlignmentFacet.ItemAlignmentDef[2]; 1477 defs[0] = new ItemAlignmentFacet.ItemAlignmentDef(); 1478 defs[0].setItemAlignmentViewId(R.id.t1); 1479 defs[0].setItemAlignmentOffsetPercent(0); 1480 defs[1] = new ItemAlignmentFacet.ItemAlignmentDef(); 1481 defs[1].setItemAlignmentViewId(R.id.t2); 1482 defs[1].setItemAlignmentOffsetPercent(ItemAlignmentFacet.ITEM_ALIGN_OFFSET_PERCENT_DISABLED); 1483 defs[1].setItemAlignmentOffset(-10); 1484 mMultipleFacet.setAlignmentDefs(defs); 1485 } 1486 1487 @Override 1488 public ItemAlignmentFacet getItemAlignmentFacet(int position) { 1489 if (position == 0) { 1490 return mMultipleFacet; 1491 } else { 1492 return null; 1493 } 1494 } 1495 } 1496 1497 public void testMultipleScrollPosition2() throws Throwable { 1498 mInstrumentation = getInstrumentation(); 1499 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1500 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 1501 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout); 1502 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 1503 int[] items = new int[100]; 1504 for (int i = 0; i < items.length; i++) { 1505 items[i] = 300; 1506 } 1507 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1508 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1509 intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS, 1510 TwoViewTypesProvider.class.getName()); 1511 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS, 1512 PositionItemAlignmentFacetProviderForRelativeLayout2.class.getName()); 1513 mOrientation = BaseGridView.VERTICAL; 1514 mNumRows = 1; 1515 1516 initActivity(intent); 1517 1518 assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(), 1519 mGridView.getChildAt(0).getTop()); 1520 1521 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 1522 waitForScrollIdle(mVerifyLayout); 1523 1524 final View v = mGridView.getChildAt(0); 1525 View t1 = v.findViewById(R.id.t1); 1526 int t1align = t1.getTop(); 1527 View t2 = v.findViewById(R.id.t2); 1528 int t2align = t2.getTop() - 10; 1529 assertEquals("Expected alignment for 2nd textview", 1530 mGridView.getPaddingTop() - (t2align - t1align), v.getTop()); 1531 } 1532 1533 static class ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2 implements 1534 ItemAlignmentFacetProvider { 1535 ItemAlignmentFacet mMultipleFacet; 1536 1537 ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2() { 1538 mMultipleFacet = new ItemAlignmentFacet(); 1539 ItemAlignmentFacet.ItemAlignmentDef[] defs = new ItemAlignmentFacet.ItemAlignmentDef[2]; 1540 defs[0] = new ItemAlignmentFacet.ItemAlignmentDef(); 1541 defs[0].setItemAlignmentViewId(R.id.t1); 1542 defs[0].setItemAlignmentOffsetPercent(0); 1543 defs[1] = new ItemAlignmentFacet.ItemAlignmentDef(); 1544 defs[1].setItemAlignmentViewId(R.id.t2); 1545 defs[1].setItemAlignmentOffsetPercent(100); 1546 defs[1].setItemAlignmentOffset(-10); 1547 mMultipleFacet.setAlignmentDefs(defs); 1548 } 1549 1550 @Override 1551 public ItemAlignmentFacet getItemAlignmentFacet(int viewType) { 1552 if (viewType == TwoViewTypesProvider.VIEW_TYPE_FIRST) { 1553 return mMultipleFacet; 1554 } else { 1555 return null; 1556 } 1557 } 1558 } 1559 1560 public void testMultipleScrollPosition3() throws Throwable { 1561 mInstrumentation = getInstrumentation(); 1562 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1563 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear); 1564 intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout); 1565 intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true); 1566 int[] items = new int[100]; 1567 for (int i = 0; i < items.length; i++) { 1568 items[i] = 300; 1569 } 1570 intent.putExtra(GridActivity.EXTRA_ITEMS, items); 1571 intent.putExtra(GridActivity.EXTRA_STAGGERED, false); 1572 intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS, 1573 TwoViewTypesProvider.class.getName()); 1574 intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_VIEWTYPE_CLASS, 1575 ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2.class.getName()); 1576 mOrientation = BaseGridView.VERTICAL; 1577 mNumRows = 1; 1578 1579 initActivity(intent); 1580 1581 assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(), 1582 mGridView.getChildAt(0).getTop()); 1583 1584 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 1585 waitForScrollIdle(mVerifyLayout); 1586 1587 final View v = mGridView.getChildAt(0); 1588 View t1 = v.findViewById(R.id.t1); 1589 int t1align = t1.getTop(); 1590 View t2 = v.findViewById(R.id.t2); 1591 int t2align = t2.getBottom() - 10; 1592 assertEquals("Expected alignment for 2nd textview", 1593 mGridView.getPaddingTop() - (t2align - t1align), v.getTop()); 1594 } 1595 1596 public void testSelectionAndAddItemInOneCycle() throws Throwable { 1597 mInstrumentation = getInstrumentation(); 1598 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1599 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1600 R.layout.vertical_linear); 1601 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0); 1602 initActivity(intent); 1603 mOrientation = BaseGridView.HORIZONTAL; 1604 mNumRows = 1; 1605 1606 runTestOnUiThread(new Runnable() { 1607 public void run() { 1608 mActivity.addItems(0, new int[]{300, 300}); 1609 mGridView.setSelectedPosition(0); 1610 } 1611 }); 1612 waitForTransientStateGone(null); 1613 assertEquals(0, mGridView.getSelectedPosition()); 1614 } 1615 1616 public void testSelectionSmoothAndAddItemInOneCycle() throws Throwable { 1617 mInstrumentation = getInstrumentation(); 1618 Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class); 1619 intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, 1620 R.layout.vertical_linear); 1621 intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0); 1622 initActivity(intent); 1623 mOrientation = BaseGridView.HORIZONTAL; 1624 mNumRows = 1; 1625 1626 runTestOnUiThread(new Runnable() { 1627 public void run() { 1628 mActivity.addItems(0, new int[]{300, 300}); 1629 mGridView.setSelectedPositionSmooth(0); 1630 } 1631 }); 1632 waitForTransientStateGone(null); 1633 assertEquals(0, mGridView.getSelectedPosition()); 1634 } 1635} 1636