1 // CHECKSTYLE:OFF Generated code 2 /* This file is auto-generated from RowsSupportFragmentTest.java. DO NOT MODIFY. */ 3 4 /* 5 * Copyright (C) 2016 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 package androidx.leanback.app; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertFalse; 23 import static org.junit.Assert.assertNotNull; 24 import static org.junit.Assert.assertNotSame; 25 import static org.junit.Assert.assertNull; 26 import static org.junit.Assert.assertSame; 27 import static org.junit.Assert.assertTrue; 28 29 import android.app.Fragment; 30 import android.graphics.Rect; 31 import android.os.Build; 32 import android.os.Bundle; 33 import android.os.Handler; 34 import android.os.SystemClock; 35 import android.support.test.InstrumentationRegistry; 36 import android.support.test.filters.LargeTest; 37 import android.support.test.filters.SdkSuppress; 38 import android.support.test.runner.AndroidJUnit4; 39 import android.view.KeyEvent; 40 import android.view.LayoutInflater; 41 import android.view.View; 42 import android.view.ViewGroup; 43 import android.widget.TextView; 44 45 import androidx.leanback.test.R; 46 import androidx.leanback.testutils.PollingCheck; 47 import androidx.leanback.widget.ArrayObjectAdapter; 48 import androidx.leanback.widget.HeaderItem; 49 import androidx.leanback.widget.HorizontalGridView; 50 import androidx.leanback.widget.ItemBridgeAdapter; 51 import androidx.leanback.widget.ListRow; 52 import androidx.leanback.widget.ListRowPresenter; 53 import androidx.leanback.widget.ObjectAdapter; 54 import androidx.leanback.widget.OnItemViewClickedListener; 55 import androidx.leanback.widget.PageRow; 56 import androidx.leanback.widget.Presenter; 57 import androidx.leanback.widget.Row; 58 import androidx.leanback.widget.RowPresenter; 59 import androidx.leanback.widget.SinglePresenterSelector; 60 import androidx.leanback.widget.VerticalGridView; 61 62 import org.junit.Test; 63 import org.junit.runner.RunWith; 64 65 import java.lang.ref.WeakReference; 66 import java.util.ArrayList; 67 import java.util.List; 68 69 @LargeTest 70 @RunWith(AndroidJUnit4.class) 71 public class RowsFragmentTest extends SingleFragmentTestBase { 72 73 static final StringPresenter sCardPresenter = new StringPresenter(); 74 75 static void loadData(ArrayObjectAdapter adapter, int numRows, int repeatPerRow) { 76 for (int i = 0; i < numRows; ++i) { 77 ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(sCardPresenter); 78 int index = 0; 79 for (int j = 0; j < repeatPerRow; ++j) { 80 listRowAdapter.add("Hello world-" + (index++)); 81 listRowAdapter.add("This is a test-" + (index++)); 82 listRowAdapter.add("Android TV-" + (index++)); 83 listRowAdapter.add("Leanback-" + (index++)); 84 listRowAdapter.add("Hello world-" + (index++)); 85 listRowAdapter.add("Android TV-" + (index++)); 86 listRowAdapter.add("Leanback-" + (index++)); 87 listRowAdapter.add("GuidedStepFragment-" + (index++)); 88 } 89 HeaderItem header = new HeaderItem(i, "Row " + i); 90 adapter.add(new ListRow(header, listRowAdapter)); 91 } 92 } 93 94 static Bundle saveActivityState(final SingleFragmentTestActivity activity) { 95 final Bundle[] savedState = new Bundle[1]; 96 // save activity state 97 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 98 @Override 99 public void run() { 100 savedState[0] = activity.performSaveInstanceState(); 101 } 102 }); 103 return savedState[0]; 104 } 105 106 static void waitForHeaderTransition(final F_Base fragment) { 107 // Wait header transition finishes 108 SystemClock.sleep(100); 109 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 110 @Override 111 public boolean canProceed() { 112 return !fragment.isInHeadersTransition(); 113 } 114 }); 115 } 116 117 static void selectAndWaitFragmentAnimation(final F_Base fragment, final int row, 118 final int item) { 119 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 120 @Override 121 public void run() { 122 fragment.setSelectedPosition(row, true, 123 new ListRowPresenter.SelectItemViewHolderTask(item)); 124 } 125 }); 126 // Wait header transition finishes and scrolling stops 127 SystemClock.sleep(100); 128 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 129 @Override 130 public boolean canProceed() { 131 return !fragment.isInHeadersTransition() 132 && !fragment.getHeadersFragment().isScrolling(); 133 } 134 }); 135 } 136 137 public static class F_defaultAlignment extends RowsFragment { 138 @Override 139 public void onCreate(Bundle savedInstanceState) { 140 super.onCreate(savedInstanceState); 141 ListRowPresenter lrp = new ListRowPresenter(); 142 ArrayObjectAdapter adapter = new ArrayObjectAdapter(lrp); 143 setAdapter(adapter); 144 loadData(adapter, 10, 1); 145 } 146 } 147 148 @Test 149 public void defaultAlignment() throws Throwable { 150 SingleFragmentTestActivity activity = launchAndWaitActivity(F_defaultAlignment.class, 1000); 151 152 final Rect rect = new Rect(); 153 154 final VerticalGridView gridView = ((RowsFragment) activity.getTestFragment()) 155 .getVerticalGridView(); 156 View row0 = gridView.findViewHolderForAdapterPosition(0).itemView; 157 rect.set(0, 0, row0.getWidth(), row0.getHeight()); 158 gridView.offsetDescendantRectToMyCoords(row0, rect); 159 assertEquals("First row is initially aligned to top of screen", 0, rect.top); 160 161 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 162 waitForScrollIdle(gridView); 163 View row1 = gridView.findViewHolderForAdapterPosition(1).itemView; 164 PollingCheck.waitFor(new PollingCheck.ViewStableOnScreen(row1)); 165 166 rect.set(0, 0, row1.getWidth(), row1.getHeight()); 167 gridView.offsetDescendantRectToMyCoords(row1, rect); 168 assertTrue("Second row should not be aligned to top of screen", rect.top > 0); 169 } 170 171 public static class F_selectBeforeSetAdapter extends RowsFragment { 172 @Override 173 public void onCreate(Bundle savedInstanceState) { 174 super.onCreate(savedInstanceState); 175 setSelectedPosition(7, false); 176 new Handler().postDelayed(new Runnable() { 177 @Override 178 public void run() { 179 getVerticalGridView().requestLayout(); 180 } 181 }, 100); 182 new Handler().postDelayed(new Runnable() { 183 @Override 184 public void run() { 185 ListRowPresenter lrp = new ListRowPresenter(); 186 ArrayObjectAdapter adapter = new ArrayObjectAdapter(lrp); 187 setAdapter(adapter); 188 loadData(adapter, 10, 1); 189 } 190 }, 1000); 191 } 192 } 193 194 @Test 195 public void selectBeforeSetAdapter() throws InterruptedException { 196 SingleFragmentTestActivity activity = 197 launchAndWaitActivity(F_selectBeforeSetAdapter.class, 2000); 198 199 final VerticalGridView gridView = ((RowsFragment) activity.getTestFragment()) 200 .getVerticalGridView(); 201 assertEquals(7, gridView.getSelectedPosition()); 202 assertNotNull(gridView.findViewHolderForAdapterPosition(7)); 203 } 204 205 public static class F_selectBeforeAddData extends RowsFragment { 206 @Override 207 public void onCreate(Bundle savedInstanceState) { 208 super.onCreate(savedInstanceState); 209 ListRowPresenter lrp = new ListRowPresenter(); 210 final ArrayObjectAdapter adapter = new ArrayObjectAdapter(lrp); 211 setAdapter(adapter); 212 setSelectedPosition(7, false); 213 new Handler().postDelayed(new Runnable() { 214 @Override 215 public void run() { 216 getVerticalGridView().requestLayout(); 217 } 218 }, 100); 219 new Handler().postDelayed(new Runnable() { 220 @Override 221 public void run() { 222 loadData(adapter, 10, 1); 223 } 224 }, 1000); 225 } 226 } 227 228 @Test 229 public void selectBeforeAddData() throws InterruptedException { 230 SingleFragmentTestActivity activity = 231 launchAndWaitActivity(F_selectBeforeAddData.class, 2000); 232 233 final VerticalGridView gridView = ((RowsFragment) activity.getTestFragment()) 234 .getVerticalGridView(); 235 assertEquals(7, gridView.getSelectedPosition()); 236 assertNotNull(gridView.findViewHolderForAdapterPosition(7)); 237 } 238 239 public static class F_selectAfterAddData extends RowsFragment { 240 @Override 241 public void onCreate(Bundle savedInstanceState) { 242 super.onCreate(savedInstanceState); 243 ListRowPresenter lrp = new ListRowPresenter(); 244 final ArrayObjectAdapter adapter = new ArrayObjectAdapter(lrp); 245 setAdapter(adapter); 246 loadData(adapter, 10, 1); 247 new Handler().postDelayed(new Runnable() { 248 @Override 249 public void run() { 250 setSelectedPosition(7, false); 251 } 252 }, 1000); 253 } 254 } 255 256 @Test 257 public void selectAfterAddData() throws InterruptedException { 258 SingleFragmentTestActivity activity = 259 launchAndWaitActivity(F_selectAfterAddData.class, 2000); 260 261 final VerticalGridView gridView = ((RowsFragment) activity.getTestFragment()) 262 .getVerticalGridView(); 263 assertEquals(7, gridView.getSelectedPosition()); 264 assertNotNull(gridView.findViewHolderForAdapterPosition(7)); 265 } 266 267 static WeakReference<F_restoreSelection> sLastF_restoreSelection; 268 269 public static class F_restoreSelection extends RowsFragment { 270 public F_restoreSelection() { 271 sLastF_restoreSelection = new WeakReference<F_restoreSelection>(this); 272 } 273 274 @Override 275 public void onCreate(Bundle savedInstanceState) { 276 super.onCreate(savedInstanceState); 277 ListRowPresenter lrp = new ListRowPresenter(); 278 final ArrayObjectAdapter adapter = new ArrayObjectAdapter(lrp); 279 setAdapter(adapter); 280 loadData(adapter, 10, 1); 281 if (savedInstanceState == null) { 282 setSelectedPosition(7, false); 283 } 284 } 285 } 286 287 @Test 288 public void restoreSelection() { 289 final SingleFragmentTestActivity activity = 290 launchAndWaitActivity(F_restoreSelection.class, 1000); 291 292 InstrumentationRegistry.getInstrumentation().runOnMainSync( 293 new Runnable() { 294 @Override 295 public void run() { 296 activity.recreate(); 297 } 298 } 299 ); 300 SystemClock.sleep(1000); 301 302 // mActivity is invalid after recreate(), a new Activity instance is created 303 // but we could get Fragment from static variable. 304 RowsFragment fragment = sLastF_restoreSelection.get(); 305 final VerticalGridView gridView = fragment.getVerticalGridView(); 306 assertEquals(7, gridView.getSelectedPosition()); 307 assertNotNull(gridView.findViewHolderForAdapterPosition(7)); 308 309 } 310 311 public static class F_ListRowWithOnClick extends RowsFragment { 312 Presenter.ViewHolder mLastClickedItemViewHolder; 313 @Override 314 public void onCreate(Bundle savedInstanceState) { 315 super.onCreate(savedInstanceState); 316 setOnItemViewClickedListener(new OnItemViewClickedListener() { 317 @Override 318 public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, 319 RowPresenter.ViewHolder rowViewHolder, Row row) { 320 mLastClickedItemViewHolder = itemViewHolder; 321 } 322 }); 323 ListRowPresenter lrp = new ListRowPresenter(); 324 ArrayObjectAdapter adapter = new ArrayObjectAdapter(lrp); 325 setAdapter(adapter); 326 loadData(adapter, 10, 1); 327 } 328 } 329 330 @Test 331 public void prefetchChildItemsBeforeAttach() throws Throwable { 332 SingleFragmentTestActivity activity = 333 launchAndWaitActivity(F_ListRowWithOnClick.class, 1000); 334 335 F_ListRowWithOnClick fragment = (F_ListRowWithOnClick) activity.getTestFragment(); 336 final VerticalGridView gridView = fragment.getVerticalGridView(); 337 View lastRow = gridView.getChildAt(gridView.getChildCount() - 1); 338 final int lastRowPos = gridView.getChildAdapterPosition(lastRow); 339 InstrumentationRegistry.getInstrumentation().runOnMainSync( 340 new Runnable() { 341 public void run() { 342 gridView.setSelectedPositionSmooth(lastRowPos); 343 } 344 } 345 ); 346 waitForScrollIdle(gridView); 347 ItemBridgeAdapter.ViewHolder prefetchedBridgeVh = (ItemBridgeAdapter.ViewHolder) 348 gridView.findViewHolderForAdapterPosition(lastRowPos + 1); 349 RowPresenter prefetchedRowPresenter = (RowPresenter) prefetchedBridgeVh.getPresenter(); 350 final ListRowPresenter.ViewHolder prefetchedListRowVh = (ListRowPresenter.ViewHolder) 351 prefetchedRowPresenter.getRowViewHolder(prefetchedBridgeVh.getViewHolder()); 352 353 fragment.mLastClickedItemViewHolder = null; 354 InstrumentationRegistry.getInstrumentation().runOnMainSync( 355 new Runnable() { 356 public void run() { 357 prefetchedListRowVh.getItemViewHolder(0).view.performClick(); 358 } 359 } 360 ); 361 assertSame(prefetchedListRowVh.getItemViewHolder(0), fragment.mLastClickedItemViewHolder); 362 } 363 364 @Test 365 public void changeHasStableIdToTrueAfterViewCreated() throws InterruptedException { 366 SingleFragmentTestActivity activity = 367 launchAndWaitActivity(RowsFragment.class, 2000); 368 final RowsFragment fragment = (RowsFragment) activity.getTestFragment(); 369 370 InstrumentationRegistry.getInstrumentation().runOnMainSync( 371 new Runnable() { 372 public void run() { 373 ObjectAdapter adapter = new ObjectAdapter() { 374 @Override 375 public int size() { 376 return 0; 377 } 378 379 @Override 380 public Object get(int position) { 381 return null; 382 } 383 384 @Override 385 public long getId(int position) { 386 return 1; 387 } 388 }; 389 adapter.setHasStableIds(true); 390 fragment.setAdapter(adapter); 391 } 392 } 393 ); 394 } 395 396 static class StableIdAdapter extends ObjectAdapter { 397 ArrayList<Integer> mList = new ArrayList(); 398 399 @Override 400 public long getId(int position) { 401 return mList.get(position).longValue(); 402 } 403 404 @Override 405 public Object get(int position) { 406 return mList.get(position); 407 } 408 409 @Override 410 public int size() { 411 return mList.size(); 412 } 413 } 414 415 public static class F_rowNotifyItemRangeChange extends BrowseFragment { 416 417 @Override 418 public void onCreate(Bundle savedInstanceState) { 419 super.onCreate(savedInstanceState); 420 ListRowPresenter lrp = new ListRowPresenter(); 421 final ArrayObjectAdapter adapter = new ArrayObjectAdapter(lrp); 422 for (int i = 0; i < 2; i++) { 423 StableIdAdapter listRowAdapter = new StableIdAdapter(); 424 listRowAdapter.setHasStableIds(true); 425 listRowAdapter.setPresenterSelector( 426 new SinglePresenterSelector(sCardPresenter)); 427 int index = 0; 428 listRowAdapter.mList.add(index++); 429 listRowAdapter.mList.add(index++); 430 listRowAdapter.mList.add(index++); 431 HeaderItem header = new HeaderItem(i, "Row " + i); 432 adapter.add(new ListRow(header, listRowAdapter)); 433 } 434 setAdapter(adapter); 435 new Handler().postDelayed(new Runnable() { 436 @Override 437 public void run() { 438 StableIdAdapter rowAdapter = (StableIdAdapter) 439 ((ListRow) adapter.get(1)).getAdapter(); 440 rowAdapter.notifyItemRangeChanged(0, 3); 441 } 442 }, 500); 443 } 444 } 445 446 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 447 @Test 448 public void rowNotifyItemRangeChange() throws InterruptedException { 449 SingleFragmentTestActivity activity = launchAndWaitActivity( 450 RowsFragmentTest.F_rowNotifyItemRangeChange.class, 2000); 451 452 VerticalGridView verticalGridView = ((BrowseFragment) activity.getTestFragment()) 453 .getRowsFragment().getVerticalGridView(); 454 for (int i = 0; i < verticalGridView.getChildCount(); i++) { 455 HorizontalGridView horizontalGridView = verticalGridView.getChildAt(i) 456 .findViewById(R.id.row_content); 457 for (int j = 0; j < horizontalGridView.getChildCount(); j++) { 458 assertEquals(horizontalGridView.getPaddingTop(), 459 horizontalGridView.getChildAt(j).getTop()); 460 } 461 } 462 } 463 464 public static class F_rowNotifyItemRangeChangeWithTransition extends BrowseFragment { 465 466 @Override 467 public void onCreate(Bundle savedInstanceState) { 468 super.onCreate(savedInstanceState); 469 ListRowPresenter lrp = new ListRowPresenter(); 470 prepareEntranceTransition(); 471 final ArrayObjectAdapter adapter = new ArrayObjectAdapter(lrp); 472 for (int i = 0; i < 2; i++) { 473 StableIdAdapter listRowAdapter = new StableIdAdapter(); 474 listRowAdapter.setHasStableIds(true); 475 listRowAdapter.setPresenterSelector( 476 new SinglePresenterSelector(sCardPresenter)); 477 int index = 0; 478 listRowAdapter.mList.add(index++); 479 listRowAdapter.mList.add(index++); 480 listRowAdapter.mList.add(index++); 481 HeaderItem header = new HeaderItem(i, "Row " + i); 482 adapter.add(new ListRow(header, listRowAdapter)); 483 } 484 setAdapter(adapter); 485 new Handler().postDelayed(new Runnable() { 486 @Override 487 public void run() { 488 StableIdAdapter rowAdapter = (StableIdAdapter) 489 ((ListRow) adapter.get(1)).getAdapter(); 490 rowAdapter.notifyItemRangeChanged(0, 3); 491 } 492 }, 500); 493 new Handler().postDelayed(new Runnable() { 494 @Override 495 public void run() { 496 startEntranceTransition(); 497 } 498 }, 520); 499 } 500 } 501 502 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 503 @Test 504 public void rowNotifyItemRangeChangeWithTransition() throws InterruptedException { 505 SingleFragmentTestActivity activity = launchAndWaitActivity( 506 RowsFragmentTest.F_rowNotifyItemRangeChangeWithTransition.class, 3000); 507 508 VerticalGridView verticalGridView = ((BrowseFragment) activity.getTestFragment()) 509 .getRowsFragment().getVerticalGridView(); 510 for (int i = 0; i < verticalGridView.getChildCount(); i++) { 511 HorizontalGridView horizontalGridView = verticalGridView.getChildAt(i) 512 .findViewById(R.id.row_content); 513 for (int j = 0; j < horizontalGridView.getChildCount(); j++) { 514 assertEquals(horizontalGridView.getPaddingTop(), 515 horizontalGridView.getChildAt(j).getTop()); 516 assertEquals(0, horizontalGridView.getChildAt(j).getTranslationY(), 0.1f); 517 } 518 } 519 } 520 521 public static class F_Base extends BrowseFragment { 522 523 List<Long> mEntranceTransitionStartTS = new ArrayList(); 524 List<Long> mEntranceTransitionEndTS = new ArrayList(); 525 526 @Override 527 protected void onEntranceTransitionStart() { 528 super.onEntranceTransitionStart(); 529 mEntranceTransitionStartTS.add(SystemClock.uptimeMillis()); 530 } 531 532 @Override 533 protected void onEntranceTransitionEnd() { 534 super.onEntranceTransitionEnd(); 535 mEntranceTransitionEndTS.add(SystemClock.uptimeMillis()); 536 } 537 538 public void assertExecutedEntranceTransition() { 539 assertEquals(1, mEntranceTransitionStartTS.size()); 540 assertEquals(1, mEntranceTransitionEndTS.size()); 541 assertTrue(mEntranceTransitionEndTS.get(0) - mEntranceTransitionStartTS.get(0) > 100); 542 } 543 544 public void assertNoEntranceTransition() { 545 assertEquals(0, mEntranceTransitionStartTS.size()); 546 assertEquals(0, mEntranceTransitionEndTS.size()); 547 } 548 549 /** 550 * Util to wait PageFragment swapped. 551 */ 552 Fragment waitPageFragment(final Class pageFragmentClass) { 553 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 554 @Override 555 public boolean canProceed() { 556 return pageFragmentClass.isInstance(getMainFragment()) 557 && getMainFragment().getView() != null; 558 } 559 }); 560 return getMainFragment(); 561 } 562 563 /** 564 * Wait until a fragment for non-page Row is created. Does not apply to the case a 565 * RowsFragment is created on a PageRow. 566 */ 567 RowsFragment waitRowsFragment() { 568 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 569 @Override 570 public boolean canProceed() { 571 return mMainFragmentListRowDataAdapter != null 572 && getMainFragment() instanceof RowsFragment 573 && !(getMainFragment() instanceof SampleRowsFragment); 574 } 575 }); 576 return (RowsFragment) getMainFragment(); 577 } 578 } 579 580 static ObjectAdapter createListRowAdapter() { 581 StableIdAdapter listRowAdapter = new StableIdAdapter(); 582 listRowAdapter.setHasStableIds(false); 583 listRowAdapter.setPresenterSelector( 584 new SinglePresenterSelector(sCardPresenter)); 585 int index = 0; 586 listRowAdapter.mList.add(index++); 587 listRowAdapter.mList.add(index++); 588 listRowAdapter.mList.add(index++); 589 return listRowAdapter; 590 } 591 592 /** 593 * Create BrowseFragmentAdapter with 3 ListRows 594 */ 595 static ArrayObjectAdapter createListRowsAdapter() { 596 ListRowPresenter lrp = new ListRowPresenter(); 597 final ArrayObjectAdapter adapter = new ArrayObjectAdapter(lrp); 598 for (int i = 0; i < 3; i++) { 599 ObjectAdapter listRowAdapter = createListRowAdapter(); 600 HeaderItem header = new HeaderItem(i, "Row " + i); 601 adapter.add(new ListRow(header, listRowAdapter)); 602 } 603 return adapter; 604 } 605 606 /** 607 * A typical BrowseFragment with multiple rows that start entrance transition 608 */ 609 public static class F_standard extends F_Base { 610 @Override 611 public void onCreate(Bundle savedInstanceState) { 612 super.onCreate(savedInstanceState); 613 if (savedInstanceState == null) { 614 prepareEntranceTransition(); 615 } 616 new Handler().postDelayed(new Runnable() { 617 @Override 618 public void run() { 619 setAdapter(createListRowsAdapter()); 620 startEntranceTransition(); 621 } 622 }, 100); 623 } 624 } 625 626 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 627 @Test 628 public void browseFragmentSetNullAdapter() throws InterruptedException { 629 final SingleFragmentTestActivity activity = launchAndWaitActivity( 630 RowsFragmentTest.F_standard.class, 2000); 631 final F_standard fragment = ((F_standard) activity.getTestFragment()); 632 fragment.assertExecutedEntranceTransition(); 633 634 final ObjectAdapter adapter1 = fragment.getAdapter(); 635 ListRowDataAdapter wrappedAdapter = fragment.mMainFragmentListRowDataAdapter; 636 assertTrue(adapter1.hasObserver()); 637 assertTrue(wrappedAdapter.hasObserver()); 638 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 639 @Override 640 public void run() { 641 fragment.setAdapter(null); 642 } 643 }); 644 // adapter should no longer has observer and there is no reference to adapter from 645 // BrowseFragment. 646 assertFalse(adapter1.hasObserver()); 647 assertFalse(wrappedAdapter.hasObserver()); 648 assertNull(fragment.getAdapter()); 649 assertNull(fragment.mMainFragmentListRowDataAdapter); 650 // RowsFragment is still there 651 assertTrue(fragment.mMainFragment instanceof RowsFragment); 652 assertNotNull(fragment.mMainFragmentRowsAdapter); 653 assertNotNull(fragment.mMainFragmentAdapter); 654 655 // initialize to same adapter 656 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 657 @Override 658 public void run() { 659 fragment.setAdapter(adapter1); 660 } 661 }); 662 assertTrue(adapter1.hasObserver()); 663 assertNotSame(wrappedAdapter, fragment.mMainFragmentListRowDataAdapter); 664 } 665 666 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 667 @Test 668 public void browseFragmentChangeAdapter() throws InterruptedException { 669 final SingleFragmentTestActivity activity = launchAndWaitActivity( 670 RowsFragmentTest.F_standard.class, 2000); 671 final F_standard fragment = ((F_standard) activity.getTestFragment()); 672 fragment.assertExecutedEntranceTransition(); 673 674 final ObjectAdapter adapter1 = fragment.getAdapter(); 675 ListRowDataAdapter wrappedAdapter = fragment.mMainFragmentListRowDataAdapter; 676 assertTrue(adapter1.hasObserver()); 677 assertTrue(wrappedAdapter.hasObserver()); 678 final ObjectAdapter adapter2 = createListRowsAdapter(); 679 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 680 @Override 681 public void run() { 682 fragment.setAdapter(adapter2); 683 } 684 }); 685 // adapter1 should no longer has observer and adapter2 will have observer 686 assertFalse(adapter1.hasObserver()); 687 assertFalse(wrappedAdapter.hasObserver()); 688 assertSame(adapter2, fragment.getAdapter()); 689 assertNotSame(wrappedAdapter, fragment.mMainFragmentListRowDataAdapter); 690 assertTrue(adapter2.hasObserver()); 691 assertTrue(fragment.mMainFragmentListRowDataAdapter.hasObserver()); 692 } 693 694 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 695 @Test 696 public void browseFragmentChangeAdapterToPage() throws InterruptedException { 697 final SingleFragmentTestActivity activity = launchAndWaitActivity( 698 RowsFragmentTest.F_standard.class, 2000); 699 final F_standard fragment = ((F_standard) activity.getTestFragment()); 700 fragment.assertExecutedEntranceTransition(); 701 702 final ObjectAdapter adapter1 = fragment.getAdapter(); 703 ListRowDataAdapter wrappedAdapter = fragment.mMainFragmentListRowDataAdapter; 704 assertTrue(adapter1.hasObserver()); 705 assertTrue(wrappedAdapter.hasObserver()); 706 final ObjectAdapter adapter2 = create2PageRow3ListRow(); 707 fragment.getMainFragmentRegistry().registerFragment(MyPageRow.class, 708 new MyFragmentFactory()); 709 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 710 @Override 711 public void run() { 712 fragment.setAdapter(adapter2); 713 } 714 }); 715 fragment.waitPageFragment(SampleRowsFragment.class); 716 // adapter1 should no longer has observer and adapter2 will have observer 717 assertFalse(adapter1.hasObserver()); 718 assertFalse(wrappedAdapter.hasObserver()); 719 assertSame(adapter2, fragment.getAdapter()); 720 assertNull(fragment.mMainFragmentListRowDataAdapter); 721 assertTrue(adapter2.hasObserver()); 722 } 723 724 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 725 @Test 726 public void browseFragmentNotifyDataChangeListRowToPage() throws InterruptedException { 727 final SingleFragmentTestActivity activity = launchAndWaitActivity( 728 RowsFragmentTest.F_standard.class, 2000); 729 final F_standard fragment = ((F_standard) activity.getTestFragment()); 730 fragment.assertExecutedEntranceTransition(); 731 732 final ArrayObjectAdapter adapter1 = (ArrayObjectAdapter) fragment.getAdapter(); 733 ListRowDataAdapter wrappedAdapter = fragment.mMainFragmentListRowDataAdapter; 734 assertTrue(adapter1.hasObserver()); 735 assertTrue(wrappedAdapter.hasObserver()); 736 737 fragment.getMainFragmentRegistry().registerFragment(MyPageRow.class, 738 new MyFragmentFactory()); 739 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 740 @Override 741 public void run() { 742 adapter1.removeItems(0, 1); 743 adapter1.add(0, new MyPageRow(0)); 744 } 745 }); 746 fragment.waitPageFragment(SampleRowsFragment.class); 747 assertTrue(adapter1.hasObserver()); 748 assertNull(fragment.mMainFragmentListRowDataAdapter); 749 } 750 751 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 752 @Test 753 public void browseFragmentNotifyItemChangeListRowToPage() throws InterruptedException { 754 final SingleFragmentTestActivity activity = launchAndWaitActivity( 755 RowsFragmentTest.F_standard.class, 2000); 756 final F_standard fragment = ((F_standard) activity.getTestFragment()); 757 fragment.assertExecutedEntranceTransition(); 758 759 final ArrayObjectAdapter adapter1 = (ArrayObjectAdapter) fragment.getAdapter(); 760 ListRowDataAdapter wrappedAdapter = fragment.mMainFragmentListRowDataAdapter; 761 assertTrue(adapter1.hasObserver()); 762 assertTrue(wrappedAdapter.hasObserver()); 763 764 fragment.getMainFragmentRegistry().registerFragment(MyPageRow.class, 765 new MyFragmentFactory()); 766 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 767 @Override 768 public void run() { 769 adapter1.replace(0, new MyPageRow(0)); 770 } 771 }); 772 fragment.waitPageFragment(SampleRowsFragment.class); 773 assertTrue(adapter1.hasObserver()); 774 assertNull(fragment.mMainFragmentListRowDataAdapter); 775 } 776 777 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 778 @Test 779 public void browseFragmentNotifyDataChangeListRowToListRow() throws InterruptedException { 780 final SingleFragmentTestActivity activity = launchAndWaitActivity( 781 RowsFragmentTest.F_standard.class, 2000); 782 final F_standard fragment = ((F_standard) activity.getTestFragment()); 783 fragment.assertExecutedEntranceTransition(); 784 785 final ArrayObjectAdapter adapter1 = (ArrayObjectAdapter) fragment.getAdapter(); 786 ListRowDataAdapter wrappedAdapter = fragment.mMainFragmentListRowDataAdapter; 787 assertTrue(adapter1.hasObserver()); 788 assertTrue(wrappedAdapter.hasObserver()); 789 790 fragment.getMainFragmentRegistry().registerFragment(MyPageRow.class, 791 new MyFragmentFactory()); 792 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 793 @Override 794 public void run() { 795 ObjectAdapter listRowAdapter = createListRowAdapter(); 796 HeaderItem header = new HeaderItem(0, "Row 0 changed"); 797 adapter1.removeItems(0, 1); 798 adapter1.add(0, new ListRow(header, listRowAdapter)); 799 } 800 }); 801 assertTrue(adapter1.hasObserver()); 802 assertTrue(wrappedAdapter.hasObserver()); 803 assertSame(wrappedAdapter, fragment.mMainFragmentListRowDataAdapter); 804 } 805 806 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 807 @Test 808 public void browseFragmentNotifyItemChangeListRowToListRow() throws InterruptedException { 809 final SingleFragmentTestActivity activity = launchAndWaitActivity( 810 RowsFragmentTest.F_standard.class, 2000); 811 final F_standard fragment = ((F_standard) activity.getTestFragment()); 812 fragment.assertExecutedEntranceTransition(); 813 814 final ArrayObjectAdapter adapter1 = (ArrayObjectAdapter) fragment.getAdapter(); 815 ListRowDataAdapter wrappedAdapter = fragment.mMainFragmentListRowDataAdapter; 816 assertTrue(adapter1.hasObserver()); 817 assertTrue(wrappedAdapter.hasObserver()); 818 819 fragment.getMainFragmentRegistry().registerFragment(MyPageRow.class, 820 new MyFragmentFactory()); 821 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 822 @Override 823 public void run() { 824 ObjectAdapter listRowAdapter = createListRowAdapter(); 825 HeaderItem header = new HeaderItem(0, "Row 0 changed"); 826 adapter1.replace(0, new ListRow(header, listRowAdapter)); 827 } 828 }); 829 assertTrue(adapter1.hasObserver()); 830 assertTrue(wrappedAdapter.hasObserver()); 831 assertSame(wrappedAdapter, fragment.mMainFragmentListRowDataAdapter); 832 } 833 834 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 835 @Test 836 public void browseFragmentChangeAdapterPageToPage() throws InterruptedException { 837 final SingleFragmentTestActivity activity = launchAndWaitActivity( 838 RowsFragmentTest.F_2PageRow3ListRow.class, 2000); 839 final F_2PageRow3ListRow fragment = ((F_2PageRow3ListRow) activity.getTestFragment()); 840 fragment.assertExecutedEntranceTransition(); 841 842 final ObjectAdapter adapter1 = fragment.getAdapter(); 843 assertNull(fragment.mMainFragmentListRowDataAdapter); 844 assertTrue(adapter1.hasObserver()); 845 final ObjectAdapter adapter2 = create2PageRow3ListRow(); 846 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 847 @Override 848 public void run() { 849 fragment.setAdapter(adapter2); 850 } 851 }); 852 fragment.waitPageFragment(SampleRowsFragment.class); 853 // adapter1 should no longer has observer and adapter2 will have observer 854 assertFalse(adapter1.hasObserver()); 855 assertSame(adapter2, fragment.getAdapter()); 856 assertNull(fragment.mMainFragmentListRowDataAdapter); 857 assertTrue(adapter2.hasObserver()); 858 } 859 860 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 861 @Test 862 public void browseFragmentNotifyChangePageToPage() throws InterruptedException { 863 final SingleFragmentTestActivity activity = launchAndWaitActivity( 864 RowsFragmentTest.F_2PageRow3ListRow.class, 2000); 865 final F_2PageRow3ListRow fragment = ((F_2PageRow3ListRow) activity.getTestFragment()); 866 fragment.assertExecutedEntranceTransition(); 867 868 final ArrayObjectAdapter adapter1 = (ArrayObjectAdapter) fragment.getAdapter(); 869 assertNull(fragment.mMainFragmentListRowDataAdapter); 870 assertTrue(adapter1.hasObserver()); 871 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 872 @Override 873 public void run() { 874 adapter1.removeItems(0, 1); 875 adapter1.add(0, new MyPageRow(1)); 876 } 877 }); 878 fragment.waitPageFragment(SampleFragment.class); 879 // adapter1 should no longer has observer and adapter2 will have observer 880 assertTrue(adapter1.hasObserver()); 881 assertNull(fragment.mMainFragmentListRowDataAdapter); 882 } 883 884 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 885 @Test 886 public void browseFragmentNotifyItemChangePageToPage() throws InterruptedException { 887 final SingleFragmentTestActivity activity = launchAndWaitActivity( 888 RowsFragmentTest.F_2PageRow3ListRow.class, 2000); 889 final F_2PageRow3ListRow fragment = ((F_2PageRow3ListRow) activity.getTestFragment()); 890 fragment.assertExecutedEntranceTransition(); 891 892 final ArrayObjectAdapter adapter1 = (ArrayObjectAdapter) fragment.getAdapter(); 893 assertNull(fragment.mMainFragmentListRowDataAdapter); 894 assertTrue(adapter1.hasObserver()); 895 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 896 @Override 897 public void run() { 898 adapter1.replace(0, new MyPageRow(1)); 899 } 900 }); 901 fragment.waitPageFragment(SampleFragment.class); 902 // adapter1 should no longer has observer and adapter2 will have observer 903 assertTrue(adapter1.hasObserver()); 904 assertNull(fragment.mMainFragmentListRowDataAdapter); 905 } 906 907 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 908 @Test 909 public void browseFragmentChangeAdapterPageToListRow() throws InterruptedException { 910 final SingleFragmentTestActivity activity = launchAndWaitActivity( 911 RowsFragmentTest.F_2PageRow3ListRow.class, 2000); 912 final F_2PageRow3ListRow fragment = ((F_2PageRow3ListRow) activity.getTestFragment()); 913 fragment.assertExecutedEntranceTransition(); 914 915 final ObjectAdapter adapter1 = fragment.getAdapter(); 916 assertNull(fragment.mMainFragmentListRowDataAdapter); 917 assertTrue(adapter1.hasObserver()); 918 final ObjectAdapter adapter2 = createListRowsAdapter(); 919 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 920 @Override 921 public void run() { 922 fragment.setAdapter(adapter2); 923 } 924 }); 925 fragment.waitRowsFragment(); 926 // adapter1 should no longer has observer and adapter2 will have observer 927 assertFalse(adapter1.hasObserver()); 928 assertSame(adapter2, fragment.getAdapter()); 929 assertTrue(adapter2.hasObserver()); 930 assertTrue(fragment.mMainFragmentListRowDataAdapter.hasObserver()); 931 } 932 933 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 934 @Test 935 public void browseFragmentNotifyDataChangePageToListRow() throws InterruptedException { 936 final SingleFragmentTestActivity activity = launchAndWaitActivity( 937 RowsFragmentTest.F_2PageRow3ListRow.class, 2000); 938 final F_2PageRow3ListRow fragment = ((F_2PageRow3ListRow) activity.getTestFragment()); 939 fragment.assertExecutedEntranceTransition(); 940 941 final ArrayObjectAdapter adapter1 = (ArrayObjectAdapter) fragment.getAdapter(); 942 assertNull(fragment.mMainFragmentListRowDataAdapter); 943 assertTrue(adapter1.hasObserver()); 944 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 945 @Override 946 public void run() { 947 ObjectAdapter listRowAdapter = createListRowAdapter(); 948 HeaderItem header = new HeaderItem(0, "Row 0 changed"); 949 adapter1.removeItems(0, 1); 950 adapter1.add(0, new ListRow(header, listRowAdapter)); 951 } 952 }); 953 fragment.waitRowsFragment(); 954 assertTrue(adapter1.hasObserver()); 955 assertTrue(fragment.mMainFragmentListRowDataAdapter.hasObserver()); 956 } 957 958 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 959 @Test 960 public void browseFragmentNotifyItemChangePageToListRow() throws InterruptedException { 961 final SingleFragmentTestActivity activity = launchAndWaitActivity( 962 RowsFragmentTest.F_2PageRow3ListRow.class, 2000); 963 final F_2PageRow3ListRow fragment = ((F_2PageRow3ListRow) activity.getTestFragment()); 964 fragment.assertExecutedEntranceTransition(); 965 966 final ArrayObjectAdapter adapter1 = (ArrayObjectAdapter) fragment.getAdapter(); 967 assertNull(fragment.mMainFragmentListRowDataAdapter); 968 assertTrue(adapter1.hasObserver()); 969 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 970 @Override 971 public void run() { 972 ObjectAdapter listRowAdapter = createListRowAdapter(); 973 HeaderItem header = new HeaderItem(0, "Row 0 changed"); 974 adapter1.replace(0, new ListRow(header, listRowAdapter)); 975 } 976 }); 977 fragment.waitRowsFragment(); 978 assertTrue(adapter1.hasObserver()); 979 assertTrue(fragment.mMainFragmentListRowDataAdapter.hasObserver()); 980 } 981 982 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 983 @Test 984 public void browseFragmentRestore() throws InterruptedException { 985 final SingleFragmentTestActivity activity = launchAndWaitActivity( 986 RowsFragmentTest.F_standard.class, 2000); 987 final F_standard fragment = ((F_standard) activity.getTestFragment()); 988 fragment.assertExecutedEntranceTransition(); 989 990 // select item 2 on row 1 991 selectAndWaitFragmentAnimation(fragment, 1, 2); 992 // save activity to state 993 Bundle savedState = saveActivityState(activity); 994 activity.finish(); 995 996 // recreate activity with saved state 997 SingleFragmentTestActivity activity2 = launchAndWaitActivity( 998 RowsFragmentTest.F_standard.class, 999 new Options().savedInstance(savedState), 2000); 1000 final F_standard fragment2 = ((F_standard) activity2.getTestFragment()); 1001 // validate restored activity selected row and selected item 1002 fragment2.assertNoEntranceTransition(); 1003 assertEquals(1, fragment2.getSelectedPosition()); 1004 assertEquals(2, ((ListRowPresenter.ViewHolder) fragment2.getSelectedRowViewHolder()) 1005 .getSelectedPosition()); 1006 activity2.finish(); 1007 } 1008 1009 public static class MyPageRow extends PageRow { 1010 public int type; 1011 public MyPageRow(int type) { 1012 super(new HeaderItem(100 + type, "page type " + type)); 1013 this.type = type; 1014 } 1015 } 1016 1017 /** 1018 * A RowsFragment that is a separate page in BrowseFragment. 1019 */ 1020 public static class SampleRowsFragment extends RowsFragment { 1021 public SampleRowsFragment() { 1022 // simulates late data loading: 1023 new Handler().postDelayed(new Runnable() { 1024 @Override 1025 public void run() { 1026 setAdapter(createListRowsAdapter()); 1027 if (getMainFragmentAdapter() != null) { 1028 getMainFragmentAdapter().getFragmentHost() 1029 .notifyDataReady(getMainFragmentAdapter()); 1030 } 1031 } 1032 }, 500); 1033 } 1034 } 1035 1036 /** 1037 * A custom Fragment that is a separate page in BrowseFragment. 1038 */ 1039 public static class SampleFragment extends Fragment implements 1040 BrowseFragment.MainFragmentAdapterProvider { 1041 1042 public static class PageFragmentAdapterImpl extends 1043 BrowseFragment.MainFragmentAdapter<SampleFragment> { 1044 1045 public PageFragmentAdapterImpl(SampleFragment fragment) { 1046 super(fragment); 1047 setScalingEnabled(true); 1048 } 1049 1050 @Override 1051 public void setEntranceTransitionState(boolean state) { 1052 getFragment().setEntranceTransitionState(state); 1053 } 1054 } 1055 1056 final PageFragmentAdapterImpl mMainFragmentAdapter = new PageFragmentAdapterImpl(this); 1057 1058 void setEntranceTransitionState(boolean state) { 1059 final View view = getView(); 1060 int visibility = state ? View.VISIBLE : View.INVISIBLE; 1061 view.findViewById(R.id.tv1).setVisibility(visibility); 1062 view.findViewById(R.id.tv2).setVisibility(visibility); 1063 view.findViewById(R.id.tv3).setVisibility(visibility); 1064 } 1065 1066 @Override 1067 public View onCreateView( 1068 final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 1069 View view = inflater.inflate(R.layout.page_fragment, container, false); 1070 return view; 1071 } 1072 1073 @Override 1074 public void onViewCreated(View view, Bundle savedInstanceState) { 1075 // static layout has view and data ready immediately 1076 mMainFragmentAdapter.getFragmentHost().notifyViewCreated(mMainFragmentAdapter); 1077 mMainFragmentAdapter.getFragmentHost().notifyDataReady(mMainFragmentAdapter); 1078 } 1079 1080 @Override 1081 public BrowseFragment.MainFragmentAdapter getMainFragmentAdapter() { 1082 return mMainFragmentAdapter; 1083 } 1084 } 1085 1086 /** 1087 * Create BrowseFragmentAdapter with 3 ListRows and 2 PageRows 1088 */ 1089 private static ArrayObjectAdapter create3ListRow2PageRowAdapter() { 1090 ListRowPresenter lrp = new ListRowPresenter(); 1091 final ArrayObjectAdapter adapter = new ArrayObjectAdapter(lrp); 1092 for (int i = 0; i < 3; i++) { 1093 StableIdAdapter listRowAdapter = new StableIdAdapter(); 1094 listRowAdapter.setHasStableIds(false); 1095 listRowAdapter.setPresenterSelector( 1096 new SinglePresenterSelector(sCardPresenter)); 1097 int index = 0; 1098 listRowAdapter.mList.add(index++); 1099 listRowAdapter.mList.add(index++); 1100 listRowAdapter.mList.add(index++); 1101 HeaderItem header = new HeaderItem(i, "Row " + i); 1102 adapter.add(new ListRow(header, listRowAdapter)); 1103 } 1104 adapter.add(new MyPageRow(0)); 1105 adapter.add(new MyPageRow(1)); 1106 return adapter; 1107 } 1108 1109 /** 1110 * Create BrowseFragmentAdapter with 2 PageRows then 3 ListRow 1111 */ 1112 private static ArrayObjectAdapter create2PageRow3ListRow() { 1113 ListRowPresenter lrp = new ListRowPresenter(); 1114 final ArrayObjectAdapter adapter = new ArrayObjectAdapter(lrp); 1115 adapter.add(new MyPageRow(0)); 1116 adapter.add(new MyPageRow(1)); 1117 for (int i = 0; i < 3; i++) { 1118 StableIdAdapter listRowAdapter = new StableIdAdapter(); 1119 listRowAdapter.setHasStableIds(false); 1120 listRowAdapter.setPresenterSelector( 1121 new SinglePresenterSelector(sCardPresenter)); 1122 int index = 0; 1123 listRowAdapter.mList.add(index++); 1124 listRowAdapter.mList.add(index++); 1125 listRowAdapter.mList.add(index++); 1126 HeaderItem header = new HeaderItem(i, "Row " + i); 1127 adapter.add(new ListRow(header, listRowAdapter)); 1128 } 1129 return adapter; 1130 } 1131 1132 static class MyFragmentFactory extends BrowseFragment.FragmentFactory { 1133 @Override 1134 public Fragment createFragment(Object rowObj) { 1135 MyPageRow row = (MyPageRow) rowObj; 1136 if (row.type == 0) { 1137 return new SampleRowsFragment(); 1138 } else if (row.type == 1) { 1139 return new SampleFragment(); 1140 } 1141 return null; 1142 } 1143 } 1144 1145 /** 1146 * A BrowseFragment with three ListRows, one SampleRowsFragment and one SampleFragment. 1147 */ 1148 public static class F_3ListRow2PageRow extends F_Base { 1149 public F_3ListRow2PageRow() { 1150 getMainFragmentRegistry().registerFragment(MyPageRow.class, new MyFragmentFactory()); 1151 } 1152 @Override 1153 public void onCreate(Bundle savedInstanceState) { 1154 super.onCreate(savedInstanceState); 1155 if (savedInstanceState == null) { 1156 prepareEntranceTransition(); 1157 } 1158 new Handler().postDelayed(new Runnable() { 1159 @Override 1160 public void run() { 1161 setAdapter(create3ListRow2PageRowAdapter()); 1162 startEntranceTransition(); 1163 } 1164 }, 100); 1165 } 1166 } 1167 1168 /** 1169 * A BrowseFragment with three ListRows, one SampleRowsFragment and one SampleFragment. 1170 */ 1171 public static class F_2PageRow3ListRow extends F_Base { 1172 public F_2PageRow3ListRow() { 1173 getMainFragmentRegistry().registerFragment(MyPageRow.class, new MyFragmentFactory()); 1174 } 1175 @Override 1176 public void onCreate(Bundle savedInstanceState) { 1177 super.onCreate(savedInstanceState); 1178 if (savedInstanceState == null) { 1179 prepareEntranceTransition(); 1180 } 1181 new Handler().postDelayed(new Runnable() { 1182 @Override 1183 public void run() { 1184 setAdapter(create2PageRow3ListRow()); 1185 startEntranceTransition(); 1186 } 1187 }, 100); 1188 } 1189 } 1190 1191 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 1192 @Test 1193 public void mixedBrowseFragmentRestoreToListRow() throws Throwable { 1194 final SingleFragmentTestActivity activity = launchAndWaitActivity( 1195 RowsFragmentTest.F_3ListRow2PageRow.class, 2000); 1196 final F_3ListRow2PageRow fragment = ((F_3ListRow2PageRow) activity.getTestFragment()); 1197 fragment.assertExecutedEntranceTransition(); 1198 1199 // select item 2 on row 1. 1200 selectAndWaitFragmentAnimation(fragment, 1, 2); 1201 Bundle savedState = saveActivityState(activity); 1202 activity.finish(); 1203 1204 // start a new activity with the state 1205 SingleFragmentTestActivity activity2 = launchAndWaitActivity( 1206 RowsFragmentTest.F_standard.class, 1207 new Options().savedInstance(savedState), 2000); 1208 final F_3ListRow2PageRow fragment2 = ((F_3ListRow2PageRow) activity2.getTestFragment()); 1209 assertFalse(fragment2.isShowingHeaders()); 1210 fragment2.assertNoEntranceTransition(); 1211 assertEquals(1, fragment2.getSelectedPosition()); 1212 assertEquals(2, ((ListRowPresenter.ViewHolder) fragment2.getSelectedRowViewHolder()) 1213 .getSelectedPosition()); 1214 activity2.finish(); 1215 } 1216 1217 void mixedBrowseFragmentRestoreToSampleRowsFragment(final boolean hideFastLane) 1218 throws Throwable { 1219 final SingleFragmentTestActivity activity = launchAndWaitActivity( 1220 RowsFragmentTest.F_3ListRow2PageRow.class, 2000); 1221 final F_3ListRow2PageRow fragment = ((F_3ListRow2PageRow) activity.getTestFragment()); 1222 fragment.assertExecutedEntranceTransition(); 1223 1224 // select row 3 which is mapped to SampleRowsFragment. 1225 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 1226 @Override 1227 public void run() { 1228 fragment.setSelectedPosition(3, true); 1229 } 1230 }); 1231 // Wait SampleRowsFragment being created 1232 final SampleRowsFragment mainFragment = (SampleRowsFragment) fragment.waitPageFragment( 1233 SampleRowsFragment.class); 1234 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 1235 @Override 1236 public void run() { 1237 if (hideFastLane) { 1238 fragment.startHeadersTransition(false); 1239 } 1240 } 1241 }); 1242 // Wait header transition finishes 1243 waitForHeaderTransition(fragment); 1244 // Select item 1 on row 1 in SampleRowsFragment 1245 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 1246 @Override 1247 public void run() { 1248 mainFragment.setSelectedPosition(1, true, 1249 new ListRowPresenter.SelectItemViewHolderTask(1)); 1250 } 1251 }); 1252 // Save activity state 1253 Bundle savedState = saveActivityState(activity); 1254 activity.finish(); 1255 1256 SingleFragmentTestActivity activity2 = launchAndWaitActivity( 1257 RowsFragmentTest.F_3ListRow2PageRow.class, 1258 new Options().savedInstance(savedState), 2000); 1259 final F_3ListRow2PageRow fragment2 = ((F_3ListRow2PageRow) activity2.getTestFragment()); 1260 final SampleRowsFragment mainFragment2 = (SampleRowsFragment) fragment2.waitPageFragment( 1261 SampleRowsFragment.class); 1262 assertEquals(!hideFastLane, fragment2.isShowingHeaders()); 1263 fragment2.assertNoEntranceTransition(); 1264 // Validate BrowseFragment selected row 3 (mapped to SampleRowsFragment) 1265 assertEquals(3, fragment2.getSelectedPosition()); 1266 // Validate SampleRowsFragment's selected row and selected item 1267 assertEquals(1, mainFragment2.getSelectedPosition()); 1268 assertEquals(1, ((ListRowPresenter.ViewHolder) mainFragment2 1269 .findRowViewHolderByPosition(1)).getSelectedPosition()); 1270 activity2.finish(); 1271 } 1272 1273 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 1274 @Test 1275 public void mixedBrowseFragmentRestoreToSampleRowsFragmentHideFastLane() throws Throwable { 1276 mixedBrowseFragmentRestoreToSampleRowsFragment(true); 1277 1278 } 1279 1280 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 1281 @Test 1282 public void mixedBrowseFragmentRestoreToSampleRowsFragmentShowFastLane() throws Throwable { 1283 mixedBrowseFragmentRestoreToSampleRowsFragment(false); 1284 } 1285 1286 void mixedBrowseFragmentRestoreToSampleFragment(final boolean hideFastLane) 1287 throws Throwable { 1288 final SingleFragmentTestActivity activity = launchAndWaitActivity( 1289 RowsFragmentTest.F_3ListRow2PageRow.class, 2000); 1290 final F_3ListRow2PageRow fragment = ((F_3ListRow2PageRow) activity.getTestFragment()); 1291 fragment.assertExecutedEntranceTransition(); 1292 1293 // select row 3 which is mapped to SampleFragment. 1294 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 1295 @Override 1296 public void run() { 1297 fragment.setSelectedPosition(4, true); 1298 } 1299 }); 1300 // Wait SampleFragment to be created 1301 final SampleFragment mainFragment = (SampleFragment) fragment.waitPageFragment( 1302 SampleFragment.class); 1303 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 1304 @Override 1305 public void run() { 1306 if (hideFastLane) { 1307 fragment.startHeadersTransition(false); 1308 } 1309 } 1310 }); 1311 waitForHeaderTransition(fragment); 1312 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 1313 @Override 1314 public void run() { 1315 // change TextView content which should be saved in states. 1316 TextView t = mainFragment.getView().findViewById(R.id.tv2); 1317 t.setText("changed text"); 1318 } 1319 }); 1320 // Save activity state 1321 Bundle savedState = saveActivityState(activity); 1322 activity.finish(); 1323 1324 SingleFragmentTestActivity activity2 = launchAndWaitActivity( 1325 RowsFragmentTest.F_3ListRow2PageRow.class, 1326 new Options().savedInstance(savedState), 2000); 1327 final F_3ListRow2PageRow fragment2 = ((F_3ListRow2PageRow) activity2.getTestFragment()); 1328 final SampleFragment mainFragment2 = (SampleFragment) fragment2.waitPageFragment( 1329 SampleFragment.class); 1330 assertEquals(!hideFastLane, fragment2.isShowingHeaders()); 1331 fragment2.assertNoEntranceTransition(); 1332 // Validate BrowseFragment selected row 3 (mapped to SampleFragment) 1333 assertEquals(4, fragment2.getSelectedPosition()); 1334 // Validate SampleFragment's view states are restored 1335 TextView t = mainFragment2.getView().findViewById(R.id.tv2); 1336 assertEquals("changed text", t.getText().toString()); 1337 activity2.finish(); 1338 } 1339 1340 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 1341 @Test 1342 public void mixedBrowseFragmentRestoreToSampleFragmentHideFastLane() throws Throwable { 1343 mixedBrowseFragmentRestoreToSampleFragment(true); 1344 1345 } 1346 1347 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP) 1348 @Test 1349 public void mixedBrowseFragmentRestoreToSampleFragmentShowFastLane() throws Throwable { 1350 mixedBrowseFragmentRestoreToSampleFragment(false); 1351 } 1352 1353 1354 } 1355