1 /* 2 * Copyright (C) 2016 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.v4.app; 17 18 import static junit.framework.Assert.assertFalse; 19 import static junit.framework.Assert.assertNotNull; 20 import static junit.framework.Assert.assertNull; 21 import static junit.framework.Assert.assertSame; 22 23 import static org.junit.Assert.assertEquals; 24 import static org.junit.Assert.assertTrue; 25 import static org.junit.Assert.fail; 26 27 import android.app.Instrumentation; 28 import android.os.Bundle; 29 import android.support.annotation.Nullable; 30 import android.support.fragment.test.R; 31 import android.support.test.InstrumentationRegistry; 32 import android.support.test.filters.MediumTest; 33 import android.support.test.rule.ActivityTestRule; 34 import android.support.test.runner.AndroidJUnit4; 35 import android.support.v4.app.test.FragmentTestActivity; 36 import android.view.LayoutInflater; 37 import android.view.View; 38 import android.view.ViewGroup; 39 40 import org.junit.Before; 41 import org.junit.Rule; 42 import org.junit.Test; 43 import org.junit.runner.RunWith; 44 45 @MediumTest 46 @RunWith(AndroidJUnit4.class) 47 public class FragmentViewTests { 48 @Rule 49 public ActivityTestRule<FragmentTestActivity> mActivityRule = 50 new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class); 51 52 private Instrumentation mInstrumentation; 53 54 @Before 55 public void setupInstrumentation() { 56 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 57 } 58 59 // Test that adding a fragment adds the Views in the proper order. Popping the back stack 60 // should remove the correct Views. 61 @Test 62 public void addFragments() throws Throwable { 63 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 64 ViewGroup container = (ViewGroup) 65 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 66 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 67 68 // One fragment with a view 69 final StrictViewFragment fragment1 = new StrictViewFragment(); 70 fm.beginTransaction().add(R.id.fragmentContainer, fragment1).addToBackStack(null).commit(); 71 FragmentTestUtil.executePendingTransactions(mActivityRule); 72 FragmentTestUtil.assertChildren(container, fragment1); 73 74 // Add another on top 75 final StrictViewFragment fragment2 = new StrictViewFragment(); 76 fm.beginTransaction().add(R.id.fragmentContainer, fragment2).addToBackStack(null).commit(); 77 FragmentTestUtil.executePendingTransactions(mActivityRule); 78 FragmentTestUtil.assertChildren(container, fragment1, fragment2); 79 80 // Now add two in one transaction: 81 final StrictViewFragment fragment3 = new StrictViewFragment(); 82 final StrictViewFragment fragment4 = new StrictViewFragment(); 83 fm.beginTransaction() 84 .add(R.id.fragmentContainer, fragment3) 85 .add(R.id.fragmentContainer, fragment4) 86 .addToBackStack(null) 87 .commit(); 88 FragmentTestUtil.executePendingTransactions(mActivityRule); 89 FragmentTestUtil.assertChildren(container, fragment1, fragment2, fragment3, fragment4); 90 91 fm.popBackStack(); 92 FragmentTestUtil.executePendingTransactions(mActivityRule); 93 FragmentTestUtil.assertChildren(container, fragment1, fragment2); 94 95 fm.popBackStack(); 96 FragmentTestUtil.executePendingTransactions(mActivityRule); 97 assertEquals(1, container.getChildCount()); 98 FragmentTestUtil.assertChildren(container, fragment1); 99 100 fm.popBackStack(); 101 FragmentTestUtil.executePendingTransactions(mActivityRule); 102 FragmentTestUtil.assertChildren(container); 103 } 104 105 // Add fragments to multiple containers in the same transaction. Make sure that 106 // they pop correctly, too. 107 @Test 108 public void addTwoContainers() throws Throwable { 109 FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container); 110 ViewGroup container1 = (ViewGroup) 111 mActivityRule.getActivity().findViewById(R.id.fragmentContainer1); 112 ViewGroup container2 = (ViewGroup) 113 mActivityRule.getActivity().findViewById(R.id.fragmentContainer2); 114 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 115 116 final StrictViewFragment fragment1 = new StrictViewFragment(); 117 fm.beginTransaction().add(R.id.fragmentContainer1, fragment1).addToBackStack(null).commit(); 118 FragmentTestUtil.executePendingTransactions(mActivityRule); 119 FragmentTestUtil.assertChildren(container1, fragment1); 120 121 final StrictViewFragment fragment2 = new StrictViewFragment(); 122 fm.beginTransaction().add(R.id.fragmentContainer2, fragment2).addToBackStack(null).commit(); 123 FragmentTestUtil.executePendingTransactions(mActivityRule); 124 FragmentTestUtil.assertChildren(container2, fragment2); 125 126 final StrictViewFragment fragment3 = new StrictViewFragment(); 127 final StrictViewFragment fragment4 = new StrictViewFragment(); 128 fm.beginTransaction() 129 .add(R.id.fragmentContainer1, fragment3) 130 .add(R.id.fragmentContainer2, fragment4) 131 .addToBackStack(null) 132 .commit(); 133 FragmentTestUtil.executePendingTransactions(mActivityRule); 134 135 FragmentTestUtil.assertChildren(container1, fragment1, fragment3); 136 FragmentTestUtil.assertChildren(container2, fragment2, fragment4); 137 138 fm.popBackStack(); 139 FragmentTestUtil.executePendingTransactions(mActivityRule); 140 FragmentTestUtil.assertChildren(container1, fragment1); 141 FragmentTestUtil.assertChildren(container2, fragment2); 142 143 fm.popBackStack(); 144 FragmentTestUtil.executePendingTransactions(mActivityRule); 145 FragmentTestUtil.assertChildren(container1, fragment1); 146 FragmentTestUtil.assertChildren(container2); 147 148 fm.popBackStack(); 149 FragmentTestUtil.executePendingTransactions(mActivityRule); 150 assertEquals(0, container1.getChildCount()); 151 } 152 153 // When you add a fragment that's has already been added, it should throw. 154 @Test 155 public void doubleAdd() throws Throwable { 156 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 157 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 158 final StrictViewFragment fragment1 = new StrictViewFragment(); 159 fm.beginTransaction().add(R.id.fragmentContainer, fragment1).commit(); 160 FragmentTestUtil.executePendingTransactions(mActivityRule); 161 162 mInstrumentation.runOnMainSync(new Runnable() { 163 @Override 164 public void run() { 165 try { 166 fm.beginTransaction() 167 .add(R.id.fragmentContainer, fragment1) 168 .addToBackStack(null) 169 .commit(); 170 fm.executePendingTransactions(); 171 fail("Adding a fragment that is already added should be an error"); 172 } catch (IllegalStateException e) { 173 // expected 174 } 175 } 176 }); 177 } 178 179 // Make sure that removed fragments remove the right Views. Popping the back stack should 180 // add the Views back properly 181 @Test 182 public void removeFragments() throws Throwable { 183 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 184 ViewGroup container = (ViewGroup) 185 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 186 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 187 final StrictViewFragment fragment1 = new StrictViewFragment(); 188 final StrictViewFragment fragment2 = new StrictViewFragment(); 189 final StrictViewFragment fragment3 = new StrictViewFragment(); 190 final StrictViewFragment fragment4 = new StrictViewFragment(); 191 fm.beginTransaction() 192 .add(R.id.fragmentContainer, fragment1, "1") 193 .add(R.id.fragmentContainer, fragment2, "2") 194 .add(R.id.fragmentContainer, fragment3, "3") 195 .add(R.id.fragmentContainer, fragment4, "4") 196 .commit(); 197 FragmentTestUtil.executePendingTransactions(mActivityRule); 198 FragmentTestUtil.assertChildren(container, fragment1, fragment2, fragment3, fragment4); 199 200 // Remove a view 201 fm.beginTransaction().remove(fragment4).addToBackStack(null).commit(); 202 FragmentTestUtil.executePendingTransactions(mActivityRule); 203 204 assertEquals(3, container.getChildCount()); 205 FragmentTestUtil.assertChildren(container, fragment1, fragment2, fragment3); 206 207 // remove another one 208 fm.beginTransaction().remove(fragment2).addToBackStack(null).commit(); 209 FragmentTestUtil.executePendingTransactions(mActivityRule); 210 FragmentTestUtil.assertChildren(container, fragment1, fragment3); 211 212 // Now remove the remaining: 213 fm.beginTransaction() 214 .remove(fragment3) 215 .remove(fragment1) 216 .addToBackStack(null) 217 .commit(); 218 FragmentTestUtil.executePendingTransactions(mActivityRule); 219 FragmentTestUtil.assertChildren(container); 220 221 fm.popBackStack(); 222 FragmentTestUtil.executePendingTransactions(mActivityRule); 223 final Fragment replacement1 = fm.findFragmentByTag("1"); 224 final Fragment replacement3 = fm.findFragmentByTag("3"); 225 FragmentTestUtil.assertChildren(container, replacement1, replacement3); 226 227 fm.popBackStack(); 228 FragmentTestUtil.executePendingTransactions(mActivityRule); 229 final Fragment replacement2 = fm.findFragmentByTag("2"); 230 FragmentTestUtil.assertChildren(container, replacement1, replacement3, replacement2); 231 232 fm.popBackStack(); 233 FragmentTestUtil.executePendingTransactions(mActivityRule); 234 final Fragment replacement4 = fm.findFragmentByTag("4"); 235 FragmentTestUtil.assertChildren(container, replacement1, replacement3, replacement2, 236 replacement4); 237 } 238 239 // Removing a hidden fragment should remove the View and popping should bring it back hidden 240 @Test 241 public void removeHiddenView() throws Throwable { 242 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 243 ViewGroup container = (ViewGroup) 244 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 245 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 246 final StrictViewFragment fragment1 = new StrictViewFragment(); 247 fm.beginTransaction().add(R.id.fragmentContainer, fragment1, "1").hide(fragment1).commit(); 248 FragmentTestUtil.executePendingTransactions(mActivityRule); 249 FragmentTestUtil.assertChildren(container, fragment1); 250 assertTrue(fragment1.isHidden()); 251 252 fm.beginTransaction().remove(fragment1).addToBackStack(null).commit(); 253 FragmentTestUtil.executePendingTransactions(mActivityRule); 254 FragmentTestUtil.assertChildren(container); 255 256 fm.popBackStack(); 257 FragmentTestUtil.executePendingTransactions(mActivityRule); 258 final Fragment replacement1 = fm.findFragmentByTag("1"); 259 FragmentTestUtil.assertChildren(container, replacement1); 260 assertTrue(replacement1.isHidden()); 261 assertEquals(View.GONE, replacement1.getView().getVisibility()); 262 } 263 264 // Removing a detached fragment should do nothing to the View and popping should bring 265 // the Fragment back detached 266 @Test 267 public void removeDetatchedView() throws Throwable { 268 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 269 ViewGroup container = (ViewGroup) 270 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 271 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 272 final StrictViewFragment fragment1 = new StrictViewFragment(); 273 fm.beginTransaction() 274 .add(R.id.fragmentContainer, fragment1, "1") 275 .detach(fragment1) 276 .commit(); 277 FragmentTestUtil.executePendingTransactions(mActivityRule); 278 FragmentTestUtil.assertChildren(container); 279 assertTrue(fragment1.isDetached()); 280 281 fm.beginTransaction().remove(fragment1).addToBackStack(null).commit(); 282 FragmentTestUtil.executePendingTransactions(mActivityRule); 283 FragmentTestUtil.assertChildren(container); 284 285 fm.popBackStack(); 286 FragmentTestUtil.executePendingTransactions(mActivityRule); 287 final Fragment replacement1 = fm.findFragmentByTag("1"); 288 FragmentTestUtil.assertChildren(container); 289 assertTrue(replacement1.isDetached()); 290 } 291 292 // Unlike adding the same fragment twice, you should be able to add and then remove and then 293 // add the same fragment in one transaction. 294 @Test 295 public void addRemoveAdd() throws Throwable { 296 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 297 ViewGroup container = (ViewGroup) 298 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 299 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 300 final StrictViewFragment fragment = new StrictViewFragment(); 301 fm.beginTransaction() 302 .add(R.id.fragmentContainer, fragment) 303 .remove(fragment) 304 .add(R.id.fragmentContainer, fragment) 305 .addToBackStack(null) 306 .commit(); 307 FragmentTestUtil.executePendingTransactions(mActivityRule); 308 FragmentTestUtil.assertChildren(container, fragment); 309 310 fm.popBackStack(); 311 FragmentTestUtil.executePendingTransactions(mActivityRule); 312 FragmentTestUtil.assertChildren(container); 313 } 314 315 // Removing a fragment that isn't in should not throw 316 @Test 317 public void removeNothThere() throws Throwable { 318 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 319 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 320 final StrictViewFragment fragment = new StrictViewFragment(); 321 fm.beginTransaction().remove(fragment).commit(); 322 FragmentTestUtil.executePendingTransactions(mActivityRule); 323 } 324 325 // Hide a fragment and its View should be GONE. Then pop it and the View should be VISIBLE 326 @Test 327 public void hideFragment() throws Throwable { 328 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 329 ViewGroup container = (ViewGroup) 330 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 331 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 332 final StrictViewFragment fragment = new StrictViewFragment(); 333 fm.beginTransaction().add(R.id.fragmentContainer, fragment).commit(); 334 FragmentTestUtil.executePendingTransactions(mActivityRule); 335 336 FragmentTestUtil.assertChildren(container, fragment); 337 assertEquals(View.VISIBLE, fragment.getView().getVisibility()); 338 339 fm.beginTransaction().hide(fragment).addToBackStack(null).commit(); 340 FragmentTestUtil.executePendingTransactions(mActivityRule); 341 342 FragmentTestUtil.assertChildren(container, fragment); 343 assertTrue(fragment.isHidden()); 344 assertEquals(View.GONE, fragment.getView().getVisibility()); 345 346 fm.popBackStack(); 347 FragmentTestUtil.executePendingTransactions(mActivityRule); 348 349 FragmentTestUtil.assertChildren(container, fragment); 350 assertFalse(fragment.isHidden()); 351 assertEquals(View.VISIBLE, fragment.getView().getVisibility()); 352 } 353 354 // Hiding a hidden fragment should not throw 355 @Test 356 public void doubleHide() throws Throwable { 357 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 358 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 359 final StrictViewFragment fragment = new StrictViewFragment(); 360 fm.beginTransaction() 361 .add(R.id.fragmentContainer, fragment) 362 .hide(fragment) 363 .hide(fragment) 364 .commit(); 365 FragmentTestUtil.executePendingTransactions(mActivityRule); 366 } 367 368 // Hiding a non-existing fragment should not throw 369 @Test 370 public void hideUnAdded() throws Throwable { 371 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 372 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 373 final StrictViewFragment fragment = new StrictViewFragment(); 374 fm.beginTransaction() 375 .hide(fragment) 376 .commit(); 377 FragmentTestUtil.executePendingTransactions(mActivityRule); 378 } 379 380 // Show a hidden fragment and its View should be VISIBLE. Then pop it and the View should be 381 // GONE. 382 @Test 383 public void showFragment() throws Throwable { 384 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 385 ViewGroup container = (ViewGroup) 386 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 387 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 388 final StrictViewFragment fragment = new StrictViewFragment(); 389 fm.beginTransaction().add(R.id.fragmentContainer, fragment).hide(fragment).commit(); 390 FragmentTestUtil.executePendingTransactions(mActivityRule); 391 392 FragmentTestUtil.assertChildren(container, fragment); 393 assertTrue(fragment.isHidden()); 394 assertEquals(View.GONE, fragment.getView().getVisibility()); 395 396 fm.beginTransaction().show(fragment).addToBackStack(null).commit(); 397 FragmentTestUtil.executePendingTransactions(mActivityRule); 398 399 FragmentTestUtil.assertChildren(container, fragment); 400 assertFalse(fragment.isHidden()); 401 assertEquals(View.VISIBLE, fragment.getView().getVisibility()); 402 403 fm.popBackStack(); 404 FragmentTestUtil.executePendingTransactions(mActivityRule); 405 406 FragmentTestUtil.assertChildren(container, fragment); 407 assertTrue(fragment.isHidden()); 408 assertEquals(View.GONE, fragment.getView().getVisibility()); 409 } 410 411 // Showing a shown fragment should not throw 412 @Test 413 public void showShown() throws Throwable { 414 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 415 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 416 final StrictViewFragment fragment = new StrictViewFragment(); 417 fm.beginTransaction() 418 .add(R.id.fragmentContainer, fragment) 419 .show(fragment) 420 .commit(); 421 FragmentTestUtil.executePendingTransactions(mActivityRule); 422 } 423 424 // Showing a non-existing fragment should not throw 425 @Test 426 public void showUnAdded() throws Throwable { 427 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 428 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 429 final StrictViewFragment fragment = new StrictViewFragment(); 430 fm.beginTransaction() 431 .show(fragment) 432 .commit(); 433 FragmentTestUtil.executePendingTransactions(mActivityRule); 434 } 435 436 // Detaching a fragment should remove the View from the hierarchy. Then popping it should 437 // bring it back VISIBLE 438 @Test 439 public void detachFragment() throws Throwable { 440 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 441 ViewGroup container = (ViewGroup) 442 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 443 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 444 final StrictViewFragment fragment = new StrictViewFragment(); 445 fm.beginTransaction().add(R.id.fragmentContainer, fragment).commit(); 446 FragmentTestUtil.executePendingTransactions(mActivityRule); 447 448 FragmentTestUtil.assertChildren(container, fragment); 449 assertFalse(fragment.isDetached()); 450 assertEquals(View.VISIBLE, fragment.getView().getVisibility()); 451 452 fm.beginTransaction().detach(fragment).addToBackStack(null).commit(); 453 FragmentTestUtil.executePendingTransactions(mActivityRule); 454 455 FragmentTestUtil.assertChildren(container); 456 assertTrue(fragment.isDetached()); 457 458 fm.popBackStack(); 459 FragmentTestUtil.executePendingTransactions(mActivityRule); 460 461 FragmentTestUtil.assertChildren(container, fragment); 462 assertFalse(fragment.isDetached()); 463 assertEquals(View.VISIBLE, fragment.getView().getVisibility()); 464 } 465 466 // Detaching a hidden fragment should remove the View from the hierarchy. Then popping it should 467 // bring it back hidden 468 @Test 469 public void detachHiddenFragment() throws Throwable { 470 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 471 ViewGroup container = (ViewGroup) 472 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 473 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 474 final StrictViewFragment fragment = new StrictViewFragment(); 475 fm.beginTransaction().add(R.id.fragmentContainer, fragment).hide(fragment).commit(); 476 FragmentTestUtil.executePendingTransactions(mActivityRule); 477 478 FragmentTestUtil.assertChildren(container, fragment); 479 assertFalse(fragment.isDetached()); 480 assertTrue(fragment.isHidden()); 481 assertEquals(View.GONE, fragment.getView().getVisibility()); 482 483 fm.beginTransaction().detach(fragment).addToBackStack(null).commit(); 484 FragmentTestUtil.executePendingTransactions(mActivityRule); 485 486 FragmentTestUtil.assertChildren(container); 487 assertTrue(fragment.isHidden()); 488 assertTrue(fragment.isDetached()); 489 490 fm.popBackStack(); 491 FragmentTestUtil.executePendingTransactions(mActivityRule); 492 493 FragmentTestUtil.assertChildren(container, fragment); 494 assertTrue(fragment.isHidden()); 495 assertFalse(fragment.isDetached()); 496 assertEquals(View.GONE, fragment.getView().getVisibility()); 497 } 498 499 // Detaching a detached fragment should not throw 500 @Test 501 public void detachDetatched() throws Throwable { 502 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 503 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 504 final StrictViewFragment fragment = new StrictViewFragment(); 505 fm.beginTransaction() 506 .add(R.id.fragmentContainer, fragment) 507 .detach(fragment) 508 .detach(fragment) 509 .commit(); 510 FragmentTestUtil.executePendingTransactions(mActivityRule); 511 } 512 513 // Detaching a non-existing fragment should not throw 514 @Test 515 public void detachUnAdded() throws Throwable { 516 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 517 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 518 final StrictViewFragment fragment = new StrictViewFragment(); 519 fm.beginTransaction() 520 .detach(fragment) 521 .commit(); 522 FragmentTestUtil.executePendingTransactions(mActivityRule); 523 } 524 525 // Attaching a fragment should add the View back into the hierarchy. Then popping it should 526 // remove it again 527 @Test 528 public void attachFragment() throws Throwable { 529 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 530 ViewGroup container = (ViewGroup) 531 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 532 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 533 final StrictViewFragment fragment = new StrictViewFragment(); 534 fm.beginTransaction().add(R.id.fragmentContainer, fragment).detach(fragment).commit(); 535 FragmentTestUtil.executePendingTransactions(mActivityRule); 536 537 FragmentTestUtil.assertChildren(container); 538 assertTrue(fragment.isDetached()); 539 540 fm.beginTransaction().attach(fragment).addToBackStack(null).commit(); 541 FragmentTestUtil.executePendingTransactions(mActivityRule); 542 543 FragmentTestUtil.assertChildren(container, fragment); 544 assertFalse(fragment.isDetached()); 545 assertEquals(View.VISIBLE, fragment.getView().getVisibility()); 546 547 fm.popBackStack(); 548 FragmentTestUtil.executePendingTransactions(mActivityRule); 549 550 FragmentTestUtil.assertChildren(container); 551 assertTrue(fragment.isDetached()); 552 } 553 554 // Attaching a hidden fragment should add the View as GONE the hierarchy. Then popping it should 555 // remove it again. 556 @Test 557 public void attachHiddenFragment() throws Throwable { 558 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 559 ViewGroup container = (ViewGroup) 560 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 561 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 562 final StrictViewFragment fragment = new StrictViewFragment(); 563 fm.beginTransaction() 564 .add(R.id.fragmentContainer, fragment) 565 .hide(fragment) 566 .detach(fragment) 567 .commit(); 568 FragmentTestUtil.executePendingTransactions(mActivityRule); 569 570 FragmentTestUtil.assertChildren(container); 571 assertTrue(fragment.isDetached()); 572 assertTrue(fragment.isHidden()); 573 574 fm.beginTransaction().attach(fragment).addToBackStack(null).commit(); 575 FragmentTestUtil.executePendingTransactions(mActivityRule); 576 577 FragmentTestUtil.assertChildren(container, fragment); 578 assertTrue(fragment.isHidden()); 579 assertFalse(fragment.isDetached()); 580 assertEquals(View.GONE, fragment.getView().getVisibility()); 581 582 fm.popBackStack(); 583 FragmentTestUtil.executePendingTransactions(mActivityRule); 584 585 FragmentTestUtil.assertChildren(container); 586 assertTrue(fragment.isDetached()); 587 assertTrue(fragment.isHidden()); 588 } 589 590 // Attaching an attached fragment should not throw 591 @Test 592 public void attachAttached() throws Throwable { 593 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 594 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 595 final StrictViewFragment fragment = new StrictViewFragment(); 596 fm.beginTransaction() 597 .add(R.id.fragmentContainer, fragment) 598 .attach(fragment) 599 .commit(); 600 FragmentTestUtil.executePendingTransactions(mActivityRule); 601 } 602 603 // Attaching a non-existing fragment should not throw 604 @Test 605 public void attachUnAdded() throws Throwable { 606 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 607 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 608 final StrictViewFragment fragment = new StrictViewFragment(); 609 fm.beginTransaction() 610 .attach(fragment) 611 .commit(); 612 FragmentTestUtil.executePendingTransactions(mActivityRule); 613 } 614 615 // Simple replace of one fragment in a container. Popping should replace it back again 616 @Test 617 public void replaceOne() throws Throwable { 618 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 619 ViewGroup container = (ViewGroup) 620 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 621 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 622 final StrictViewFragment fragment1 = new StrictViewFragment(); 623 fm.beginTransaction().add(R.id.fragmentContainer, fragment1, "1").commit(); 624 FragmentTestUtil.executePendingTransactions(mActivityRule); 625 626 FragmentTestUtil.assertChildren(container, fragment1); 627 628 final StrictViewFragment fragment2 = new StrictViewFragment(); 629 fm.beginTransaction() 630 .replace(R.id.fragmentContainer, fragment2) 631 .addToBackStack(null) 632 .commit(); 633 FragmentTestUtil.executePendingTransactions(mActivityRule); 634 635 FragmentTestUtil.assertChildren(container, fragment2); 636 assertEquals(View.VISIBLE, fragment2.getView().getVisibility()); 637 638 fm.popBackStack(); 639 FragmentTestUtil.executePendingTransactions(mActivityRule); 640 641 Fragment replacement1 = fm.findFragmentByTag("1"); 642 assertNotNull(replacement1); 643 FragmentTestUtil.assertChildren(container, replacement1); 644 assertFalse(replacement1.isHidden()); 645 assertTrue(replacement1.isAdded()); 646 assertFalse(replacement1.isDetached()); 647 assertEquals(View.VISIBLE, replacement1.getView().getVisibility()); 648 } 649 650 // Replace of multiple fragments in a container. Popping should replace it back again 651 @Test 652 public void replaceTwo() throws Throwable { 653 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 654 ViewGroup container = (ViewGroup) 655 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 656 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 657 final StrictViewFragment fragment1 = new StrictViewFragment(); 658 final StrictViewFragment fragment2 = new StrictViewFragment(); 659 fm.beginTransaction() 660 .add(R.id.fragmentContainer, fragment1, "1") 661 .add(R.id.fragmentContainer, fragment2, "2") 662 .hide(fragment2) 663 .commit(); 664 FragmentTestUtil.executePendingTransactions(mActivityRule); 665 666 FragmentTestUtil.assertChildren(container, fragment1, fragment2); 667 668 final StrictViewFragment fragment3 = new StrictViewFragment(); 669 fm.beginTransaction() 670 .replace(R.id.fragmentContainer, fragment3) 671 .addToBackStack(null) 672 .commit(); 673 FragmentTestUtil.executePendingTransactions(mActivityRule); 674 675 FragmentTestUtil.assertChildren(container, fragment3); 676 assertEquals(View.VISIBLE, fragment3.getView().getVisibility()); 677 678 fm.popBackStack(); 679 FragmentTestUtil.executePendingTransactions(mActivityRule); 680 681 Fragment replacement1 = fm.findFragmentByTag("1"); 682 Fragment replacement2 = fm.findFragmentByTag("2"); 683 assertNotNull(replacement1); 684 assertNotNull(replacement2); 685 FragmentTestUtil.assertChildren(container, replacement1, replacement2); 686 assertFalse(replacement1.isHidden()); 687 assertTrue(replacement1.isAdded()); 688 assertFalse(replacement1.isDetached()); 689 assertEquals(View.VISIBLE, replacement1.getView().getVisibility()); 690 691 // fragment2 was hidden, so it should be returned hidden 692 assertTrue(replacement2.isHidden()); 693 assertTrue(replacement2.isAdded()); 694 assertFalse(replacement2.isDetached()); 695 assertEquals(View.GONE, replacement2.getView().getVisibility()); 696 } 697 698 // Replace of empty container. Should act as add and popping should just remove the fragment 699 @Test 700 public void replaceZero() throws Throwable { 701 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 702 ViewGroup container = (ViewGroup) 703 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 704 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 705 706 final StrictViewFragment fragment = new StrictViewFragment(); 707 fm.beginTransaction() 708 .replace(R.id.fragmentContainer, fragment) 709 .addToBackStack(null) 710 .commit(); 711 FragmentTestUtil.executePendingTransactions(mActivityRule); 712 713 FragmentTestUtil.assertChildren(container, fragment); 714 assertEquals(View.VISIBLE, fragment.getView().getVisibility()); 715 716 fm.popBackStack(); 717 FragmentTestUtil.executePendingTransactions(mActivityRule); 718 719 FragmentTestUtil.assertChildren(container); 720 } 721 722 // Replace a fragment that exists with itself 723 @Test 724 public void replaceExisting() throws Throwable { 725 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 726 ViewGroup container = (ViewGroup) 727 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 728 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 729 final StrictViewFragment fragment1 = new StrictViewFragment(); 730 final StrictViewFragment fragment2 = new StrictViewFragment(); 731 fm.beginTransaction() 732 .add(R.id.fragmentContainer, fragment1, "1") 733 .add(R.id.fragmentContainer, fragment2, "2") 734 .commit(); 735 FragmentTestUtil.executePendingTransactions(mActivityRule); 736 737 FragmentTestUtil.assertChildren(container, fragment1, fragment2); 738 739 fm.beginTransaction() 740 .replace(R.id.fragmentContainer, fragment1) 741 .addToBackStack(null) 742 .commit(); 743 FragmentTestUtil.executePendingTransactions(mActivityRule); 744 745 FragmentTestUtil.assertChildren(container, fragment1); 746 747 fm.popBackStack(); 748 FragmentTestUtil.executePendingTransactions(mActivityRule); 749 750 final Fragment replacement1 = fm.findFragmentByTag("1"); 751 final Fragment replacement2 = fm.findFragmentByTag("2"); 752 753 assertSame(fragment1, replacement1); 754 FragmentTestUtil.assertChildren(container, replacement1, replacement2); 755 } 756 757 // Have two replace operations in the same transaction to ensure that they 758 // don't interfere with each other 759 @Test 760 public void replaceReplace() throws Throwable { 761 FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container); 762 ViewGroup container1 = (ViewGroup) 763 mActivityRule.getActivity().findViewById(R.id.fragmentContainer1); 764 ViewGroup container2 = (ViewGroup) 765 mActivityRule.getActivity().findViewById(R.id.fragmentContainer2); 766 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 767 768 final StrictViewFragment fragment1 = new StrictViewFragment(); 769 final StrictViewFragment fragment2 = new StrictViewFragment(); 770 final StrictViewFragment fragment3 = new StrictViewFragment(); 771 final StrictViewFragment fragment4 = new StrictViewFragment(); 772 final StrictViewFragment fragment5 = new StrictViewFragment(); 773 fm.beginTransaction() 774 .add(R.id.fragmentContainer1, fragment1) 775 .add(R.id.fragmentContainer2, fragment2) 776 .replace(R.id.fragmentContainer1, fragment3) 777 .replace(R.id.fragmentContainer2, fragment4) 778 .replace(R.id.fragmentContainer1, fragment5) 779 .addToBackStack(null) 780 .commit(); 781 FragmentTestUtil.executePendingTransactions(mActivityRule); 782 783 assertChildren(container1, fragment5); 784 assertChildren(container2, fragment4); 785 786 fm.popBackStack(); 787 FragmentTestUtil.executePendingTransactions(mActivityRule); 788 789 assertChildren(container1); 790 assertChildren(container2); 791 } 792 793 // Test to prevent regressions in FragmentManager fragment replace method. See b/24693644 794 @Test 795 public void testReplaceFragment() throws Throwable { 796 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 797 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 798 StrictViewFragment fragmentA = new StrictViewFragment(); 799 fragmentA.setLayoutId(R.layout.text_a); 800 801 fm.beginTransaction() 802 .add(R.id.fragmentContainer, fragmentA) 803 .addToBackStack(null) 804 .commit(); 805 FragmentTestUtil.executePendingTransactions(mActivityRule); 806 807 assertNotNull(findViewById(R.id.textA)); 808 assertNull(findViewById(R.id.textB)); 809 assertNull(findViewById(R.id.textC)); 810 811 StrictViewFragment fragmentB = new StrictViewFragment(); 812 fragmentB.setLayoutId(R.layout.text_b); 813 fm.beginTransaction() 814 .add(R.id.fragmentContainer, fragmentB) 815 .addToBackStack(null) 816 .commit(); 817 FragmentTestUtil.executePendingTransactions(mActivityRule); 818 assertNotNull(findViewById(R.id.textA)); 819 assertNotNull(findViewById(R.id.textB)); 820 assertNull(findViewById(R.id.textC)); 821 822 StrictViewFragment fragmentC = new StrictViewFragment(); 823 fragmentC.setLayoutId(R.layout.text_c); 824 fm.beginTransaction() 825 .replace(R.id.fragmentContainer, fragmentC) 826 .addToBackStack(null) 827 .commit(); 828 FragmentTestUtil.executePendingTransactions(mActivityRule); 829 assertNull(findViewById(R.id.textA)); 830 assertNull(findViewById(R.id.textB)); 831 assertNotNull(findViewById(R.id.textC)); 832 } 833 834 // Test that adding a fragment with invisible or gone views does not end up with the view 835 // being visible 836 @Test 837 public void addInvisibleAndGoneFragments() throws Throwable { 838 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 839 ViewGroup container = (ViewGroup) 840 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 841 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 842 843 final StrictViewFragment fragment1 = new InvisibleFragment(); 844 fm.beginTransaction().add(R.id.fragmentContainer, fragment1).addToBackStack(null).commit(); 845 FragmentTestUtil.executePendingTransactions(mActivityRule); 846 FragmentTestUtil.assertChildren(container, fragment1); 847 848 assertEquals(View.INVISIBLE, fragment1.getView().getVisibility()); 849 850 final InvisibleFragment fragment2 = new InvisibleFragment(); 851 fragment2.visibility = View.GONE; 852 fm.beginTransaction() 853 .replace(R.id.fragmentContainer, fragment2) 854 .addToBackStack(null) 855 .commit(); 856 FragmentTestUtil.executePendingTransactions(mActivityRule); 857 FragmentTestUtil.assertChildren(container, fragment2); 858 859 assertEquals(View.GONE, fragment2.getView().getVisibility()); 860 } 861 862 // Test to ensure that popping and adding a fragment properly track the fragments added 863 // and removed. 864 @Test 865 public void popAdd() throws Throwable { 866 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 867 ViewGroup container = (ViewGroup) 868 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 869 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 870 871 // One fragment with a view 872 final StrictViewFragment fragment1 = new StrictViewFragment(); 873 fm.beginTransaction().add(R.id.fragmentContainer, fragment1).addToBackStack(null).commit(); 874 FragmentTestUtil.executePendingTransactions(mActivityRule); 875 FragmentTestUtil.assertChildren(container, fragment1); 876 877 final StrictViewFragment fragment2 = new StrictViewFragment(); 878 final StrictViewFragment fragment3 = new StrictViewFragment(); 879 mInstrumentation.runOnMainSync(new Runnable() { 880 @Override 881 public void run() { 882 fm.popBackStack(); 883 fm.beginTransaction() 884 .replace(R.id.fragmentContainer, fragment2) 885 .addToBackStack(null) 886 .commit(); 887 fm.executePendingTransactions(); 888 fm.popBackStack(); 889 fm.beginTransaction() 890 .replace(R.id.fragmentContainer, fragment3) 891 .addToBackStack(null) 892 .commit(); 893 fm.executePendingTransactions(); 894 } 895 }); 896 FragmentTestUtil.assertChildren(container, fragment3); 897 } 898 899 // Ensure that ordered transactions are executed individually rather than together. 900 // This forces references from one fragment to another that should be executed earlier 901 // to work. 902 @Test 903 public void orderedOperationsTogether() throws Throwable { 904 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 905 ViewGroup container = (ViewGroup) 906 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 907 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 908 909 final StrictViewFragment fragment1 = new StrictViewFragment(); 910 fragment1.setLayoutId(R.layout.scene1); 911 final StrictViewFragment fragment2 = new StrictViewFragment(); 912 fragment2.setLayoutId(R.layout.fragment_a); 913 914 mActivityRule.runOnUiThread(new Runnable() { 915 @Override 916 public void run() { 917 fm.beginTransaction() 918 .add(R.id.fragmentContainer, fragment1) 919 .setReorderingAllowed(false) 920 .addToBackStack(null) 921 .commit(); 922 fm.beginTransaction() 923 .add(R.id.squareContainer, fragment2) 924 .setReorderingAllowed(false) 925 .addToBackStack(null) 926 .commit(); 927 fm.executePendingTransactions(); 928 } 929 }); 930 FragmentTestUtil.assertChildren(container, fragment1); 931 assertNotNull(findViewById(R.id.textA)); 932 } 933 934 // Ensure that there is no problem if the child fragment manager is used before 935 // the View has been added. 936 @Test 937 public void childFragmentManager() throws Throwable { 938 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 939 ViewGroup container = (ViewGroup) 940 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 941 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 942 943 final StrictViewFragment fragment1 = new ParentFragment(); 944 fragment1.setLayoutId(R.layout.double_container); 945 946 fm.beginTransaction() 947 .add(R.id.fragmentContainer, fragment1) 948 .addToBackStack(null) 949 .commit(); 950 951 FragmentTestUtil.executePendingTransactions(mActivityRule); 952 953 FragmentTestUtil.assertChildren(container, fragment1); 954 ViewGroup innerContainer = (ViewGroup) 955 fragment1.getView().findViewById(R.id.fragmentContainer1); 956 957 Fragment fragment2 = fragment1.getChildFragmentManager().findFragmentByTag("inner"); 958 FragmentTestUtil.assertChildren(innerContainer, fragment2); 959 } 960 961 // Popping the backstack with ordered fragments should execute the operations together. 962 // When a non-backstack fragment will be raised, it should not be destroyed. 963 @Test 964 public void popToNonBackStackFragment() throws Throwable { 965 FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container); 966 final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager(); 967 968 final SimpleViewFragment fragment1 = new SimpleViewFragment(); 969 970 fm.beginTransaction() 971 .add(R.id.fragmentContainer, fragment1) 972 .commit(); 973 974 FragmentTestUtil.executePendingTransactions(mActivityRule); 975 976 final SimpleViewFragment fragment2 = new SimpleViewFragment(); 977 978 fm.beginTransaction() 979 .replace(R.id.fragmentContainer, fragment2) 980 .addToBackStack("two") 981 .commit(); 982 983 FragmentTestUtil.executePendingTransactions(mActivityRule); 984 985 final SimpleViewFragment fragment3 = new SimpleViewFragment(); 986 987 fm.beginTransaction() 988 .replace(R.id.fragmentContainer, fragment3) 989 .addToBackStack("three") 990 .commit(); 991 992 FragmentTestUtil.executePendingTransactions(mActivityRule); 993 994 assertEquals(1, fragment1.onCreateViewCount); 995 assertEquals(1, fragment2.onCreateViewCount); 996 assertEquals(1, fragment3.onCreateViewCount); 997 998 FragmentTestUtil.popBackStackImmediate(mActivityRule, "two", 999 FragmentManager.POP_BACK_STACK_INCLUSIVE); 1000 1001 ViewGroup container = (ViewGroup) 1002 mActivityRule.getActivity().findViewById(R.id.fragmentContainer); 1003 1004 FragmentTestUtil.assertChildren(container, fragment1); 1005 1006 assertEquals(2, fragment1.onCreateViewCount); 1007 assertEquals(1, fragment2.onCreateViewCount); 1008 assertEquals(1, fragment3.onCreateViewCount); 1009 } 1010 1011 private View findViewById(int viewId) { 1012 return mActivityRule.getActivity().findViewById(viewId); 1013 } 1014 1015 private void assertChildren(ViewGroup container, Fragment... fragments) { 1016 final int numFragments = fragments == null ? 0 : fragments.length; 1017 assertEquals("There aren't the correct number of fragment Views in its container", 1018 numFragments, container.getChildCount()); 1019 for (int i = 0; i < numFragments; i++) { 1020 assertEquals("Wrong Fragment View order for [" + i + "]", container.getChildAt(i), 1021 fragments[i].getView()); 1022 } 1023 } 1024 1025 public static class InvisibleFragment extends StrictViewFragment { 1026 public int visibility = View.INVISIBLE; 1027 1028 @Override 1029 public void onViewCreated(View view, Bundle savedInstanceState) { 1030 view.setVisibility(visibility); 1031 super.onViewCreated(view, savedInstanceState); 1032 } 1033 } 1034 1035 public static class ParentFragment extends StrictViewFragment { 1036 public ParentFragment() { 1037 setLayoutId(R.layout.double_container); 1038 } 1039 1040 @Override 1041 public View onCreateView(LayoutInflater inflater, ViewGroup container, 1042 Bundle savedInstanceState) { 1043 View view = super.onCreateView(inflater, container, savedInstanceState); 1044 final StrictViewFragment fragment2 = new StrictViewFragment(); 1045 fragment2.setLayoutId(R.layout.fragment_a); 1046 1047 getChildFragmentManager().beginTransaction() 1048 .add(R.id.fragmentContainer1, fragment2, "inner") 1049 .addToBackStack(null) 1050 .commit(); 1051 getChildFragmentManager().executePendingTransactions(); 1052 return view; 1053 } 1054 } 1055 1056 public static class SimpleViewFragment extends Fragment { 1057 public int onCreateViewCount; 1058 1059 @Nullable 1060 @Override 1061 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, 1062 @Nullable Bundle savedInstanceState) { 1063 onCreateViewCount++; 1064 return inflater.inflate(R.layout.fragment_a, container, false); 1065 } 1066 } 1067 } 1068