Primary navigation fragments
Port of I82cd22cda6e9ee22fe293c36859e99f49d36a129 from frameworks/support Add API to track the "primary navigation fragment" for a FragmentManager. This allows designating one active fragment in a FragmentManager as the intended nested recipient of navigation actions such as popping the back stack. The FragmentManager popBackStack methods will now delegate to the child FragmentManager of the current primary navigation fragment first before trying to pop its own back stack. This can only happen if a back stack transaction id or back stack entry name is not provided to the pop operation, as these names and ids are namespaced to each individual FragmentManager. Primary navigation fragments are set as part of a FragmentTransaction and follow the associated expectations. Transactions added to the back stack will be fully reversed when popped, restoring the previous primary navigation fragment for the FragmentManager. If a primary navigation fragment is removed from the FragmentManager, the primary navigation fragment will be set to null. Bug: 30596279 Test: CTS Change-Id: Ied7c1515f27142d6f4cd523f16eb35d38a2a2380
This commit is contained in:
@@ -4684,6 +4684,7 @@ package android.app {
|
||||
method public abstract android.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
|
||||
method public abstract int getBackStackEntryCount();
|
||||
method public abstract android.app.Fragment getFragment(android.os.Bundle, java.lang.String);
|
||||
method public abstract android.app.Fragment getPrimaryNavigationFragment();
|
||||
method public void invalidateOptionsMenu();
|
||||
method public abstract boolean isDestroyed();
|
||||
method public abstract void popBackStack();
|
||||
@@ -4760,6 +4761,7 @@ package android.app {
|
||||
method public abstract android.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
|
||||
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int);
|
||||
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int, int, int);
|
||||
method public abstract android.app.FragmentTransaction setPrimaryNavigationFragment(android.app.Fragment);
|
||||
method public abstract android.app.FragmentTransaction setTransition(int);
|
||||
method public abstract android.app.FragmentTransaction setTransitionStyle(int);
|
||||
method public abstract android.app.FragmentTransaction show(android.app.Fragment);
|
||||
|
||||
@@ -4844,6 +4844,7 @@ package android.app {
|
||||
method public abstract android.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
|
||||
method public abstract int getBackStackEntryCount();
|
||||
method public abstract android.app.Fragment getFragment(android.os.Bundle, java.lang.String);
|
||||
method public abstract android.app.Fragment getPrimaryNavigationFragment();
|
||||
method public void invalidateOptionsMenu();
|
||||
method public abstract boolean isDestroyed();
|
||||
method public abstract void popBackStack();
|
||||
@@ -4920,6 +4921,7 @@ package android.app {
|
||||
method public abstract android.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
|
||||
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int);
|
||||
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int, int, int);
|
||||
method public abstract android.app.FragmentTransaction setPrimaryNavigationFragment(android.app.Fragment);
|
||||
method public abstract android.app.FragmentTransaction setTransition(int);
|
||||
method public abstract android.app.FragmentTransaction setTransitionStyle(int);
|
||||
method public abstract android.app.FragmentTransaction show(android.app.Fragment);
|
||||
|
||||
@@ -4694,6 +4694,7 @@ package android.app {
|
||||
method public abstract android.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
|
||||
method public abstract int getBackStackEntryCount();
|
||||
method public abstract android.app.Fragment getFragment(android.os.Bundle, java.lang.String);
|
||||
method public abstract android.app.Fragment getPrimaryNavigationFragment();
|
||||
method public void invalidateOptionsMenu();
|
||||
method public abstract boolean isDestroyed();
|
||||
method public abstract void popBackStack();
|
||||
@@ -4770,6 +4771,7 @@ package android.app {
|
||||
method public abstract android.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
|
||||
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int);
|
||||
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int, int, int);
|
||||
method public abstract android.app.FragmentTransaction setPrimaryNavigationFragment(android.app.Fragment);
|
||||
method public abstract android.app.FragmentTransaction setTransition(int);
|
||||
method public abstract android.app.FragmentTransaction setTransitionStyle(int);
|
||||
method public abstract android.app.FragmentTransaction show(android.app.Fragment);
|
||||
|
||||
@@ -186,6 +186,8 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
static final int OP_SHOW = 5;
|
||||
static final int OP_DETACH = 6;
|
||||
static final int OP_ATTACH = 7;
|
||||
static final int OP_SET_PRIMARY_NAV = 8;
|
||||
static final int OP_UNSET_PRIMARY_NAV = 9;
|
||||
|
||||
static final class Op {
|
||||
int cmd;
|
||||
@@ -194,6 +196,14 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
int exitAnim;
|
||||
int popEnterAnim;
|
||||
int popExitAnim;
|
||||
|
||||
Op() {
|
||||
}
|
||||
|
||||
Op(int cmd, Fragment fragment) {
|
||||
this.cmd = cmd;
|
||||
this.fragment = fragment;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<Op> mOps = new ArrayList<>();
|
||||
@@ -318,6 +328,13 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
case OP_ATTACH:
|
||||
cmdStr = "ATTACH";
|
||||
break;
|
||||
case OP_SET_PRIMARY_NAV:
|
||||
cmdStr="SET_PRIMARY_NAV";
|
||||
break;
|
||||
case OP_UNSET_PRIMARY_NAV:
|
||||
cmdStr="UNSET_PRIMARY_NAV";
|
||||
break;
|
||||
|
||||
default:
|
||||
cmdStr = "cmd=" + op.cmd;
|
||||
break;
|
||||
@@ -438,10 +455,7 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
fragment.mContainerId = fragment.mFragmentId = containerViewId;
|
||||
}
|
||||
|
||||
Op op = new Op();
|
||||
op.cmd = opcmd;
|
||||
op.fragment = fragment;
|
||||
addOp(op);
|
||||
addOp(new Op(opcmd, fragment));
|
||||
}
|
||||
|
||||
public FragmentTransaction replace(int containerViewId, Fragment fragment) {
|
||||
@@ -458,46 +472,37 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
}
|
||||
|
||||
public FragmentTransaction remove(Fragment fragment) {
|
||||
Op op = new Op();
|
||||
op.cmd = OP_REMOVE;
|
||||
op.fragment = fragment;
|
||||
addOp(op);
|
||||
addOp(new Op(OP_REMOVE, fragment));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public FragmentTransaction hide(Fragment fragment) {
|
||||
Op op = new Op();
|
||||
op.cmd = OP_HIDE;
|
||||
op.fragment = fragment;
|
||||
addOp(op);
|
||||
addOp(new Op(OP_HIDE, fragment));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public FragmentTransaction show(Fragment fragment) {
|
||||
Op op = new Op();
|
||||
op.cmd = OP_SHOW;
|
||||
op.fragment = fragment;
|
||||
addOp(op);
|
||||
addOp(new Op(OP_SHOW, fragment));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public FragmentTransaction detach(Fragment fragment) {
|
||||
Op op = new Op();
|
||||
op.cmd = OP_DETACH;
|
||||
op.fragment = fragment;
|
||||
addOp(op);
|
||||
addOp(new Op(OP_DETACH, fragment));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public FragmentTransaction attach(Fragment fragment) {
|
||||
Op op = new Op();
|
||||
op.cmd = OP_ATTACH;
|
||||
op.fragment = fragment;
|
||||
addOp(op);
|
||||
addOp(new Op(OP_ATTACH, fragment));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public FragmentTransaction setPrimaryNavigationFragment(Fragment fragment) {
|
||||
addOp(new Op(OP_SET_PRIMARY_NAV, fragment));
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -689,7 +694,8 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
final int numOps = mOps.size();
|
||||
for (int opNum = 0; opNum < numOps; opNum++) {
|
||||
final Op op = mOps.get(opNum);
|
||||
if (op.fragment.mContainerId == containerId) {
|
||||
final int fragContainer = op.fragment != null ? op.fragment.mContainerId : 0;
|
||||
if (fragContainer != 0 && fragContainer == containerId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -704,7 +710,7 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
int lastContainer = -1;
|
||||
for (int opNum = 0; opNum < numOps; opNum++) {
|
||||
final Op op = mOps.get(opNum);
|
||||
final int container = op.fragment.mContainerId;
|
||||
final int container = op.fragment != null ? op.fragment.mContainerId : 0;
|
||||
if (container != 0 && container != lastContainer) {
|
||||
lastContainer = container;
|
||||
for (int i = startIndex; i < endIndex; i++) {
|
||||
@@ -712,7 +718,9 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
final int numThoseOps = record.mOps.size();
|
||||
for (int thoseOpIndex = 0; thoseOpIndex < numThoseOps; thoseOpIndex++) {
|
||||
final Op thatOp = record.mOps.get(thoseOpIndex);
|
||||
if (thatOp.fragment.mContainerId == container) {
|
||||
final int thatContainer = thatOp.fragment != null
|
||||
? thatOp.fragment.mContainerId : 0;
|
||||
if (thatContainer == container) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -731,7 +739,9 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
for (int opNum = 0; opNum < numOps; opNum++) {
|
||||
final Op op = mOps.get(opNum);
|
||||
final Fragment f = op.fragment;
|
||||
f.setNextTransition(mTransition, mTransitionStyle);
|
||||
if (f != null) {
|
||||
f.setNextTransition(mTransition, mTransitionStyle);
|
||||
}
|
||||
switch (op.cmd) {
|
||||
case OP_ADD:
|
||||
f.setNextAnim(op.enterAnim);
|
||||
@@ -757,10 +767,16 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
f.setNextAnim(op.enterAnim);
|
||||
mManager.attachFragment(f);
|
||||
break;
|
||||
case OP_SET_PRIMARY_NAV:
|
||||
mManager.setPrimaryNavigationFragment(f);
|
||||
break;
|
||||
case OP_UNSET_PRIMARY_NAV:
|
||||
mManager.setPrimaryNavigationFragment(null);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
|
||||
}
|
||||
if (!mAllowOptimization && op.cmd != OP_ADD) {
|
||||
if (!mAllowOptimization && op.cmd != OP_ADD && f != null) {
|
||||
mManager.moveFragmentToExpectedState(f);
|
||||
}
|
||||
}
|
||||
@@ -778,7 +794,10 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
|
||||
final Op op = mOps.get(opNum);
|
||||
Fragment f = op.fragment;
|
||||
f.setNextTransition(FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
|
||||
if (f != null) {
|
||||
f.setNextTransition(FragmentManagerImpl.reverseTransit(mTransition),
|
||||
mTransitionStyle);
|
||||
}
|
||||
switch (op.cmd) {
|
||||
case OP_ADD:
|
||||
f.setNextAnim(op.popExitAnim);
|
||||
@@ -804,10 +823,16 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
f.setNextAnim(op.popExitAnim);
|
||||
mManager.detachFragment(f);
|
||||
break;
|
||||
case OP_SET_PRIMARY_NAV:
|
||||
mManager.setPrimaryNavigationFragment(null);
|
||||
break;
|
||||
case OP_UNSET_PRIMARY_NAV:
|
||||
mManager.setPrimaryNavigationFragment(f);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
|
||||
}
|
||||
if (!mAllowOptimization && op.cmd != OP_REMOVE) {
|
||||
if (!mAllowOptimization && op.cmd != OP_REMOVE && f != null) {
|
||||
mManager.moveFragmentToExpectedState(f);
|
||||
}
|
||||
}
|
||||
@@ -817,15 +842,28 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all OP_REPLACE ops and replaces them with the proper add and remove
|
||||
* operations that are equivalent to the replace. This must be called prior to
|
||||
* {@link #executeOps()} or any other call that operations on mOps.
|
||||
* Expands all meta-ops into their more primitive equivalents. This must be called prior to
|
||||
* {@link #executeOps()} or any other call that operations on mOps for forward navigation.
|
||||
* It should not be called for pop/reverse navigation operations.
|
||||
*
|
||||
* <p>Removes all OP_REPLACE ops and replaces them with the proper add and remove
|
||||
* operations that are equivalent to the replace.</p>
|
||||
*
|
||||
* <p>Adds OP_UNSET_PRIMARY_NAV ops to match OP_SET_PRIMARY_NAV, OP_REMOVE and OP_DETACH
|
||||
* ops so that we can restore the old primary nav fragment later. Since callers call this
|
||||
* method in a loop before running ops from several transactions at once, the caller should
|
||||
* pass the return value from this method as the oldPrimaryNav parameter for the next call.
|
||||
* The first call in such a loop should pass the value of
|
||||
* {@link FragmentManager#getPrimaryNavigationFragment()}.</p>
|
||||
*
|
||||
* @param added Initialized to the fragments that are in the mManager.mAdded, this
|
||||
* will be modified to contain the fragments that will be in mAdded
|
||||
* after the execution ({@link #executeOps()}.
|
||||
* @param oldPrimaryNav The tracked primary navigation fragment as of the beginning of
|
||||
* this set of ops
|
||||
* @return the new oldPrimaryNav fragment after this record's ops would be run
|
||||
*/
|
||||
void expandReplaceOps(ArrayList<Fragment> added) {
|
||||
Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
|
||||
for (int opNum = 0; opNum < mOps.size(); opNum++) {
|
||||
final Op op = mOps.get(opNum);
|
||||
switch (op.cmd) {
|
||||
@@ -834,22 +872,33 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
added.add(op.fragment);
|
||||
break;
|
||||
case OP_REMOVE:
|
||||
case OP_DETACH:
|
||||
case OP_DETACH: {
|
||||
added.remove(op.fragment);
|
||||
break;
|
||||
if (op.fragment == oldPrimaryNav) {
|
||||
mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, op.fragment));
|
||||
opNum++;
|
||||
oldPrimaryNav = null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OP_REPLACE: {
|
||||
Fragment f = op.fragment;
|
||||
int containerId = f.mContainerId;
|
||||
final Fragment f = op.fragment;
|
||||
final int containerId = f.mContainerId;
|
||||
boolean alreadyAdded = false;
|
||||
for (int i = added.size() - 1; i >= 0; i--) {
|
||||
Fragment old = added.get(i);
|
||||
final Fragment old = added.get(i);
|
||||
if (old.mContainerId == containerId) {
|
||||
if (old == f) {
|
||||
alreadyAdded = true;
|
||||
} else {
|
||||
Op removeOp = new Op();
|
||||
removeOp.cmd = OP_REMOVE;
|
||||
removeOp.fragment = old;
|
||||
// This is duplicated from above since we only make
|
||||
// a single pass for expanding ops. Unset any outgoing primary nav.
|
||||
if (old == oldPrimaryNav) {
|
||||
mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, old));
|
||||
opNum++;
|
||||
oldPrimaryNav = null;
|
||||
}
|
||||
final Op removeOp = new Op(OP_REMOVE, old);
|
||||
removeOp.enterAnim = op.enterAnim;
|
||||
removeOp.popEnterAnim = op.popEnterAnim;
|
||||
removeOp.exitAnim = op.exitAnim;
|
||||
@@ -869,8 +918,18 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OP_SET_PRIMARY_NAV: {
|
||||
// It's ok if this is null, that means we will restore to no active
|
||||
// primary navigation fragment on a pop.
|
||||
mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, oldPrimaryNav));
|
||||
opNum++;
|
||||
// Will be set by the OP_SET_PRIMARY_NAV we inserted before when run
|
||||
oldPrimaryNav = op.fragment;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return oldPrimaryNav;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -917,8 +976,8 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
|
||||
private static boolean isFragmentPostponed(Op op) {
|
||||
final Fragment fragment = op.fragment;
|
||||
return (fragment.mAdded && fragment.mView != null && !fragment.mDetached &&
|
||||
!fragment.mHidden && fragment.isPostponed());
|
||||
return fragment != null && fragment.mAdded && fragment.mView != null && !fragment.mDetached
|
||||
&& !fragment.mHidden && fragment.isPostponed();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
||||
@@ -359,6 +359,18 @@ public abstract class FragmentManager {
|
||||
*/
|
||||
public abstract void unregisterFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb);
|
||||
|
||||
/**
|
||||
* Return the currently active primary navigation fragment for this FragmentManager.
|
||||
*
|
||||
* <p>The primary navigation fragment's
|
||||
* {@link Fragment#getChildFragmentManager() child FragmentManager} will be called first
|
||||
* to process delegated navigation actions such as {@link #popBackStack()} if no ID
|
||||
* or transaction name is provided to pop to.</p>
|
||||
*
|
||||
* @return the fragment designated as the primary navigation fragment
|
||||
*/
|
||||
public abstract Fragment getPrimaryNavigationFragment();
|
||||
|
||||
/**
|
||||
* Print the FragmentManager's state into the given stream.
|
||||
*
|
||||
@@ -524,6 +536,7 @@ final class FragmentManagerState implements Parcelable {
|
||||
FragmentState[] mActive;
|
||||
int[] mAdded;
|
||||
BackStackState[] mBackStack;
|
||||
int mPrimaryNavActiveIndex = -1;
|
||||
|
||||
public FragmentManagerState() {
|
||||
}
|
||||
@@ -532,6 +545,7 @@ final class FragmentManagerState implements Parcelable {
|
||||
mActive = in.createTypedArray(FragmentState.CREATOR);
|
||||
mAdded = in.createIntArray();
|
||||
mBackStack = in.createTypedArray(BackStackState.CREATOR);
|
||||
mPrimaryNavActiveIndex = in.readInt();
|
||||
}
|
||||
|
||||
public int describeContents() {
|
||||
@@ -542,6 +556,7 @@ final class FragmentManagerState implements Parcelable {
|
||||
dest.writeTypedArray(mActive, flags);
|
||||
dest.writeIntArray(mAdded);
|
||||
dest.writeTypedArray(mBackStack, flags);
|
||||
dest.writeInt(mPrimaryNavActiveIndex);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<FragmentManagerState> CREATOR
|
||||
@@ -626,6 +641,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
|
||||
FragmentHostCallback<?> mHost;
|
||||
FragmentContainer mContainer;
|
||||
Fragment mParent;
|
||||
Fragment mPrimaryNav;
|
||||
|
||||
boolean mNeedMenuInvalidate;
|
||||
boolean mStateSaved;
|
||||
@@ -783,6 +799,16 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
|
||||
execPendingActions();
|
||||
ensureExecReady(true);
|
||||
|
||||
if (mPrimaryNav != null // We have a primary nav fragment
|
||||
&& id < 0 // No valid id (since they're local)
|
||||
&& name == null) { // no name to pop to (since they're local)
|
||||
final FragmentManager childManager = mPrimaryNav.mChildFragmentManager;
|
||||
if (childManager != null && childManager.popBackStackImmediate()) {
|
||||
// We did something, just not to this specific FragmentManager. Return true.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean executePop = popBackStackState(mTmpRecords, mTmpIsPop, name, id, flags);
|
||||
if (executePop) {
|
||||
mExecutingActions = true;
|
||||
@@ -2038,11 +2064,12 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
|
||||
if (mAdded != null) {
|
||||
mTmpAddedFragments.addAll(mAdded);
|
||||
}
|
||||
Fragment oldPrimaryNav = getPrimaryNavigationFragment();
|
||||
for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
|
||||
final BackStackRecord record = records.get(recordNum);
|
||||
final boolean isPop = isRecordPop.get(recordNum);
|
||||
if (!isPop) {
|
||||
record.expandReplaceOps(mTmpAddedFragments);
|
||||
oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
|
||||
} else {
|
||||
record.trackAddedFragmentsInPop(mTmpAddedFragments);
|
||||
}
|
||||
@@ -2318,20 +2345,20 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
|
||||
*/
|
||||
private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records,
|
||||
ArrayList<Boolean> isPop) {
|
||||
int numActions;
|
||||
boolean didSomething = false;
|
||||
synchronized (this) {
|
||||
if (mPendingActions == null || mPendingActions.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
numActions = mPendingActions.size();
|
||||
final int numActions = mPendingActions.size();
|
||||
for (int i = 0; i < numActions; i++) {
|
||||
mPendingActions.get(i).generateOps(records, isPop);
|
||||
didSomething |= mPendingActions.get(i).generateOps(records, isPop);
|
||||
}
|
||||
mPendingActions.clear();
|
||||
mHost.getHandler().removeCallbacks(mExecCommit);
|
||||
}
|
||||
return numActions > 0;
|
||||
return didSomething;
|
||||
}
|
||||
|
||||
void doPendingDeferredStart() {
|
||||
@@ -2618,6 +2645,9 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
|
||||
fms.mActive = active;
|
||||
fms.mAdded = added;
|
||||
fms.mBackStack = backStack;
|
||||
if (mPrimaryNav != null) {
|
||||
fms.mPrimaryNavActiveIndex = mPrimaryNav.mIndex;
|
||||
}
|
||||
return fms;
|
||||
}
|
||||
|
||||
@@ -2744,6 +2774,10 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
|
||||
} else {
|
||||
mBackStack = null;
|
||||
}
|
||||
|
||||
if (fms.mPrimaryNavActiveIndex >= 0) {
|
||||
mPrimaryNav = mActive.get(fms.mPrimaryNavActiveIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public void attachController(FragmentHostCallback<?> host, FragmentContainer container,
|
||||
@@ -2942,6 +2976,19 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
|
||||
}
|
||||
}
|
||||
|
||||
public void setPrimaryNavigationFragment(Fragment f) {
|
||||
if (f != null && (f.getFragmentManager() != this || f.mIndex >= mActive.size()
|
||||
|| mActive.get(f.mIndex) != f)) {
|
||||
throw new IllegalArgumentException("Fragment " + f
|
||||
+ " is not an active fragment of FragmentManager " + this);
|
||||
}
|
||||
mPrimaryNav = f;
|
||||
}
|
||||
|
||||
public Fragment getPrimaryNavigationFragment() {
|
||||
return mPrimaryNav;
|
||||
}
|
||||
|
||||
public void registerFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb,
|
||||
boolean recursive) {
|
||||
if (mLifecycleCallbacks == null) {
|
||||
@@ -3386,6 +3433,16 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
|
||||
@Override
|
||||
public boolean generateOps(ArrayList<BackStackRecord> records,
|
||||
ArrayList<Boolean> isRecordPop) {
|
||||
if (mPrimaryNav != null // We have a primary nav fragment
|
||||
&& mId < 0 // No valid id (since they're local)
|
||||
&& mName == null) { // no name to pop to (since they're local)
|
||||
final FragmentManager childManager = mPrimaryNav.mChildFragmentManager;
|
||||
if (childManager != null && childManager.popBackStackImmediate()) {
|
||||
// We didn't add any operations for this FragmentManager even though
|
||||
// a child did do work.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return popBackStackState(records, isRecordPop, mName, mId, mFlags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,24 @@ public abstract class FragmentTransaction {
|
||||
*/
|
||||
public abstract FragmentTransaction attach(Fragment fragment);
|
||||
|
||||
/**
|
||||
* Set a currently active fragment in this FragmentManager as the primary navigation fragment.
|
||||
*
|
||||
* <p>The primary navigation fragment's
|
||||
* {@link Fragment#getChildFragmentManager() child FragmentManager} will be called first
|
||||
* to process delegated navigation actions such as {@link FragmentManager#popBackStack()}
|
||||
* if no ID or transaction name is provided to pop to. Navigation operations outside of the
|
||||
* fragment system may choose to delegate those actions to the primary navigation fragment
|
||||
* as returned by {@link FragmentManager#getPrimaryNavigationFragment()}.</p>
|
||||
*
|
||||
* <p>The fragment provided must currently be added to the FragmentManager to be set as
|
||||
* a primary navigation fragment, or previously added as part of this transaction.</p>
|
||||
*
|
||||
* @param fragment the fragment to set as the primary navigation fragment
|
||||
* @return the same FragmentTransaction instance
|
||||
*/
|
||||
public abstract FragmentTransaction setPrimaryNavigationFragment(Fragment fragment);
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if this transaction contains no operations,
|
||||
* <code>false</code> otherwise.
|
||||
|
||||
@@ -43,14 +43,16 @@ class FragmentTransition {
|
||||
* REPLACE operations have already been replaced by add/remove operations.
|
||||
*/
|
||||
private static final int[] INVERSE_OPS = {
|
||||
BackStackRecord.OP_NULL, // inverse of OP_NULL (error)
|
||||
BackStackRecord.OP_REMOVE, // inverse of OP_ADD
|
||||
BackStackRecord.OP_NULL, // inverse of OP_REPLACE (error)
|
||||
BackStackRecord.OP_ADD, // inverse of OP_REMOVE
|
||||
BackStackRecord.OP_SHOW, // inverse of OP_HIDE
|
||||
BackStackRecord.OP_HIDE, // inverse of OP_SHOW
|
||||
BackStackRecord.OP_ATTACH, // inverse of OP_DETACH
|
||||
BackStackRecord.OP_DETACH, // inverse of OP_ATTACH
|
||||
BackStackRecord.OP_NULL, // inverse of OP_NULL (error)
|
||||
BackStackRecord.OP_REMOVE, // inverse of OP_ADD
|
||||
BackStackRecord.OP_NULL, // inverse of OP_REPLACE (error)
|
||||
BackStackRecord.OP_ADD, // inverse of OP_REMOVE
|
||||
BackStackRecord.OP_SHOW, // inverse of OP_HIDE
|
||||
BackStackRecord.OP_HIDE, // inverse of OP_SHOW
|
||||
BackStackRecord.OP_ATTACH, // inverse of OP_DETACH
|
||||
BackStackRecord.OP_DETACH, // inverse of OP_ATTACH
|
||||
BackStackRecord.OP_UNSET_PRIMARY_NAV, // inverse of OP_SET_PRIMARY_NAV
|
||||
BackStackRecord.OP_SET_PRIMARY_NAV, // inverse of OP_UNSET_PRIMARY_NAV
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1232,6 +1234,9 @@ class FragmentTransition {
|
||||
SparseArray<FragmentContainerTransition> transitioningFragments, boolean isPop,
|
||||
boolean isOptimizedTransaction) {
|
||||
final Fragment fragment = op.fragment;
|
||||
if (fragment == null) {
|
||||
return; // no fragment, no transition
|
||||
}
|
||||
final int containerId = fragment.mContainerId;
|
||||
if (containerId == 0) {
|
||||
return; // no container, no transition
|
||||
|
||||
Reference in New Issue
Block a user