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

Commit eafc79d9 authored by Yunfan Chen's avatar Yunfan Chen
Browse files

Implement Relative Insets

This change implements the relative insets.

Relative insets is to describe the insets by the insets size based on
the window the insets attached, instead of any absolute coordinate on
the display. The shell before this change can only provide insets with
arbitrary frame coordinates and to resolve the synchronization issue, a
special policy was introduced to caption bar and caused many layout
issues.

This change allows the shell to provide insets with insets size. As the
caption bar is very likely to have a stable height to the window, even
after the window resizes, this method can avoid repeatedly insets update
from the shell to the WM server. Also, the calculation process is
improved to support this use case. Besides the frame used to calculate
the insets, additional window bounds was introduced. The insets size is
relative to the window bounds (task bounds) and the window bounds will
be used to have the calculation works correctly.

Unnecessary call to the insets change notification was removed when the
relative insets is introduced. No insets re-calculation is needed
anymore. This will also improve the performance during the window
resizing.

Test: InsetsStateTest InsetsPolicyTests
Test: InsetsSourceTest InsetsAnimationControlImplTest
Test: WindowContainerTests WindowDecorationTests
Flag: com.android.window.flags.relative_insets
Bug: 277292497

Change-Id: Id55cffba39c5ca2e1c2fd7c591e1d9e529c5901f
parent ee3ee62c
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -1395,10 +1395,10 @@ public abstract class WallpaperService extends Service {
                    final Rect visibleFrame = new Rect(mWinFrames.frame);
                    visibleFrame.intersect(mInsetsState.getDisplayFrame());
                    WindowInsets windowInsets = mInsetsState.calculateInsets(visibleFrame,
                            null /* ignoringVisibilityState */, config.isScreenRound(),
                            mLayout.softInputMode, mLayout.flags, SYSTEM_UI_FLAG_VISIBLE,
                            mLayout.type, config.windowConfiguration.getActivityType(),
                            null /* idSideMap */);
                            null /* hostBounds */, null /* ignoringVisibilityState */,
                            config.isScreenRound(), mLayout.softInputMode, mLayout.flags,
                            SYSTEM_UI_FLAG_VISIBLE, mLayout.type,
                            config.windowConfiguration.getActivityType(), null /* idSideMap */);

                    if (!fixedSize) {
                        final Rect padding = mIWallpaperEngine.mDisplayPadding;
+14 −12
Original line number Diff line number Diff line
@@ -123,7 +123,8 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro

    @VisibleForTesting(visibility = PACKAGE)
    public InsetsAnimationControlImpl(SparseArray<InsetsSourceControl> controls,
            @Nullable Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener,
            @Nullable Rect frame, @Nullable Rect bounds, InsetsState state,
            WindowInsetsAnimationControlListener listener,
            @InsetsType int types, InsetsAnimationControlCallbacks controller,
            SurfaceParamsApplier surfaceParamsApplier,
            InsetsAnimationSpec insetsAnimationSpec, @AnimationType int animationType,
@@ -136,13 +137,14 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
        mController = controller;
        mSurfaceParamsApplier = surfaceParamsApplier;
        mInitialInsetsState = new InsetsState(state, true /* copySources */);
        if (frame != null) {
        if (frame != null && bounds != null) {
            final SparseIntArray idSideMap = new SparseIntArray();
            mCurrentInsets = getInsetsFromState(mInitialInsetsState, frame, null /* idSideMap */);
            mHiddenInsets = calculateInsets(mInitialInsetsState, frame, controls, false /* shown */,
            mCurrentInsets = getInsetsFromState(mInitialInsetsState, frame, bounds,
                    null /* idSideMap */);
            mShownInsets = calculateInsets(mInitialInsetsState, frame, controls, true /* shown */,
                    idSideMap);
            mHiddenInsets = calculateInsets(mInitialInsetsState, frame, bounds, controls,
                    false /* shown */, null /* idSideMap */);
            mShownInsets = calculateInsets(mInitialInsetsState, frame, bounds, controls,
                    true /* shown */, idSideMap);
            mHasZeroInsetsIme = mShownInsets.bottom == 0 && controlsType(WindowInsets.Type.ime());
            if (mHasZeroInsetsIme) {
                // IME has shownInsets of ZERO, and can't map to a side by default.
@@ -151,8 +153,8 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
            }
            buildSideControlsMap(idSideMap, mSideControlsMap, controls);
        } else {
            // Passing a null frame indicates the caller wants to play the insets animation anyway,
            // no matter the source provides insets to the frame or not.
            // Passing a null frame or bounds indicates the caller wants to play the insets
            // animation anyway, no matter the source provides insets to the frame or not.
            mCurrentInsets = calculateInsets(mInitialInsetsState, controls, true /* shown */);
            mHiddenInsets = calculateInsets(null, controls, false /* shown */);
            mShownInsets = calculateInsets(null, controls, true /* shown */);
@@ -429,16 +431,16 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
        return mControls;
    }

    private Insets getInsetsFromState(InsetsState state, Rect frame,
    private Insets getInsetsFromState(InsetsState state, Rect frame, Rect bounds,
            @Nullable @InternalInsetsSide SparseIntArray idSideMap) {
        return state.calculateInsets(frame, null /* ignoringVisibilityState */,
        return state.calculateInsets(frame, bounds, null /* ignoringVisibilityState */,
                false /* isScreenRound */, SOFT_INPUT_ADJUST_RESIZE /* legacySoftInputMode */,
                0 /* legacyWindowFlags */, 0 /* legacySystemUiFlags */, TYPE_APPLICATION,
                ACTIVITY_TYPE_UNDEFINED, idSideMap).getInsets(mTypes);
    }

    /** Computes the insets relative to the given frame. */
    private Insets calculateInsets(InsetsState state, Rect frame,
    private Insets calculateInsets(InsetsState state, Rect frame, Rect bounds,
            SparseArray<InsetsSourceControl> controls, boolean shown,
            @Nullable @InternalInsetsSide SparseIntArray idSideMap) {
        for (int i = controls.size() - 1; i >= 0; i--) {
@@ -449,7 +451,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
            }
            state.setSourceVisible(control.getId(), shown);
        }
        return getInsetsFromState(state, frame, idSideMap);
        return getInsetsFromState(state, frame, bounds, idSideMap);
    }

    /** Computes the insets from the insets hints of controls. */
+3 −2
Original line number Diff line number Diff line
@@ -107,7 +107,8 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro

    @UiThread
    public InsetsAnimationThreadControlRunner(SparseArray<InsetsSourceControl> controls,
            @Nullable Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener,
            @Nullable Rect frame, @Nullable Rect bounds, InsetsState state,
            WindowInsetsAnimationControlListener listener,
            @InsetsType int types, InsetsAnimationControlCallbacks controller,
            InsetsAnimationSpec insetsAnimationSpec, @AnimationType int animationType,
            @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
@@ -115,7 +116,7 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro
            @Nullable ImeTracker.Token statsToken) {
        mMainThreadHandler = mainThreadHandler;
        mOuterCallbacks = controller;
        mControl = new InsetsAnimationControlImpl(controls, frame, state, listener, types,
        mControl = new InsetsAnimationControlImpl(controls, frame, bounds, state, listener, types,
                mCallbacks, mSurfaceParamsApplier, insetsAnimationSpec, animationType,
                layoutInsetsDuringAnimation, translator, statsToken);
        InsetsAnimationThread.getHandler().post(() -> {
+35 −23
Original line number Diff line number Diff line
@@ -615,6 +615,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    private final InsetsState mLastDispatchedState = new InsetsState();

    private final Rect mFrame = new Rect();
    private final Rect mBounds = new Rect();

    @NonNull
    private final TriFunction<InsetsController, Integer, Integer, InsetsSourceConsumer>
            mConsumerCreator;
@@ -753,7 +755,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                    }
                    cancelExistingControllers(mTypes);
                    final InsetsAnimationControlRunner runner = new InsetsResizeAnimationRunner(
                            mFrame, mFromState, mToState, RESIZE_INTERPOLATOR,
                            mFrame, mBounds, mFromState, mToState, RESIZE_INTERPOLATOR,
                            ANIMATION_DURATION_RESIZE, mTypes, InsetsController.this);
                    if (mRunningAnimations.isEmpty()) {
                        mHost.updateAnimatingTypes(runner.getTypes(),
@@ -812,7 +814,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            }

            WindowInsets insets = state.calculateInsets(mFrame,
                    mState /* ignoringVisibilityState */, mLastInsets.isRound(),
                    mBounds, mState /* ignoringVisibilityState */, mLastInsets.isRound(),
                    mLastLegacySoftInputMode, mLastLegacyWindowFlags, mLastLegacySystemUiFlags,
                    mWindowType, mLastActivityType, null /* idSideMap */);
            mHost.dispatchWindowInsetsAnimationProgress(insets,
@@ -845,6 +847,14 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        mFrame.set(frame);
    }

    public void onBoundsChanged(Rect bounds) {
        if (mBounds.equals(bounds)) {
            return;
        }
        mBounds.set(bounds);
        mHost.notifyInsetsChanged();
    }

    @Override
    @NonNull
    public InsetsState getState() {
@@ -925,7 +935,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    }

    /**
     * @see InsetsState#calculateInsets(Rect, InsetsState, boolean, int, int, int, int, int,
     * @see InsetsState#calculateInsets(Rect, Rect, InsetsState, boolean, int, int, int, int, int,
     *      android.util.SparseIntArray)
     */
    @VisibleForTesting
@@ -936,19 +946,19 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        mLastLegacySoftInputMode = legacySoftInputMode;
        mLastLegacyWindowFlags = legacyWindowFlags;
        mLastLegacySystemUiFlags = legacySystemUiFlags;
        mLastInsets = mState.calculateInsets(mFrame, null /* ignoringVisibilityState */,
        mLastInsets = mState.calculateInsets(mFrame, mBounds, null /* ignoringVisibilityState */,
                isScreenRound, legacySoftInputMode, legacyWindowFlags,
                legacySystemUiFlags, windowType, activityType, null /* idSideMap */);
        return mLastInsets;
    }

    /**
     * @see InsetsState#calculateVisibleInsets(Rect, int, int, int, int)
     * @see InsetsState#calculateVisibleInsets(Rect, Rect, int, int, int, int)
     */
    public Insets calculateVisibleInsets(int windowType, int activityType,
            @SoftInputModeFlags int softInputMode, int windowFlags) {
        return mState.calculateVisibleInsets(mFrame, windowType, activityType, softInputMode,
                windowFlags);
        return mState.calculateVisibleInsets(mFrame, mBounds, windowType, activityType,
                softInputMode, windowFlags);
    }

    /**
@@ -1228,7 +1238,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        // We are about to playing the default animation. Passing a null frame indicates the
        // controlled types should be animated regardless of the frame.
        controlAnimationUnchecked(pendingRequest.types, pendingRequest.cancellationSignal,
                pendingRequest.listener, null /* frame */, true /* fromIme */,
                pendingRequest.listener, null /* frame */, null /* bounds */, true /* fromIme */,
                pendingRequest.mInsetsAnimationSpec,
                pendingRequest.animationType, pendingRequest.layoutInsetsDuringAnimation,
                pendingRequest.useInsetsAnimationThread, statsToken,
@@ -1347,7 +1357,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            WindowInsetsAnimationControlListener listener,
            boolean fromIme, long durationMs, @Nullable Interpolator interpolator,
            @AnimationType int animationType, boolean fromPredictiveBack) {
        if ((mState.calculateUncontrollableInsetsFromFrame(mFrame) & types) != 0
        if ((mState.calculateUncontrollableInsetsFromFrame(mFrame, mBounds) & types) != 0
                || (fromPredictiveBack && ((mRequestedVisibleTypes & ime()) == 0))) {
            // abort if insets are uncontrollable or if control request is from predictive back but
            // there is already a hide anim in progress
@@ -1371,15 +1381,16 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            }
        };
        // TODO(b/342111149): Create statsToken here once ImeTracker#onStart becomes async.
        controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, spec,
                animationType, getLayoutInsetsDuringAnimationMode(types, fromPredictiveBack),
        controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, mBounds, fromIme,
                spec, animationType, getLayoutInsetsDuringAnimationMode(types, fromPredictiveBack),
                false /* useInsetsAnimationThread */, null, fromPredictiveBack);
    }

    private void controlAnimationUnchecked(@InsetsType int types,
            @Nullable CancellationSignal cancellationSignal,
            WindowInsetsAnimationControlListener listener, @Nullable Rect frame, boolean fromIme,
            InsetsAnimationSpec insetsAnimationSpec, @AnimationType int animationType,
            WindowInsetsAnimationControlListener listener, @Nullable Rect frame,
            @Nullable Rect bounds, boolean fromIme, InsetsAnimationSpec insetsAnimationSpec,
            @AnimationType int animationType,
            @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
            boolean useInsetsAnimationThread, @Nullable ImeTracker.Token statsToken,
            boolean fromPredictiveBack) {
@@ -1395,7 +1406,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

        // However, we might reject the request in some cases, such as delaying showing IME or
        // rejecting showing IME.
        controlAnimationUncheckedInner(types, cancellationSignal, listener, frame, fromIme,
        controlAnimationUncheckedInner(types, cancellationSignal, listener, frame, bounds, fromIme,
                insetsAnimationSpec, animationType, layoutInsetsDuringAnimation,
                useInsetsAnimationThread, statsToken, fromPredictiveBack);

@@ -1406,8 +1417,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

    private void controlAnimationUncheckedInner(@InsetsType int types,
            @Nullable CancellationSignal cancellationSignal,
            WindowInsetsAnimationControlListener listener, @Nullable Rect frame, boolean fromIme,
            InsetsAnimationSpec insetsAnimationSpec, @AnimationType int animationType,
            WindowInsetsAnimationControlListener listener, @Nullable Rect frame,
            @Nullable Rect bounds, boolean fromIme, InsetsAnimationSpec insetsAnimationSpec,
            @AnimationType int animationType,
            @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
            boolean useInsetsAnimationThread, @Nullable ImeTracker.Token statsToken,
            boolean fromPredictiveBack) {
@@ -1566,13 +1578,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

        final InsetsAnimationControlRunner runner = useInsetsAnimationThread
                ? new InsetsAnimationThreadControlRunner(controls,
                        frame, mState, listener, typesReady, this,
                        frame, bounds, mState, listener, typesReady, this,
                        insetsAnimationSpec, animationType, layoutInsetsDuringAnimation,
                        mHost.getTranslator(), mHost.getHandler(), statsToken)
                : new InsetsAnimationControlImpl(controls,
                        frame, mState, listener, typesReady, this, this, insetsAnimationSpec,
                        animationType, layoutInsetsDuringAnimation, mHost.getTranslator(),
                        statsToken);
                        frame, bounds, mState, listener, typesReady, this, this,
                        insetsAnimationSpec, animationType, layoutInsetsDuringAnimation,
                        mHost.getTranslator(), statsToken);
        for (int i = controls.size() - 1; i >= 0; i--) {
            final InsetsSourceConsumer consumer = mSourceConsumers.get(controls.keyAt(i));
            if (consumer != null) {
@@ -2098,8 +2110,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        // We are about to playing the default animation (show/hide). Passing a null frame indicates
        // the controlled types should be animated regardless of the frame.
        controlAnimationUnchecked(
                types, null /* cancellationSignal */, listener, null /* frame */, fromIme,
                listener /* insetsAnimationSpec */,
                types, null /* cancellationSignal */, listener, null /* frame */, null /* bounds */,
                fromIme, listener /* insetsAnimationSpec */,
                show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
                show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
                !hasAnimationCallbacks || skipsCallbacks /* useInsetsAnimationThread */, statsToken,
@@ -2270,7 +2282,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                result |= consumer.getType();
            }
        }
        return result & ~mState.calculateUncontrollableInsetsFromFrame(mFrame);
        return result & ~mState.calculateUncontrollableInsetsFromFrame(mFrame, mBounds);
    }

    /**
+8 −0
Original line number Diff line number Diff line
@@ -63,6 +63,12 @@ public class InsetsFrameProvider implements Parcelable {
     */
    public static final int SOURCE_ARBITRARY_RECTANGLE = 3;

    /**
     * Uses the container bounds to which the insets attached as the source.
     * Only use this if the insets is a local insets only applied to the children of the container.
     */
    public static final int SOURCE_ATTACHED_CONTAINER_BOUNDS = 4;

    private final int mId;

    /**
@@ -277,6 +283,8 @@ public class InsetsFrameProvider implements Parcelable {
                return "FRAME";
            case SOURCE_ARBITRARY_RECTANGLE:
                return "ARBITRARY_RECTANGLE";
            case SOURCE_ATTACHED_CONTAINER_BOUNDS:
                return "ATTACHED_CONTAINER_BOUNDS";
        }
        return "UNDEFINED";
    }
Loading