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

Commit 98f9d6bf authored by Tiger's avatar Tiger
Browse files

Enable InsetsState to store sources with discontinuous IDs

This CL uses a SparseArray to store the sources instead of a fixed-
length array. In this way, the amount of the sources in the state won't
be limited by the amount of the pre-defined IDs (InternalInsetsType).
Also, the IDs can be discontinuous integers now.

This is a step to remove InternalInsetsType.

This CL also fixes the misuses of InsetsState#getSource. In most of
cases, they should use peekSource instead. To prevent the caller
from creating the source unexpectedly, this CL renames getSource to
getOrCreateSource.

Bug: 234093736
Test: atest InsetsAnimationControlImplTest InsetsControllerTest
      InsetsStateTest SurfaceControlViewHostInsetsTest
      ActivityRecordTests DisplayContentTests
      DisplayPolicyLayoutTests InsetsPolicyTest
      InsetsStateControllerTest TaskLaunchParamsModifierTests
      WindowLayoutTests WindowStateTests
Change-Id: I41729a973fbf7f2765b51f4d696cb9be9981fbed
parent 04e433ca
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -133,7 +133,8 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
        // If we had a request before to show from IME (tracked with mImeRequestedShow), reaching
        // this code here means that we now got control, so we can start the animation immediately.
        // If client window is trying to control IME and IME is already visible, it is immediate.
        if (fromIme || (mState.getSource(getId()).isVisible() && getControl() != null)) {
        if (fromIme
                || (mState.isSourceOrDefaultVisible(getId(), getType()) && getControl() != null)) {
            return ShowResult.SHOW_IMMEDIATELY;
        }

+11 −7
Original line number Diff line number Diff line
@@ -417,7 +417,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
                // control may be null if it got revoked.
                continue;
            }
            state.getSource(control.getId()).setVisible(shown);
            state.setSourceVisible(control.getId(), shown);
        }
        return getInsetsFromState(state, frame, typeSideMap);
    }
@@ -435,7 +435,8 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
                // control may be null if it got revoked.
                continue;
            }
            if (state == null || state.getSource(control.getId()).isVisible()) {
            if (state == null
                    || state.isSourceOrDefaultVisible(control.getId(), control.getType())) {
                insets = Insets.max(insets, control.getInsetsHint());
            }
        }
@@ -465,20 +466,23 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
        // TODO: Implement behavior when inset spans over multiple types
        for (int i = controls.size() - 1; i >= 0; i--) {
            final InsetsSourceControl control = controls.valueAt(i);
            final InsetsSource source = mInitialInsetsState.getSource(control.getId());
            final InsetsSource source = mInitialInsetsState.peekSource(control.getId());
            final SurfaceControl leash = control.getLeash();

            mTmpMatrix.setTranslate(control.getSurfacePosition().x, control.getSurfacePosition().y);
            if (source != null) {
                mTmpFrame.set(source.getFrame());
            }
            addTranslationToMatrix(side, offset, mTmpMatrix, mTmpFrame);

            final boolean visible = mHasZeroInsetsIme && side == ISIDE_BOTTOM
                    ? (mAnimationType == ANIMATION_TYPE_SHOW || !mFinished)
                    : inset != 0;

            if (outState != null) {
                outState.getSource(source.getId()).setVisible(visible);
                outState.getSource(source.getId()).setFrame(mTmpFrame);
            if (outState != null && source != null) {
                outState.getOrCreateSource(source.getId(), source.getType())
                        .setVisible(visible)
                        .setFrame(mTmpFrame);
            }

            // If the system is controlling the insets source, the leash can be null.
+88 −65
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static android.view.ViewRootImpl.CAPTION_ON_SHELL;
import static android.view.WindowInsets.Type.FIRST;
import static android.view.WindowInsets.Type.LAST;
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.ime;

import android.animation.AnimationHandler;
@@ -44,13 +45,12 @@ import android.os.IBinder;
import android.os.Process;
import android.os.Trace;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsSourceConsumer.ShowResult;
import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
@@ -621,6 +621,79 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    private final Runnable mInvokeControllableInsetsChangedListeners =
            this::invokeControllableInsetsChangedListeners;

    private final InsetsState.OnTraverseCallbacks mRemoveGoneSources =
            new InsetsState.OnTraverseCallbacks() {

                private final IntArray mPendingRemoveIndexes = new IntArray();

                @Override
                public void onIdNotFoundInState2(int index1, InsetsSource source1) {
                    if (!CAPTION_ON_SHELL && source1.getType() == captionBar()) {
                        return;
                    }

                    // Don't change the indexes of the sources while traversing. Remove it later.
                    mPendingRemoveIndexes.add(index1);

                    // Remove the consumer as well except the IME one. IME consumer should always
                    // be there since we need to communicate with InputMethodManager no matter we
                    // have the source or not.
                    if (source1.getType() != ime()) {
                        mSourceConsumers.remove(source1.getId());
                    }
                }

                @Override
                public void onFinish(InsetsState state1, InsetsState state2) {
                    for (int i = mPendingRemoveIndexes.size() - 1; i >= 0; i--) {
                        state1.removeSourceAt(mPendingRemoveIndexes.get(i));
                    }
                    mPendingRemoveIndexes.clear();
                }
            };

    private final InsetsState.OnTraverseCallbacks mStartResizingAnimationIfNeeded =
            new InsetsState.OnTraverseCallbacks() {

                private @InsetsType int mTypes;
                private InsetsState mToState;

                @Override
                public void onStart(InsetsState state1, InsetsState state2) {
                    mTypes = 0;
                    mToState = null;
                }

                @Override
                public void onIdMatch(InsetsSource source1, InsetsSource source2) {
                    final @InsetsType int type = source1.getType();
                    if ((type & Type.systemBars()) == 0
                            || !source1.isVisible() || !source2.isVisible()
                            || source1.getFrame().equals(source2.getFrame())
                            || !(Rect.intersects(mFrame, source1.getFrame())
                                    || Rect.intersects(mFrame, source2.getFrame()))) {
                        return;
                    }
                    mTypes |= type;
                    if (mToState == null) {
                        mToState = new InsetsState();
                    }
                    mToState.addSource(new InsetsSource(source2));
                }

                @Override
                public void onFinish(InsetsState state1, InsetsState state2) {
                    if (mTypes == 0) {
                        return;
                    }
                    cancelExistingControllers(mTypes);
                    final InsetsAnimationControlRunner runner = new InsetsResizeAnimationRunner(
                            mFrame, state1, mToState, RESIZE_INTERPOLATOR,
                            ANIMATION_DURATION_RESIZE, mTypes, InsetsController.this);
                    mRunningAnimations.add(new RunningAnimation(runner, runner.getAnimationType()));
                }
            };

    public InsetsController(Host host) {
        this(host, (controller, source) -> {
            if (source.getType() == ime()) {
@@ -739,29 +812,21 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                true /* excludeInvisibleIme */)) {
            if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged");
            mHost.notifyInsetsChanged();
            startResizingAnimationIfNeeded(lastState);
            if (lastState.getDisplayFrame().equals(mState.getDisplayFrame())) {
                InsetsState.traverse(lastState, mState, mStartResizingAnimationIfNeeded);
            }
        }
        return true;
    }

    private void updateState(InsetsState newState) {
        mState.set(newState, 0 /* types */);
        for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
            final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
            final InsetsSource source = newState.peekSource(consumer.getId());
            if (source == null && consumer != mImeSourceConsumer) {
                // IME source consumer should always be there since we need to communicate with
                // InputMethodManager no matter we have the source or not.
                mSourceConsumers.removeAt(i);
            }
        }
        @InsetsType int existingTypes = 0;
        @InsetsType int visibleTypes = 0;
        @InsetsType int disabledUserAnimationTypes = 0;
        @InsetsType int[] cancelledUserAnimationTypes = {0};
        for (int i = 0; i < InsetsState.SIZE; i++) {
            InsetsSource source = newState.peekSource(i);
            if (source == null) continue;
        for (int i = 0, size = newState.sourceSize(); i < size; i++) {
            final InsetsSource source = newState.sourceAt(i);
            @InsetsType int type = source.getType();
            @AnimationType int animationType = getAnimationType(type);
            if (!source.isUserControllable()) {
@@ -789,15 +854,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            }
            mVisibleTypes = visibleTypes;
        }
        for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
            // Only update the server side insets here.
            if (!CAPTION_ON_SHELL && type == ITYPE_CAPTION_BAR) continue;
            InsetsSource source = mState.peekSource(type);
            if (source == null) continue;
            if (newState.peekSource(type) == null) {
                mState.removeSource(type);
            }
        }
        InsetsState.traverse(mState, newState, mRemoveGoneSources);

        updateDisabledUserAnimationTypes(disabledUserAnimationTypes);

@@ -825,52 +882,17 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        if (CAPTION_ON_SHELL) {
            return false;
        }
        if (mState.peekSource(ITYPE_CAPTION_BAR) == null
                && mCaptionInsetsHeight == 0) {
        final InsetsSource source = mState.peekSource(ITYPE_CAPTION_BAR);
        if (source == null && mCaptionInsetsHeight == 0) {
            return false;
        }
        if (mState.peekSource(ITYPE_CAPTION_BAR) != null
                && mCaptionInsetsHeight
                == mState.peekSource(ITYPE_CAPTION_BAR).getFrame().height()) {
        if (source != null && mCaptionInsetsHeight == source.getFrame().height()) {
            return false;
        }

        return true;
    }

    private void startResizingAnimationIfNeeded(InsetsState fromState) {
        if (!fromState.getDisplayFrame().equals(mState.getDisplayFrame())) {
            return;
        }
        @InsetsType int types = 0;
        InsetsState toState = null;
        final ArraySet<Integer> internalTypes = InsetsState.toInternalType(Type.systemBars());
        for (int i = internalTypes.size() - 1; i >= 0; i--) {
            final @InternalInsetsType int type = internalTypes.valueAt(i);
            final InsetsSource fromSource = fromState.peekSource(type);
            final InsetsSource toSource = mState.peekSource(type);
            if (fromSource != null && toSource != null
                    && fromSource.isVisible() && toSource.isVisible()
                    && !fromSource.getFrame().equals(toSource.getFrame())
                    && (Rect.intersects(mFrame, fromSource.getFrame())
                            || Rect.intersects(mFrame, toSource.getFrame()))) {
                types |= toSource.getType();
                if (toState == null) {
                    toState = new InsetsState();
                }
                toState.addSource(new InsetsSource(toSource));
            }
        }
        if (types == 0) {
            return;
        }
        cancelExistingControllers(types);
        final InsetsAnimationControlRunner runner = new InsetsResizeAnimationRunner(
                mFrame, fromState, toState, RESIZE_INTERPOLATOR, ANIMATION_DURATION_RESIZE, types,
                this);
        mRunningAnimations.add(new RunningAnimation(runner, runner.getAnimationType()));
    }

    /**
     * @see InsetsState#calculateInsets(Rect, InsetsState, boolean, boolean, int, int, int, int,
     *      int, SparseIntArray)
@@ -1217,7 +1239,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                ImeTracker.get().onFailed(statsToken,
                        ImeTracker.PHASE_CLIENT_DISABLED_USER_ANIMATION);

                if (fromIme && !mState.getSource(mImeSourceConsumer.getId()).isVisible()) {
                if (fromIme
                        && !mState.isSourceOrDefaultVisible(mImeSourceConsumer.getId(), ime())) {
                    // We've requested IMM to show IME, but the IME is not controllable. We need to
                    // cancel the request.
                    setRequestedVisibleTypes(0 /* visibleTypes */, ime());
@@ -1757,8 +1780,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        if (mCaptionInsetsHeight != height) {
            mCaptionInsetsHeight = height;
            if (mCaptionInsetsHeight != 0) {
                mState.getSource(ITYPE_CAPTION_BAR).setFrame(mFrame.left, mFrame.top,
                        mFrame.right, mFrame.top + mCaptionInsetsHeight);
                mState.getOrCreateSource(ITYPE_CAPTION_BAR, captionBar()).setFrame(
                        mFrame.left, mFrame.top, mFrame.right, mFrame.top + mCaptionInsetsHeight);
            } else {
                mState.removeSource(ITYPE_CAPTION_BAR);
            }
+16 −18
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@ import android.graphics.Insets;
import android.graphics.Rect;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation.Bounds;
import android.view.animation.Interpolator;
@@ -142,12 +141,9 @@ public class InsetsResizeAnimationRunner implements InsetsAnimationControlRunner
            return false;
        }
        final float fraction = mAnimation.getInterpolatedFraction();
        for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
            final InsetsSource fromSource = mFromState.peekSource(type);
            final InsetsSource toSource = mToState.peekSource(type);
            if (fromSource == null || toSource == null) {
                continue;
            }
        InsetsState.traverse(mFromState, mToState, new InsetsState.OnTraverseCallbacks() {
            @Override
            public void onIdMatch(InsetsSource fromSource, InsetsSource toSource) {
                final Rect fromFrame = fromSource.getFrame();
                final Rect toFrame = toSource.getFrame();
                final Rect frame = new Rect(
@@ -155,11 +151,13 @@ public class InsetsResizeAnimationRunner implements InsetsAnimationControlRunner
                        (int) (fromFrame.top + fraction * (toFrame.top - fromFrame.top)),
                        (int) (fromFrame.right + fraction * (toFrame.right - fromFrame.right)),
                        (int) (fromFrame.bottom + fraction * (toFrame.bottom - fromFrame.bottom)));
            final InsetsSource source = new InsetsSource(type, fromSource.getType());
                final InsetsSource source =
                        new InsetsSource(fromSource.getId(), fromSource.getType());
                source.setFrame(frame);
                source.setVisible(toSource.isVisible());
                outState.addSource(source);
            }
        });
        if (mFinished) {
            mController.notifyFinished(this, true /* shown */);
        }
+10 −5
Original line number Diff line number Diff line
@@ -83,20 +83,24 @@ public class InsetsSource implements Parcelable {
        mInsetsRoundedCornerFrame = other.mInsetsRoundedCornerFrame;
    }

    public void setFrame(int left, int top, int right, int bottom) {
    public InsetsSource setFrame(int left, int top, int right, int bottom) {
        mFrame.set(left, top, right, bottom);
        return this;
    }

    public void setFrame(Rect frame) {
    public InsetsSource setFrame(Rect frame) {
        mFrame.set(frame);
        return this;
    }

    public void setVisibleFrame(@Nullable Rect visibleFrame) {
    public InsetsSource setVisibleFrame(@Nullable Rect visibleFrame) {
        mVisibleFrame = visibleFrame != null ? new Rect(visibleFrame) : null;
        return this;
    }

    public void setVisible(boolean visible) {
    public InsetsSource setVisible(boolean visible) {
        mVisible = visible;
        return this;
    }

    public int getId() {
@@ -128,8 +132,9 @@ public class InsetsSource implements Parcelable {
        return mInsetsRoundedCornerFrame;
    }

    public void setInsetsRoundedCornerFrame(boolean insetsRoundedCornerFrame) {
    public InsetsSource setInsetsRoundedCornerFrame(boolean insetsRoundedCornerFrame) {
        mInsetsRoundedCornerFrame = insetsRoundedCornerFrame;
        return this;
    }

    /**
Loading