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

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

Fix focus problems when using optimized fragment transactions.

Bug 33754255

Instead of making Views INVISIBLE immediately after adding them,
Views are set to transitionAlpha = 0.

Test: I966da3051912fff0f7ac42dec31626fd8248f7c2

Change-Id: Id032d363379ad07376e5ad8def6131820493e4a9
parent 5df7f1ab
Loading
Loading
Loading
Loading
+41 −14
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.os.Debug;
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.DebugUtils;
import android.util.Log;
@@ -1245,11 +1246,13 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
                        dispatchOnFragmentViewDestroyed(f, false);
                        if (f.mView != null && f.mContainer != null) {
                            Animator anim = null;
                            if (mCurState > Fragment.INITIALIZING && !mDestroyed &&
                                    f.mView.getVisibility() == View.VISIBLE) {
                            if (mCurState > Fragment.INITIALIZING && !mDestroyed
                                    && f.mView.getVisibility() == View.VISIBLE
                                    && f.mView.getTransitionAlpha() > 0) {
                                anim = loadAnimator(f, transit, false,
                                        transitionStyle);
                            }
                            f.mView.setTransitionAlpha(1f);
                            if (anim != null) {
                                final ViewGroup container = f.mContainer;
                                final View view = f.mView;
@@ -1439,7 +1442,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
            }
            if (f.mIsNewlyAdded && f.mContainer != null) {
                // Make it visible and run the animations
                f.mView.setVisibility(View.VISIBLE);
                f.mView.setTransitionAlpha(1f);
                f.mIsNewlyAdded = false;
                // run animations:
                Animator anim = loadAnimator(f, f.getNextTransition(), true, f.getNextTransitionStyle());
@@ -2038,9 +2041,11 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate

        int postponeIndex = endIndex;
        if (allowOptimization) {
            moveFragmentsToInvisible();
            ArraySet<Fragment> addedFragments = new ArraySet<>();
            addAddedFragments(addedFragments);
            postponeIndex = postponePostponableTransactions(records, isRecordPop,
                    startIndex, endIndex);
                    startIndex, endIndex, addedFragments);
            makeRemovedFragmentsInvisible(addedFragments);
        }

        if (postponeIndex != startIndex && allowOptimization) {
@@ -2064,6 +2069,24 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
        }
    }

    /**
     * Any fragments that were removed because they have been postponed should have their views
     * made invisible by setting their transition alpha to 0.
     *
     * @param fragments The fragments that were added during operation execution. Only the ones
     *                  that are no longer added will have their transition alpha changed.
     */
    private void makeRemovedFragmentsInvisible(ArraySet<Fragment> fragments) {
        final int numAdded = fragments.size();
        for (int i = 0; i < numAdded; i++) {
            final Fragment fragment = fragments.valueAt(i);
            if (!fragment.mAdded) {
                final View view = fragment.getView();
                view.setTransitionAlpha(0f);
            }
        }
    }

    /**
     * Examine all transactions and determine which ones are marked as postponed. Those will
     * have their operations rolled back and moved to the end of the record list (up to endIndex).
@@ -2077,7 +2100,8 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
     * postponed.
     */
    private int postponePostponableTransactions(ArrayList<BackStackRecord> records,
            ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
            ArrayList<Boolean> isRecordPop, int startIndex, int endIndex,
            ArraySet<Fragment> added) {
        int postponeIndex = endIndex;
        for (int i = endIndex - 1; i >= startIndex; i--) {
            final BackStackRecord record = records.get(i);
@@ -2108,7 +2132,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
                }

                // different views may be visible now
                moveFragmentsToInvisible();
                addAddedFragments(added);
            }
        }
        return postponeIndex;
@@ -2141,14 +2165,16 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
        }
        if (moveToState) {
            moveToState(mCurState, true);
        } else if (mActive != null) {
        }

        if (mActive != null) {
            final int numActive = mActive.size();
            for (int i = 0; i < numActive; i++) {
                // Allow added fragments to be removed during the pop since we aren't going
                // to move them to the final state with moveToState(mCurState).
                Fragment fragment = mActive.get(i);
                if (fragment.mView != null && fragment.mIsNewlyAdded &&
                        record.interactsWith(fragment.mContainerId)) {
                if (fragment != null && fragment.mView != null && fragment.mIsNewlyAdded
                        && record.interactsWith(fragment.mContainerId)) {
                    fragment.mIsNewlyAdded = false;
                }
            }
@@ -2213,10 +2239,11 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate

    /**
     * Ensure that fragments that are added are moved to at least the CREATED state.
     * Any newly-added Views are made INVISIBLE so that the Transaction can be postponed
     * with {@link Fragment#postponeEnterTransition()}.
     * Any newly-added Views are inserted into {@code added} so that the Transaction can be
     * postponed with {@link Fragment#postponeEnterTransition()}. They will later be made
     * invisible by changing their transitionAlpha to 0 if they have been removed when postponed.
     */
    private void moveFragmentsToInvisible() {
    private void addAddedFragments(ArraySet<Fragment> added) {
        if (mCurState < Fragment.CREATED) {
            return;
        }
@@ -2228,7 +2255,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
            if (fragment.mState < state) {
                moveToState(fragment, state, fragment.getNextAnim(), fragment.getNextTransition(), false);
                if (fragment.mView != null && !fragment.mHidden && fragment.mIsNewlyAdded) {
                    fragment.mView.setVisibility(View.INVISIBLE);
                    added.add(fragment);
                }
            }
        }
+3 −2
Original line number Diff line number Diff line
@@ -1266,8 +1266,9 @@ class FragmentTransition {
            case BackStackRecord.OP_REMOVE:
            case BackStackRecord.OP_DETACH:
                if (isOptimizedTransaction) {
                    setFirstOut = !fragment.mAdded && fragment.mView != null &&
                            fragment.mView.getVisibility() == View.VISIBLE;
                    setFirstOut = !fragment.mAdded && fragment.mView != null
                            && fragment.mView.getVisibility() == View.VISIBLE
                            && fragment.mView.getTransitionAlpha() > 0;
                } else {
                    setFirstOut = fragment.mAdded && !fragment.mHidden;
                }