Merge "Lifecycle guarantees for target fragments"
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 73b96f1..612998d 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -762,6 +762,24 @@
* are going to call back with {@link #onActivityResult(int, int, Intent)}.
*/
public void setTargetFragment(Fragment fragment, int requestCode) {
+ // Don't allow a caller to set a target fragment in another FragmentManager,
+ // but there's a snag: people do set target fragments before fragments get added.
+ // We'll have the FragmentManager check that for validity when we move
+ // the fragments to a valid state.
+ final FragmentManager mine = getFragmentManager();
+ final FragmentManager theirs = fragment.getFragmentManager();
+ if (mine != null && theirs != null && mine != theirs) {
+ throw new IllegalArgumentException("Fragment " + fragment
+ + " must share the same FragmentManager to be set as a target fragment");
+ }
+
+ // Don't let someone create a cycle.
+ for (Fragment check = fragment; check != null; check = check.getTargetFragment()) {
+ if (check == this) {
+ throw new IllegalArgumentException("Setting " + fragment + " as the target of "
+ + this + " would create a target cycle");
+ }
+ }
mTarget = fragment;
mTargetRequestCode = requestCode;
}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 44f1322..32cf1c3 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1110,10 +1110,25 @@
}
}
}
+
f.mHost = mHost;
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
+
+ // If we have a target fragment, push it along to at least CREATED
+ // so that this one can rely on it as an initialized dependency.
+ if (f.mTarget != null) {
+ if (!mActive.contains(f.mTarget)) {
+ throw new IllegalStateException("Fragment " + f
+ + " declared target fragment " + f.mTarget
+ + " that does not belong to this FragmentManager!");
+ }
+ if (f.mTarget.mState < Fragment.CREATED) {
+ moveToState(f.mTarget, Fragment.CREATED, 0, 0, true);
+ }
+ }
+
dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
f.mCalled = false;
f.onAttach(mHost.getContext());