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

Commit 781f435c authored by Gaurav Bhola's avatar Gaurav Bhola
Browse files

Relocate the getInsetsForWindow logic inside WindowState.

- This is done so that the WindowState owns the high level insets logic.
- Will help to implement getInsetsState() in other containers once the
  insets are moved to WindowContainer as part of the hierarchical insets
  effort.

Fix: 207693667
Bug: 199449177
Test: atest WindowStateTests
Test: atest InsetsStateControllerTest
Test: atest DisplayPolicyLayouttyTests
Change-Id: Idb646f6f3730d6d88091ea82b3e80c4701bb477d
parent 60cc9881
Loading
Loading
Loading
Loading
+136 −9
Original line number Diff line number Diff line
@@ -19,24 +19,36 @@ package com.android.server.wm;
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_INVALID;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityTaskManager;
import android.app.StatusBarManager;
import android.app.WindowConfiguration;
import android.graphics.Insets;
import android.graphics.Rect;
import android.util.ArrayMap;
import android.util.IntArray;
import android.util.SparseArray;
import android.view.InsetsAnimationControlCallbacks;
@@ -235,10 +247,11 @@ class InsetsPolicy {
    }

    /**
     * @see InsetsStateController#getInsetsForWindow
     * Adjusts the sources in {@code originalState} to account for things like transient bars, IME
     * & rounded corners.
     */
    InsetsState getInsetsForWindow(WindowState target, boolean includesTransient) {
        final InsetsState originalState = mStateController.getInsetsForWindow(target);
    InsetsState adjustInsetsForWindow(WindowState target, InsetsState originalState,
            boolean includesTransient) {
        InsetsState state;
        if (!includesTransient) {
            state = adjustVisibilityForTransientTypes(originalState);
@@ -249,19 +262,133 @@ class InsetsPolicy {
        return adjustInsetsForRoundedCorners(target, state, state == originalState);
    }

    InsetsState getInsetsForWindow(WindowState target) {
        return getInsetsForWindow(target, false);
    InsetsState adjustInsetsForWindow(WindowState target, InsetsState originalState) {
        return adjustInsetsForWindow(target, originalState, false);
    }


    /**
     * @see InsetsStateController#getInsetsForWindowMetrics
     * @see WindowState#getInsetsState()
     */
    InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
        final InsetsState originalState = mStateController.getInsetsForWindowMetrics(attrs);
        final @InternalInsetsType int type = getInsetsTypeForLayoutParams(attrs);
        final WindowToken token = mDisplayContent.getWindowToken(attrs.token);
        if (token != null) {
            final InsetsState rotatedState = token.getFixedRotationTransformInsetsState();
            if (rotatedState != null) {
                return rotatedState;
            }
        }
        final boolean alwaysOnTop = token != null && token.isAlwaysOnTop();
        // Always use windowing mode fullscreen when get insets for window metrics to make sure it
        // contains all insets types.
        final InsetsState originalState = mDisplayContent.getInsetsPolicy()
                .enforceInsetsPolicyForTarget(type, WINDOWING_MODE_FULLSCREEN, alwaysOnTop,
                        mStateController.getRawInsetsState());
        return adjustVisibilityForTransientTypes(originalState);
    }

    private static @InternalInsetsType int getInsetsTypeForLayoutParams(
            WindowManager.LayoutParams attrs) {
        @WindowManager.LayoutParams.WindowType int type = attrs.type;
        switch (type) {
            case TYPE_STATUS_BAR:
                return ITYPE_STATUS_BAR;
            case TYPE_NAVIGATION_BAR:
                return ITYPE_NAVIGATION_BAR;
            case TYPE_INPUT_METHOD:
                return ITYPE_IME;
        }

        // If not one of the types above, check whether an internal inset mapping is specified.
        if (attrs.providesInsetsTypes != null) {
            for (@InternalInsetsType int insetsType : attrs.providesInsetsTypes) {
                switch (insetsType) {
                    case ITYPE_STATUS_BAR:
                    case ITYPE_NAVIGATION_BAR:
                    case ITYPE_CLIMATE_BAR:
                    case ITYPE_EXTRA_NAVIGATION_BAR:
                        return insetsType;
                }
            }
        }

        return ITYPE_INVALID;
    }


    /**
     * Modifies the given {@code state} according to the {@code type} (Inset type) provided by
     * the target.
     * When performing layout of the target or dispatching insets to the target, we need to exclude
     * sources which should not be visible to the target. e.g., the source which represents the
     * target window itself, and the IME source when the target is above IME. We also need to
     * exclude certain types of insets source for client within specific windowing modes.
     *
     * @param type the inset type provided by the target
     * @param windowingMode the windowing mode of the target
     * @param isAlwaysOnTop is the target always on top
     * @param state the input inset state containing all the sources
     * @return The state stripped of the necessary information.
     */
    InsetsState enforceInsetsPolicyForTarget(@InternalInsetsType int type,
            @WindowConfiguration.WindowingMode int windowingMode, boolean isAlwaysOnTop,
            InsetsState state) {
        boolean stateCopied = false;

        if (type != ITYPE_INVALID) {
            state = new InsetsState(state);
            stateCopied = true;
            state.removeSource(type);

            // Navigation bar doesn't get influenced by anything else
            if (type == ITYPE_NAVIGATION_BAR || type == ITYPE_EXTRA_NAVIGATION_BAR) {
                state.removeSource(ITYPE_IME);
                state.removeSource(ITYPE_STATUS_BAR);
                state.removeSource(ITYPE_CLIMATE_BAR);
                state.removeSource(ITYPE_CAPTION_BAR);
                state.removeSource(ITYPE_NAVIGATION_BAR);
                state.removeSource(ITYPE_EXTRA_NAVIGATION_BAR);
            }

            // Status bar doesn't get influenced by caption bar
            if (type == ITYPE_STATUS_BAR || type == ITYPE_CLIMATE_BAR) {
                state.removeSource(ITYPE_CAPTION_BAR);
            }

            // IME needs different frames for certain cases (e.g. navigation bar in gesture nav).
            if (type == ITYPE_IME) {
                ArrayMap<Integer, InsetsSourceProvider> providers = mStateController
                        .getSourceProviders();
                for (int i = providers.size() - 1; i >= 0; i--) {
                    InsetsSourceProvider otherProvider = providers.valueAt(i);
                    if (otherProvider.overridesImeFrame()) {
                        InsetsSource override =
                                new InsetsSource(
                                        state.getSource(otherProvider.getSource().getType()));
                        override.setFrame(otherProvider.getImeOverrideFrame());
                        state.addSource(override);
                    }
                }
            }
        }

        if (WindowConfiguration.isFloating(windowingMode)
                || (windowingMode == WINDOWING_MODE_MULTI_WINDOW && isAlwaysOnTop)) {
            if (!stateCopied) {
                state = new InsetsState(state);
                stateCopied = true;
            }
            state.removeSource(ITYPE_STATUS_BAR);
            state.removeSource(ITYPE_NAVIGATION_BAR);
            state.removeSource(ITYPE_EXTRA_NAVIGATION_BAR);
            if (windowingMode == WINDOWING_MODE_PINNED) {
                state.removeSource(ITYPE_IME);
            }
        }

        return state;
    }

    private InsetsState adjustVisibilityForTransientTypes(InsetsState originalState) {
        InsetsState state = originalState;
        for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
@@ -644,7 +771,7 @@ class InsetsPolicy {
                }
                mAnimatingShown = show;

                final InsetsState state = getInsetsForWindow(mFocusedWin);
                final InsetsState state = mFocusedWin.getInsetsState();

                // We are about to playing the default animation. Passing a null frame indicates
                // the controlled types should be animated regardless of the frame.
+4 −140
Original line number Diff line number Diff line
@@ -16,30 +16,20 @@

package com.android.server.wm;

import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_INVALID;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.mandatorySystemGestures;
import static android.view.WindowInsets.Type.systemGestures;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;

import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
import android.graphics.Rect;
import android.os.Trace;
import android.util.ArrayMap;
@@ -49,8 +39,6 @@ import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams.WindowType;

import com.android.internal.protolog.common.ProtoLog;
import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -103,134 +91,6 @@ class InsetsStateController {
        mDisplayContent = displayContent;
    }

    /**
     * Gets the insets state from the perspective of the target. When performing layout of the
     * target or dispatching insets to the target, we need to exclude sources which should not be
     * visible to the target. e.g., the source which represents the target window itself, and the
     * IME source when the target is above IME. We also need to exclude certain types of insets
     * source for client within specific windowing modes.
     * This is to get the insets for a window layout on the screen. If the window is not there, use
     * the {@link #getInsetsForWindowMetrics} to get insets instead.
     *
     * @param target The window associate with the perspective.
     * @return The state stripped of the necessary information.
     */
    InsetsState getInsetsForWindow(@NonNull WindowState target) {
        final InsetsState rotatedState = target.mToken.getFixedRotationTransformInsetsState();
        if (rotatedState != null) {
            return rotatedState;
        }
        final InsetsSourceProvider provider = target.getControllableInsetProvider();
        final @InternalInsetsType int type = provider != null
                ? provider.getSource().getType() : ITYPE_INVALID;
        return getInsetsForTarget(type, target.getWindowingMode(), target.isAlwaysOnTop(),
                target.getFrozenInsetsState() != null ? target.getFrozenInsetsState() :
                        (target.mAttrs.receiveInsetsIgnoringZOrder ? mState :
                         target.mAboveInsetsState));
    }

    InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
        final @InternalInsetsType int type = getInsetsTypeForLayoutParams(attrs);
        final WindowToken token = mDisplayContent.getWindowToken(attrs.token);
        if (token != null) {
            final InsetsState rotatedState = token.getFixedRotationTransformInsetsState();
            if (rotatedState != null) {
                return rotatedState;
            }
        }
        final boolean alwaysOnTop = token != null && token.isAlwaysOnTop();
        // Always use windowing mode fullscreen when get insets for window metrics to make sure it
        // contains all insets types.
        return getInsetsForTarget(type, WINDOWING_MODE_FULLSCREEN, alwaysOnTop, mState);
    }

    private static @InternalInsetsType
            int getInsetsTypeForLayoutParams(WindowManager.LayoutParams attrs) {
        @WindowType int type = attrs.type;
        switch (type) {
            case TYPE_STATUS_BAR:
                return ITYPE_STATUS_BAR;
            case TYPE_NAVIGATION_BAR:
                return ITYPE_NAVIGATION_BAR;
            case TYPE_INPUT_METHOD:
                return ITYPE_IME;
        }

        // If not one of the types above, check whether an internal inset mapping is specified.
        if (attrs.providesInsetsTypes != null) {
            for (@InternalInsetsType int insetsType : attrs.providesInsetsTypes) {
                switch (insetsType) {
                    case ITYPE_STATUS_BAR:
                    case ITYPE_NAVIGATION_BAR:
                    case ITYPE_CLIMATE_BAR:
                    case ITYPE_EXTRA_NAVIGATION_BAR:
                        return insetsType;
                }
            }
        }

        return ITYPE_INVALID;
    }

    /**
     * @see #getInsetsForWindow
     * @see #getInsetsForWindowMetrics
     */
    private InsetsState getInsetsForTarget(@InternalInsetsType int type,
            @WindowingMode int windowingMode, boolean isAlwaysOnTop, InsetsState state) {
        boolean stateCopied = false;

        if (type != ITYPE_INVALID) {
            state = new InsetsState(state);
            stateCopied = true;
            state.removeSource(type);

            // Navigation bar doesn't get influenced by anything else
            if (type == ITYPE_NAVIGATION_BAR || type == ITYPE_EXTRA_NAVIGATION_BAR) {
                state.removeSource(ITYPE_STATUS_BAR);
                state.removeSource(ITYPE_CLIMATE_BAR);
                state.removeSource(ITYPE_CAPTION_BAR);
                state.removeSource(ITYPE_NAVIGATION_BAR);
                state.removeSource(ITYPE_EXTRA_NAVIGATION_BAR);
            }

            // Status bar doesn't get influenced by caption bar
            if (type == ITYPE_STATUS_BAR || type == ITYPE_CLIMATE_BAR) {
                state.removeSource(ITYPE_CAPTION_BAR);
            }

            // IME needs different frames for certain cases (e.g. navigation bar in gesture nav).
            if (type == ITYPE_IME) {
                for (int i = mProviders.size() - 1; i >= 0; i--) {
                    InsetsSourceProvider otherProvider = mProviders.valueAt(i);
                    if (otherProvider.overridesImeFrame()) {
                        InsetsSource override =
                                new InsetsSource(
                                        state.getSource(otherProvider.getSource().getType()));
                        override.setFrame(otherProvider.getImeOverrideFrame());
                        state.addSource(override);
                    }
                }
            }
        }

        if (WindowConfiguration.isFloating(windowingMode)
                || (windowingMode == WINDOWING_MODE_MULTI_WINDOW && isAlwaysOnTop)) {
            if (!stateCopied) {
                state = new InsetsState(state);
                stateCopied = true;
            }
            state.removeSource(ITYPE_STATUS_BAR);
            state.removeSource(ITYPE_NAVIGATION_BAR);
            state.removeSource(ITYPE_EXTRA_NAVIGATION_BAR);
            if (windowingMode == WINDOWING_MODE_PINNED) {
                state.removeSource(ITYPE_IME);
            }
        }

        return state;
    }

    InsetsState getRawInsetsState() {
        return mState;
    }
@@ -248,6 +108,10 @@ class InsetsStateController {
        return result;
    }

    ArrayMap<Integer, InsetsSourceProvider> getSourceProviders() {
        return mProviders;
    }

    /**
     * @return The provider of a specific type.
     */
+1 −2
Original line number Diff line number Diff line
@@ -6582,8 +6582,7 @@ class Task extends TaskFragment {
            return;
        }
        if (mOverlayHost != null) {
            final InsetsState s = getDisplayContent().getInsetsPolicy()
                .getInsetsForWindow(originalChange, true);
            final InsetsState s = originalChange.getInsetsState(true);
            getBounds(mTmpRect);
            mOverlayHost.dispatchInsetsChanged(s, mTmpRect);
        }
+32 −3
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.PowerManager.DRAW_WAKE_LOCK;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_INVALID;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.SurfaceControl.Transaction;
import static android.view.SurfaceControl.getGlobalTransaction;
@@ -1646,12 +1647,40 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        return super.getMaxBounds();
    }

    /**
     * See {@link WindowState#getInsetsState(boolean)}
     */
    InsetsState getInsetsState() {
        return getInsetsState(false);
    }

    /**
     * Returns the insets state for the window. Its sources may be the copies with visibility
     * modification according to the state of transient bars.
     * This is to get the insets for a window layout on the screen. If the window is not there, use
     * the {@link InsetsPolicy#getInsetsForWindowMetrics} to get insets instead.
     * @param includeTransient whether or not the transient types should be included in the
     *                         insets state.
     */
    InsetsState getInsetsState() {
        return getDisplayContent().getInsetsPolicy().getInsetsForWindow(this);
    InsetsState getInsetsState(boolean includeTransient) {
        final InsetsState rotatedState = mToken.getFixedRotationTransformInsetsState();
        final InsetsPolicy insetsPolicy = getDisplayContent().getInsetsPolicy();
        if (rotatedState != null) {
            return insetsPolicy.adjustInsetsForWindow(this, rotatedState);
        }
        final InsetsSourceProvider provider = getControllableInsetProvider();
        final InsetsStateController insetsStateController = getDisplayContent()
                .getInsetsStateController();
        final @InternalInsetsType int insetTypeProvidedByWindow = provider != null
                ? provider.getSource().getType() : ITYPE_INVALID;
        final InsetsState rawInsetsState = getFrozenInsetsState() != null
                ? getFrozenInsetsState() : (mAttrs.receiveInsetsIgnoringZOrder
                ? insetsStateController.getRawInsetsState() : mAboveInsetsState);
        final InsetsState insetsStateForWindow = insetsPolicy
                .enforceInsetsPolicyForTarget(insetTypeProvidedByWindow,
                        getWindowingMode(), isAlwaysOnTop(), rawInsetsState);
        return insetsPolicy.adjustInsetsForWindow(this, insetsStateForWindow,
                includeTransient);
    }

    /**
@@ -5666,7 +5695,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
     * into the state of the control target.
     *
     * @param insetProvider the provider which should not be visible to the client.
     * @see InsetsStateController#getInsetsForWindow(WindowState)
     * @see #getInsetsState()
     */
    void setControllableInsetProvider(InsetsSourceProvider insetProvider) {
        mControllableInsetProvider = insetProvider;
+2 −2
Original line number Diff line number Diff line
@@ -3059,7 +3059,7 @@ public class ActivityRecordTests extends WindowTestsBase {
        mDisplayContent.setImeLayeringTarget(app);
        mDisplayContent.updateImeInputAndControlTarget(app);

        InsetsState state = mDisplayContent.getInsetsPolicy().getInsetsForWindow(app);
        InsetsState state = app.getInsetsState();
        assertFalse(state.getSource(ITYPE_IME).isVisible());
        assertTrue(state.getSource(ITYPE_IME).getFrame().isEmpty());

@@ -3079,7 +3079,7 @@ public class ActivityRecordTests extends WindowTestsBase {

        // Verify when IME is visible and the app can receive the right IME insets from policy.
        makeWindowVisibleAndDrawn(app, mImeWindow);
        state = mDisplayContent.getInsetsPolicy().getInsetsForWindow(app);
        state = app.getInsetsState();
        assertTrue(state.getSource(ITYPE_IME).isVisible());
        assertEquals(state.getSource(ITYPE_IME).getFrame(), imeSource.getFrame());
    }
Loading