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

Commit e729560d authored by Felix Stern's avatar Felix Stern
Browse files

Update the server visibility before layout

The changes in [1] were making sure that another layout traversal takes
place, if the IME was not drawn before, but is now drawn. To address the
redundant window layout, this CL introduces `onPreLayout`, which sets
the serverVisibility. As we need the previous visibility state in the
ImeInsetsSourceProvider to reset the statsToken if needed, we store it
as well.

[1]: Ibbc76dc7f3963e6c2fa1b7f15208fc69b2c8e1b5

Bug: 427863960
Bug: 427117834
Test: atest ImeInsetsSourceProviderTest#testOnPreLayout_resetServerVisibilityWhenImeIsNotDrawn
Test: atest com.android.server.wm.DisplayPolicyLayoutTests
Test: atest KeyboardVisibilityControlTest#testDialogPositionChangedAfterImeIsShown
Flag: android.view.inputmethod.set_server_visibility_onprelayout
Change-Id: I314d6d445a5aa1c8fab73689b259239dccc6f629
parent e8ef6fa0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ public class ImePerfTest extends ImePerfTestBase
            "IMMS.applyImeVisibility",
            "applyPostLayoutPolicy",
            "applyWindowSurfaceChanges",
            "ISC.onPreLayout",
            "ISC.onPostLayout"
    };

+6 −0
Original line number Diff line number Diff line
@@ -219,3 +219,9 @@ flag {
  bug: "139872425"
}

flag {
  name: "set_server_visibility_onprelayout"
  namespace: "input_method"
  description: "Set server visibility before performLayout to avoid additional window layout traversal."
  bug: "427863960"
}
+4 −0
Original line number Diff line number Diff line
@@ -5081,6 +5081,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
            setLayoutNeeded();
        }

        if (android.view.inputmethod.Flags.setServerVisibilityOnprelayout()) {
            mInsetsStateController.onPreLayout();
        }

        // Perform a layout, if needed.
        performLayout(true /* initial */, false /* updateInputWindows */);
        pendingLayoutChanges = 0;
+46 −13
Original line number Diff line number Diff line
@@ -70,6 +70,12 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider {
     */
    private boolean mServerVisible;

    /**
     * The server visibility of the source provider's window before the latest
     * {@link #onPreLayout} call.
     */
    private boolean mServerVisiblePreLayout;

    /**
     * When the IME is not ready, it has givenInsetsPending. However, this could happen again,
     * after it became serverVisible. This flag indicates is used to determine if it is
@@ -91,18 +97,31 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider {
    }

    @Override
    void onPostLayout() {
    void onPreLayout() {
        if (!android.view.inputmethod.Flags.setServerVisibilityOnprelayout()) {
            return;
        }
        mServerVisiblePreLayout = mServerVisible;
        super.onPreLayout();

        mLastDrawn = mWin != null && mWin.isDrawn();
    }

    @Override
    boolean onPostLayout() {
        final boolean wasSourceVisible = mSource.isVisible();
        super.onPostLayout();
        if (wasSourceVisible != mSource.isVisible()) {
        final boolean controlDispatched = super.onPostLayout();
        if (!android.view.inputmethod.Flags.setServerVisibilityOnprelayout()
                && wasSourceVisible != mSource.isVisible()) {
            // TODO(b/427863960): Remove this and set the server visibility in onPreLayout
            // If the IME visibility has changed, a traversal needs to apply.
            mDisplayContent.setLayoutNeeded();
        }

        final boolean givenInsetsPending = mWin != null && mWin.mGivenInsetsPending;
        if (!android.view.inputmethod.Flags.setServerVisibilityOnprelayout()) {
            mLastDrawn = mWin != null && mWin.isDrawn();

        }
        // isLeashReadyForDispatching (used to dispatch the leash of the control) is
        // depending on mGivenInsetsReady. Therefore, triggering notifyControlChanged here
        // again, so that the control with leash can be eventually dispatched
@@ -114,10 +133,14 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider {
            mGivenInsetsReady = true;
            ImeTracker.forLogging().onProgress(mStatsToken,
                    ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED);
            if (!controlDispatched) {
                mStateController.notifyControlChanged(mControlTarget, this);
            }
            setImeShowing(true);
        } else if (wasSourceVisible && isServerVisible() && mGivenInsetsReady
                && givenInsetsPending) {
            return true;
        } else if (((!android.view.inputmethod.Flags.setServerVisibilityOnprelayout()
                && wasSourceVisible) || mServerVisiblePreLayout) && isServerVisible()
                && mGivenInsetsReady && givenInsetsPending) {
            // If the server visibility didn't change (still visible), and mGivenInsetsReady
            // is set, we won't call into notifyControlChanged. Therefore, we can reset the
            // statsToken, if available.
@@ -126,12 +149,22 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider {
            ImeTracker.forLogging().onCancelled(mStatsToken,
                    ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED);
            mStatsToken = null;
        } else if (isImeShowing() && !isServerVisible()) {
        } else if (!isServerVisible()) {
            if (isImeShowing()) {
                ProtoLog.d(WM_DEBUG_IME,
                        "onPostLayout: setImeShowing(false) was: true, controlTarget=%s",
                        mControlTarget);
                setImeShowing(false);
            }
            if (android.view.inputmethod.Flags.setServerVisibilityOnprelayout()
                    && mControlTarget != null && mServerVisiblePreLayout && !controlDispatched) {
                // If the server visibility changed (not visible anymore), we need to dispatch
                // the control.
                mStateController.notifyControlChanged(mControlTarget, this);
                return true;
            }
        }
        return controlDispatched;
    }

    @Nullable
+34 −9
Original line number Diff line number Diff line
@@ -362,28 +362,53 @@ class InsetsSourceProvider {
    }

    /**
     * Called when a layout pass has occurred.
     * Called before a layout pass will occur.
     */
    void onPostLayout() {
    void onPreLayout() {
        if (!android.view.inputmethod.Flags.setServerVisibilityOnprelayout()) {
            return;
        }
        if (mWin == null) {
            return;
        }
        setServerVisible(isSurfaceVisible());
    }

    /**
     * Called after a layout pass has occurred.
     *
     * @return {@code true} if {@link InsetsStateController#notifyControlChanged} was called or
     * was scheduled to be called within this method, else {@code false}.
     */
    boolean onPostLayout() {
        if (mWin == null) {
            return false;
        }
        final boolean serverVisibleChanged;
        if (!android.view.inputmethod.Flags.setServerVisibilityOnprelayout()) {
            final boolean isServerVisible = isSurfaceVisible();

        final boolean serverVisibleChanged = mServerVisible != isServerVisible;
            serverVisibleChanged = mServerVisible != isServerVisible;
            setServerVisible(isServerVisible);
        } else {
            serverVisibleChanged = false;
        }
        if (mControl != null && mControlTarget != null) {
            final boolean positionChanged = updateInsetsControlPosition(mWin);
            if (!(positionChanged || mHasPendingPosition)
            if (positionChanged || mHasPendingPosition) {
                return true;
            }
            // The insets hint would be updated while changing the position. Here updates it
                    // for the possible change of the bounds or the server visibility.
                    && (updateInsetsHint(mControl) || serverVisibleChanged)) {
            // for the possible change of the bounds.
            if (updateInsetsHint(mControl) || serverVisibleChanged) {
                // Only call notifyControlChanged here when the position hasn't been or won't be
                // changed. Otherwise, it has been called or scheduled to be called during
                // updateInsetsControlPosition.
                mStateController.notifyControlChanged(mControlTarget, this);
                return true;
            }
        }
        return false;
    }

    /**
Loading