Merge "Prevent accidentally removing active fragments" into androidx-main
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentManagerTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentManagerTest.kt
index 72dcbb3..9dcbe26 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentManagerTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentManagerTest.kt
@@ -296,4 +296,113 @@
assertThat(popped).isTrue()
}
}
+
+ @Test
+ fun navigatePopNavigateRestore() {
+ withUse(ActivityScenario.launch(FragmentTestActivity::class.java)) {
+ val fm = withActivity { supportFragmentManager }
+ val fragment2 = StrictViewFragment()
+
+ fm.beginTransaction()
+ .setCustomAnimations(
+ androidx.fragment.R.animator.fragment_fade_enter,
+ androidx.fragment.R.animator.fragment_fade_exit,
+ androidx.fragment.R.animator.fragment_fade_enter,
+ androidx.fragment.R.animator.fragment_fade_exit
+ )
+ .replace(R.id.content, fragment2, "fragment2")
+ .setReorderingAllowed(true)
+ .addToBackStack("stack2")
+ .commit()
+ executePendingTransactions()
+
+ val fragment3 = StrictViewFragment()
+
+ fm.saveBackStack("stack2")
+ fm.beginTransaction()
+ .setCustomAnimations(
+ androidx.fragment.R.animator.fragment_fade_enter,
+ androidx.fragment.R.animator.fragment_fade_exit,
+ androidx.fragment.R.animator.fragment_fade_enter,
+ androidx.fragment.R.animator.fragment_fade_exit
+ )
+ .replace(R.id.content, fragment3, "fragment3")
+ .setReorderingAllowed(true)
+ .addToBackStack("stack3")
+ .commit()
+
+ fm.saveBackStack("stack3")
+ fm.restoreBackStack("stack2")
+ executePendingTransactions()
+
+ recreate()
+
+ val restoredFragmentManager = withActivity { supportFragmentManager }
+
+ assertThat(restoredFragmentManager.findFragmentByTag("fragment2"))
+ .isNotNull()
+ }
+ }
+
+ @Test
+ fun replacePopReplaceWithRestored() {
+ withUse(ActivityScenario.launch(FragmentTestActivity::class.java)) {
+ val fm = withActivity { supportFragmentManager }
+ val fragment2 = StrictViewFragment()
+
+ fm.beginTransaction()
+ .setCustomAnimations(
+ androidx.fragment.R.animator.fragment_fade_enter,
+ androidx.fragment.R.animator.fragment_fade_exit,
+ androidx.fragment.R.animator.fragment_fade_enter,
+ androidx.fragment.R.animator.fragment_fade_exit
+ )
+ .replace(R.id.content, fragment2, "fragment2")
+ .setReorderingAllowed(true)
+ .addToBackStack("stack2")
+ .commit()
+ executePendingTransactions()
+
+ val fragment3 = StrictViewFragment()
+
+ fm.popBackStack("stack2", 0)
+ fm.beginTransaction()
+ .setCustomAnimations(
+ androidx.fragment.R.animator.fragment_fade_enter,
+ androidx.fragment.R.animator.fragment_fade_exit,
+ androidx.fragment.R.animator.fragment_fade_enter,
+ androidx.fragment.R.animator.fragment_fade_exit
+ )
+ .replace(R.id.content, fragment3, "fragment3")
+ .setReorderingAllowed(true)
+ .addToBackStack("stack3")
+ .commit()
+
+ fm.popBackStack("stack3", 0)
+
+ val restoreFragment2 = StrictViewFragment()
+ withActivity {
+ restoreFragment2.setInitialSavedState(fm.saveFragmentInstanceState(fragment2))
+ }
+ fm.beginTransaction()
+ .setCustomAnimations(
+ androidx.fragment.R.animator.fragment_fade_enter,
+ androidx.fragment.R.animator.fragment_fade_exit,
+ androidx.fragment.R.animator.fragment_fade_enter,
+ androidx.fragment.R.animator.fragment_fade_exit
+ )
+ .replace(R.id.content, restoreFragment2, "fragment2")
+ .setReorderingAllowed(true)
+ .addToBackStack("stack2")
+ .commit()
+ executePendingTransactions()
+
+ recreate()
+
+ val restoredFragmentManager = withActivity { supportFragmentManager }
+
+ assertThat(restoredFragmentManager.findFragmentByTag("fragment2"))
+ .isNotNull()
+ }
+ }
}
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStore.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStore.java
index f7b5fb9..bcf9942 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStore.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStore.java
@@ -151,6 +151,10 @@
mNonConfig.removeRetainedFragment(f);
}
+ if (mActive.get(f.mWho) != newlyInactive) {
+ return;
+ }
+
// Don't remove yet. That happens in burpActive(). This prevents
// concurrent modification while iterating over mActive
FragmentStateManager removedStateManager = mActive.put(f.mWho, null);