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