Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2045f8f authored by George Mount's avatar George Mount
Browse files

Convert BackStackRecord Operations to ArrayList.

This slightly simplifies operations to add and remove operations
from the back stack by using an ArrayList instead of a custom
linked list.

Also removed fragments during replace are expanded into the
back stack to make the tracking of them simpler.

Change-Id: Ifac857396e4c6d42ddd44a3dc0f855649171e49c
parent fd9c9ee1
Loading
Loading
Loading
Loading
+122 −233
Original line number Diff line number Diff line
@@ -54,39 +54,22 @@ final class BackStackState implements Parcelable {
    final ArrayList<String> mSharedElementTargetNames;

    public BackStackState(FragmentManagerImpl fm, BackStackRecord bse) {
        int numRemoved = 0;
        BackStackRecord.Op op = bse.mHead;
        while (op != null) {
            if (op.removed != null) {
                numRemoved += op.removed.size();
            }
            op = op.next;
        }
        mOps = new int[bse.mNumOp * 7 + numRemoved];
        final int numOps = bse.mOps.size();
        mOps = new int[numOps * 6];

        if (!bse.mAddToBackStack) {
            throw new IllegalStateException("Not on back stack");
        }

        op = bse.mHead;
        int pos = 0;
        while (op != null) {
        for (int opNum = 0; opNum < numOps; opNum++) {
            final BackStackRecord.Op op = bse.mOps.get(opNum);
            mOps[pos++] = op.cmd;
            mOps[pos++] = op.fragment != null ? op.fragment.mIndex : -1;
            mOps[pos++] = op.enterAnim;
            mOps[pos++] = op.exitAnim;
            mOps[pos++] = op.popEnterAnim;
            mOps[pos++] = op.popExitAnim;
            if (op.removed != null) {
                final int N = op.removed.size();
                mOps[pos++] = N;
                for (int i = 0; i < N; i++) {
                    mOps[pos++] = op.removed.get(i).mIndex;
                }
            } else {
                mOps[pos++] = 0;
            }
            op = op.next;
        }
        mTransition = bse.mTransition;
        mTransitionStyle = bse.mTransitionStyle;
@@ -136,18 +119,6 @@ final class BackStackState implements Parcelable {
            op.exitAnim = mOps[pos++];
            op.popEnterAnim = mOps[pos++];
            op.popExitAnim = mOps[pos++];
            final int N = mOps[pos++];
            if (N > 0) {
                op.removed = new ArrayList<Fragment>(N);
                for (int i = 0; i < N; i++) {
                    if (FragmentManagerImpl.DEBUG) {
                        Log.v(FragmentManagerImpl.TAG,
                                "Instantiate " + bse + " set remove fragment #" + mOps[pos]);
                    }
                    Fragment r = fm.mActive.get(mOps[pos++]);
                    op.removed.add(r);
                }
            }
            bse.mEnterAnim = op.enterAnim;
            bse.mExitAnim = op.exitAnim;
            bse.mPopEnterAnim = op.popEnterAnim;
@@ -219,20 +190,15 @@ final class BackStackRecord extends FragmentTransaction implements
    static final int OP_ATTACH = 7;

    static final class Op {
        Op next;
        Op prev;
        int cmd;
        Fragment fragment;
        int enterAnim;
        int exitAnim;
        int popEnterAnim;
        int popExitAnim;
        ArrayList<Fragment> removed;
    }

    Op mHead;
    Op mTail;
    int mNumOp;
    ArrayList<Op> mOps = new ArrayList<>();
    int mEnterAnim;
    int mExitAnim;
    int mPopEnterAnim;
@@ -320,13 +286,13 @@ final class BackStackRecord extends FragmentTransaction implements
            }
        }

        if (mHead != null) {
        if (!mOps.isEmpty()) {
            writer.print(prefix);
            writer.println("Operations:");
            String innerPrefix = prefix + "    ";
            Op op = mHead;
            int num = 0;
            while (op != null) {
            final int numOps = mOps.size();
            for (int opNum = 0; opNum < numOps; opNum++) {
                final Op op = mOps.get(opNum);
                String cmdStr;
                switch (op.cmd) {
                    case OP_NULL:
@@ -359,7 +325,7 @@ final class BackStackRecord extends FragmentTransaction implements
                }
                writer.print(prefix);
                writer.print("  Op #");
                writer.print(num);
                writer.print(opNum);
                writer.print(": ");
                writer.print(cmdStr);
                writer.print(" ");
@@ -380,25 +346,6 @@ final class BackStackRecord extends FragmentTransaction implements
                        writer.println(Integer.toHexString(op.popExitAnim));
                    }
                }
                if (op.removed != null && op.removed.size() > 0) {
                    for (int i = 0; i < op.removed.size(); i++) {
                        writer.print(innerPrefix);
                        if (op.removed.size() == 1) {
                            writer.print("Removed: ");
                        } else {
                            if (i == 0) {
                                writer.println("Removed:");
                            }
                            writer.print(innerPrefix);
                            writer.print("  #");
                            writer.print(i);
                            writer.print(": ");
                        }
                        writer.println(op.removed.get(i));
                    }
                }
                op = op.next;
                num++;
            }
        }
    }
@@ -434,18 +381,11 @@ final class BackStackRecord extends FragmentTransaction implements
    }

    void addOp(Op op) {
        if (mHead == null) {
            mHead = mTail = op;
        } else {
            op.prev = mTail;
            mTail.next = op;
            mTail = op;
        }
        mOps.add(op);
        op.enterAnim = mEnterAnim;
        op.exitAnim = mExitAnim;
        op.popEnterAnim = mPopEnterAnim;
        op.popExitAnim = mPopExitAnim;
        mNumOp++;
    }

    public FragmentTransaction add(Fragment fragment, String tag) {
@@ -660,8 +600,9 @@ final class BackStackRecord extends FragmentTransaction implements
            Log.v(TAG, "Bump nesting in " + this
                    + " by " + amt);
        }
        Op op = mHead;
        while (op != null) {
        final int numOps = mOps.size();
        for (int opNum = 0; opNum < numOps; opNum++) {
            final Op op = mOps.get(opNum);
            if (op.fragment != null) {
                op.fragment.mBackStackNesting += amt;
                if (FragmentManagerImpl.DEBUG) {
@@ -669,17 +610,6 @@ final class BackStackRecord extends FragmentTransaction implements
                            + op.fragment + " to " + op.fragment.mBackStackNesting);
                }
            }
            if (op.removed != null) {
                for (int i = op.removed.size() - 1; i >= 0; i--) {
                    Fragment r = op.removed.get(i);
                    r.mBackStackNesting += amt;
                    if (FragmentManagerImpl.DEBUG) {
                        Log.v(TAG, "Bump nesting of "
                                + r + " to " + r.mBackStackNesting);
                    }
                }
            }
            op = op.next;
        }
    }

@@ -735,6 +665,7 @@ final class BackStackRecord extends FragmentTransaction implements
            }
        }

        expandReplaceOps();
        bumpBackStackNesting(1);

        if (mManager.mCurState >= Fragment.CREATED) {
@@ -744,90 +675,40 @@ final class BackStackRecord extends FragmentTransaction implements
            beginTransition(firstOutFragments, lastInFragments, false);
        }

        Op op = mHead;
        while (op != null) {
            switch (op.cmd) {
                case OP_ADD: {
        final int numOps = mOps.size();
        for (int opNum = 0; opNum < numOps; opNum++) {
            final Op op = mOps.get(opNum);
            Fragment f = op.fragment;
            switch (op.cmd) {
                case OP_ADD:
                    f.mNextAnim = op.enterAnim;
                    mManager.addFragment(f, false);
                }
                break;
                case OP_REPLACE: {
                    Fragment f = op.fragment;
                    int containerId = f.mContainerId;
                    if (mManager.mAdded != null) {
                        for (int i = mManager.mAdded.size() - 1; i >= 0; i--) {
                            Fragment old = mManager.mAdded.get(i);
                            if (FragmentManagerImpl.DEBUG) {
                                Log.v(TAG,
                                        "OP_REPLACE: adding=" + f + " old=" + old);
                            }
                            if (old.mContainerId == containerId) {
                                if (old == f) {
                                    op.fragment = f = null;
                                } else {
                                    if (op.removed == null) {
                                        op.removed = new ArrayList<Fragment>();
                                    }
                                    op.removed.add(old);
                                    old.mNextAnim = op.exitAnim;
                                    if (mAddToBackStack) {
                                        old.mBackStackNesting += 1;
                                        if (FragmentManagerImpl.DEBUG) {
                                            Log.v(TAG, "Bump nesting of "
                                                    + old + " to " + old.mBackStackNesting);
                                        }
                                    }
                                    mManager.removeFragment(old, mTransition, mTransitionStyle);
                                }
                            }
                        }
                    }
                    if (f != null) {
                        f.mNextAnim = op.enterAnim;
                        mManager.addFragment(f, false);
                    }
                }
                    break;
                case OP_REMOVE: {
                    Fragment f = op.fragment;
                case OP_REMOVE:
                    f.mNextAnim = op.exitAnim;
                    mManager.removeFragment(f, mTransition, mTransitionStyle);
                }
                    break;
                case OP_HIDE: {
                    Fragment f = op.fragment;
                case OP_HIDE:
                    f.mNextAnim = op.exitAnim;
                    mManager.hideFragment(f, mTransition, mTransitionStyle);
                }
                    break;
                case OP_SHOW: {
                    Fragment f = op.fragment;
                case OP_SHOW:
                    f.mNextAnim = op.enterAnim;
                    mManager.showFragment(f, mTransition, mTransitionStyle);
                }
                    break;
                case OP_DETACH: {
                    Fragment f = op.fragment;
                case OP_DETACH:
                    f.mNextAnim = op.exitAnim;
                    mManager.detachFragment(f, mTransition, mTransitionStyle);
                }
                    break;
                case OP_ATTACH: {
                    Fragment f = op.fragment;
                case OP_ATTACH:
                    f.mNextAnim = op.enterAnim;
                    mManager.attachFragment(f, mTransition, mTransitionStyle);
                }
                    break;
                default: {
                default:
                    throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
            }
        }

            op = op.next;
        }

        mManager.moveToState(mManager.mCurState, mTransition,
                mTransitionStyle, true);

@@ -836,6 +717,72 @@ final class BackStackRecord extends FragmentTransaction implements
        }
    }

    private void expandReplaceOps() {
        final int numOps = mOps.size();

        boolean hasReplace = false;
        // Before we do anything, check to see if any replace operations exist:
        for (int opNum = 0; opNum < numOps; opNum++) {
            final Op op = mOps.get(opNum);
            if (op.cmd == OP_REPLACE) {
                hasReplace = true;
                break;
            }
        }

        if (!hasReplace) {
            return; // nothing to expand
        }

        ArrayList<Fragment> added = (mManager.mAdded == null) ? new ArrayList<Fragment>() :
                new ArrayList<>(mManager.mAdded);
        for (int opNum = 0; opNum < mOps.size(); opNum++) {
            final Op op = mOps.get(opNum);
            switch (op.cmd) {
                case OP_ADD:
                case OP_ATTACH:
                    added.add(op.fragment);
                break;
                case OP_REMOVE:
                case OP_DETACH:
                    added.remove(op.fragment);
                    break;
                case OP_REPLACE: {
                    Fragment f = op.fragment;
                    int containerId = f.mContainerId;
                    boolean alreadyAdded = false;
                    for (int i = added.size() - 1; i >= 0; i--) {
                        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;
                                removeOp.enterAnim = op.enterAnim;
                                removeOp.popEnterAnim = op.popEnterAnim;
                                removeOp.exitAnim = op.exitAnim;
                                removeOp.popExitAnim = op.popExitAnim;
                                mOps.add(opNum, removeOp);
                                added.remove(old);
                                opNum++;
                            }
                        }
                    }
                    if (alreadyAdded) {
                        mOps.remove(opNum);
                        opNum--;
                    } else {
                        op.cmd = OP_ADD;
                        added.add(f);
                    }
                }
                break;
            }
        }
    }

    private static void setFirstOut(SparseArray<Fragment> firstOutFragments,
                            SparseArray<Fragment> lastInFragments, Fragment fragment) {
        if (fragment != null) {
@@ -889,30 +836,13 @@ final class BackStackRecord extends FragmentTransaction implements
        if (!mManager.mContainer.onHasView()) {
            return; // nothing to see, so no transitions
        }
        Op op = mHead;
        while (op != null) {
        final int numOps = mOps.size();
        for (int opNum = 0; opNum < numOps; opNum++) {
            final Op op = mOps.get(opNum);
            switch (op.cmd) {
                case OP_ADD:
                    setLastIn(firstOutFragments, lastInFragments, op.fragment);
                    break;
                case OP_REPLACE: {
                    Fragment f = op.fragment;
                    if (mManager.mAdded != null) {
                        for (int i = 0; i < mManager.mAdded.size(); i++) {
                            Fragment old = mManager.mAdded.get(i);
                            if (f == null || old.mContainerId == f.mContainerId) {
                                if (old == f) {
                                    f = null;
                                    lastInFragments.remove(old.mContainerId);
                                } else {
                                    setFirstOut(firstOutFragments, lastInFragments, old);
                                }
                            }
                        }
                    }
                    setLastIn(firstOutFragments, lastInFragments, op.fragment);
                    break;
                }
                case OP_REMOVE:
                    setFirstOut(firstOutFragments, lastInFragments, op.fragment);
                    break;
@@ -929,8 +859,6 @@ final class BackStackRecord extends FragmentTransaction implements
                    setLastIn(firstOutFragments, lastInFragments, op.fragment);
                    break;
            }

            op = op.next;
        }
    }

@@ -948,20 +876,13 @@ final class BackStackRecord extends FragmentTransaction implements
        if (!mManager.mContainer.onHasView()) {
            return; // nothing to see, so no transitions
        }
        Op op = mTail;
        while (op != null) {
        final int numOps = mOps.size();
        for (int opNum = numOps - 1; opNum >= 0; opNum--) {
            final Op op = mOps.get(opNum);
            switch (op.cmd) {
                case OP_ADD:
                    setFirstOut(firstOutFragments, lastInFragments, op.fragment);
                    break;
                case OP_REPLACE:
                    if (op.removed != null) {
                        for (int i = op.removed.size() - 1; i >= 0; i--) {
                            setLastIn(firstOutFragments, lastInFragments, op.removed.get(i));
                        }
                    }
                    setFirstOut(firstOutFragments, lastInFragments, op.fragment);
                    break;
                case OP_REMOVE:
                    setLastIn(firstOutFragments, lastInFragments, op.fragment);
                    break;
@@ -978,8 +899,6 @@ final class BackStackRecord extends FragmentTransaction implements
                    setFirstOut(firstOutFragments, lastInFragments, op.fragment);
                    break;
            }

            op = op.prev;
        }
    }

@@ -1689,76 +1608,46 @@ final class BackStackRecord extends FragmentTransaction implements

        bumpBackStackNesting(-1);

        Op op = mTail;
        while (op != null) {
            switch (op.cmd) {
                case OP_ADD: {
        final int numOps = mOps.size();
        for (int opNum = numOps - 1; opNum >= 0; opNum--) {
            final Op op = mOps.get(opNum);
            Fragment f = op.fragment;
            switch (op.cmd) {
                case OP_ADD:
                    f.mNextAnim = op.popExitAnim;
                    mManager.removeFragment(f,
                            FragmentManagerImpl.reverseTransit(mTransition),
                            mTransitionStyle);
                }
                break;
                case OP_REPLACE: {
                    Fragment f = op.fragment;
                    if (f != null) {
                        f.mNextAnim = op.popExitAnim;
                        mManager.removeFragment(f,
                                FragmentManagerImpl.reverseTransit(mTransition),
                                mTransitionStyle);
                    }
                    if (op.removed != null) {
                        for (int i = 0; i < op.removed.size(); i++) {
                            Fragment old = op.removed.get(i);
                            old.mNextAnim = op.popEnterAnim;
                            mManager.addFragment(old, false);
                        }
                    }
                }
                    break;
                case OP_REMOVE: {
                    Fragment f = op.fragment;
                case OP_REMOVE:
                    f.mNextAnim = op.popEnterAnim;
                    mManager.addFragment(f, false);
                }
                    break;
                case OP_HIDE: {
                    Fragment f = op.fragment;
                case OP_HIDE:
                    f.mNextAnim = op.popEnterAnim;
                    mManager.showFragment(f,
                            FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
                }
                    break;
                case OP_SHOW: {
                    Fragment f = op.fragment;
                case OP_SHOW:
                    f.mNextAnim = op.popExitAnim;
                    mManager.hideFragment(f,
                            FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
                }
                    break;
                case OP_DETACH: {
                    Fragment f = op.fragment;
                case OP_DETACH:
                    f.mNextAnim = op.popEnterAnim;
                    mManager.attachFragment(f,
                            FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
                }
                    break;
                case OP_ATTACH: {
                    Fragment f = op.fragment;
                case OP_ATTACH:
                    f.mNextAnim = op.popExitAnim;
                    mManager.detachFragment(f,
                            FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
                }
                    break;
                default: {
                default:
                    throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
            }
        }

            op = op.prev;
        }

        if (doStateMove) {
            mManager.moveToState(mManager.mCurState,
                    FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true);
@@ -1843,7 +1732,7 @@ final class BackStackRecord extends FragmentTransaction implements
    }

    public boolean isEmpty() {
        return mNumOp == 0;
        return mOps.isEmpty();
    }

    public class TransitionState {