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