Loading services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +39 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,13 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { */ private boolean mGivenInsetsReady = false; /** * The last state of the windowContainer. This is used to reset server visibility, in case of * the IME (temporarily) redrawing (e.g. during a rotation), to dispatch the control with * leash again after it has finished drawing. */ private boolean mLastDrawn = false; ImeInsetsSourceProvider(@NonNull InsetsSource source, @NonNull InsetsStateController stateController, @NonNull DisplayContent displayContent) { Loading @@ -97,6 +104,7 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { final WindowState ws = mWindowContainer != null ? mWindowContainer.asWindowState() : null; final boolean givenInsetsPending = ws != null && ws.mGivenInsetsPending; mLastDrawn = ws != null && ws.isDrawn(); // isLeashReadyForDispatching (used to dispatch the leash of the control) is // depending on mGivenInsetsReady. Therefore, triggering notifyControlChanged here Loading Loading @@ -158,6 +166,35 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { } } /** * This is used to determine the desired serverVisibility state. For the IME, just having a * window state that would be visible by policy is not enough. */ @Override protected boolean isSurfaceVisible() { final boolean isSurfaceVisible = super.isSurfaceVisible(); if (android.view.inputmethod.Flags.refactorInsetsController()) { final WindowState windowState = mWindowContainer.asWindowState(); if (mControl != null && windowState != null) { final boolean isDrawn = windowState.isDrawn(); if (!isServerVisible() && isSurfaceVisible) { // In case the IME becomes visible, we need to check if it is already drawn and // does not have given insets pending. If it's not yet drawn, we do not set // server visibility return isDrawn && !windowState.mGivenInsetsPending; } else if (mLastDrawn && !isDrawn) { // If the IME was drawn before, but is not drawn anymore, we need to reset // server visibility, which will also reset {@link // ImeInsetsSourceProvider#mGivenInsetsReady}. Otherwise, the new control // with leash won't be dispatched after the surface has redrawn. return false; } } } return isSurfaceVisible; } @Nullable @Override InsetsSourceControl getControl(InsetsControlTarget target) { Loading Loading @@ -779,6 +816,8 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { pw.print(prefix); pw.print("mImeShowing="); pw.print(mImeShowing); pw.print(" mLastDrawn="); pw.print(mLastDrawn); if (mImeRequester != null) { pw.print(prefix); pw.print("showImePostLayout pending for mImeRequester="); Loading services/core/java/com/android/server/wm/InsetsSourceProvider.java +12 −13 Original line number Diff line number Diff line Loading @@ -175,6 +175,16 @@ class InsetsSourceProvider { return mControllable; } /** * @return Whether the current window container has a visible surface. */ protected boolean isSurfaceVisible() { final WindowState windowState = mWindowContainer.asWindowState(); return windowState != null ? windowState.wouldBeVisibleIfPolicyIgnored() && windowState.isVisibleByPolicy() : mWindowContainer.isVisibleRequested(); } /** * Updates the window container that currently backs this source. * Loading Loading @@ -368,20 +378,9 @@ class InsetsSourceProvider { if (mWindowContainer == null) { return; } WindowState windowState = mWindowContainer.asWindowState(); boolean isServerVisible = windowState != null ? windowState.wouldBeVisibleIfPolicyIgnored() && windowState.isVisibleByPolicy() : mWindowContainer.isVisibleRequested(); final WindowState windowState = mWindowContainer.asWindowState(); final boolean isServerVisible = isSurfaceVisible(); if (android.view.inputmethod.Flags.refactorInsetsController()) { if (mControl != null && mControl.getType() == WindowInsets.Type.ime() && !mServerVisible && isServerVisible && windowState != null) { // in case the IME becomes visible, we need to check if it is already drawn and // does not have given insets pending. If it's not yet drawn, we do not set // server visibility isServerVisible = windowState.isDrawn() && !windowState.mGivenInsetsPending; } } final boolean serverVisibleChanged = mServerVisible != isServerVisible; setServerVisible(isServerVisible); if (mControl != null && mControlTarget != null) { Loading services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java +32 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,9 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN; import static com.android.server.wm.WindowStateAnimator.NO_SURFACE; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; Loading Loading @@ -244,4 +247,33 @@ public class ImeInsetsSourceProviderTest extends WindowTestsBase { verify(displayWindowInsetsController, times(1)).setImeInputTargetRequestedVisibility( eq(true), any()); } @Test @RequiresFlagsEnabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER) public void testOnPostLayout_resetServerVisibilityWhenImeIsNotDrawn() { final WindowState ime = newWindowBuilder("ime", TYPE_INPUT_METHOD).build(); final WindowState inputTarget = newWindowBuilder("app", TYPE_APPLICATION).build(); makeWindowVisibleAndDrawn(ime); mImeProvider.setWindowContainer(ime, null, null); mImeProvider.setServerVisible(true); mImeProvider.setClientVisible(true); mImeProvider.updateVisibility(); mImeProvider.updateControlForTarget(inputTarget, true /* force */, null /* statsToken */); // Calling onPostLayout, as the drawn state is initially false. mImeProvider.onPostLayout(); assertTrue(mImeProvider.isSurfaceVisible()); // Reset window's drawn state ime.mWinAnimator.mDrawState = NO_SURFACE; mImeProvider.onPostLayout(); assertFalse(mImeProvider.isServerVisible()); assertFalse(mImeProvider.isSurfaceVisible()); // Set it back to drawn ime.mWinAnimator.mDrawState = HAS_DRAWN; mImeProvider.onPostLayout(); assertTrue(mImeProvider.isServerVisible()); assertTrue(mImeProvider.isSurfaceVisible()); } } Loading
services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +39 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,13 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { */ private boolean mGivenInsetsReady = false; /** * The last state of the windowContainer. This is used to reset server visibility, in case of * the IME (temporarily) redrawing (e.g. during a rotation), to dispatch the control with * leash again after it has finished drawing. */ private boolean mLastDrawn = false; ImeInsetsSourceProvider(@NonNull InsetsSource source, @NonNull InsetsStateController stateController, @NonNull DisplayContent displayContent) { Loading @@ -97,6 +104,7 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { final WindowState ws = mWindowContainer != null ? mWindowContainer.asWindowState() : null; final boolean givenInsetsPending = ws != null && ws.mGivenInsetsPending; mLastDrawn = ws != null && ws.isDrawn(); // isLeashReadyForDispatching (used to dispatch the leash of the control) is // depending on mGivenInsetsReady. Therefore, triggering notifyControlChanged here Loading Loading @@ -158,6 +166,35 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { } } /** * This is used to determine the desired serverVisibility state. For the IME, just having a * window state that would be visible by policy is not enough. */ @Override protected boolean isSurfaceVisible() { final boolean isSurfaceVisible = super.isSurfaceVisible(); if (android.view.inputmethod.Flags.refactorInsetsController()) { final WindowState windowState = mWindowContainer.asWindowState(); if (mControl != null && windowState != null) { final boolean isDrawn = windowState.isDrawn(); if (!isServerVisible() && isSurfaceVisible) { // In case the IME becomes visible, we need to check if it is already drawn and // does not have given insets pending. If it's not yet drawn, we do not set // server visibility return isDrawn && !windowState.mGivenInsetsPending; } else if (mLastDrawn && !isDrawn) { // If the IME was drawn before, but is not drawn anymore, we need to reset // server visibility, which will also reset {@link // ImeInsetsSourceProvider#mGivenInsetsReady}. Otherwise, the new control // with leash won't be dispatched after the surface has redrawn. return false; } } } return isSurfaceVisible; } @Nullable @Override InsetsSourceControl getControl(InsetsControlTarget target) { Loading Loading @@ -779,6 +816,8 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { pw.print(prefix); pw.print("mImeShowing="); pw.print(mImeShowing); pw.print(" mLastDrawn="); pw.print(mLastDrawn); if (mImeRequester != null) { pw.print(prefix); pw.print("showImePostLayout pending for mImeRequester="); Loading
services/core/java/com/android/server/wm/InsetsSourceProvider.java +12 −13 Original line number Diff line number Diff line Loading @@ -175,6 +175,16 @@ class InsetsSourceProvider { return mControllable; } /** * @return Whether the current window container has a visible surface. */ protected boolean isSurfaceVisible() { final WindowState windowState = mWindowContainer.asWindowState(); return windowState != null ? windowState.wouldBeVisibleIfPolicyIgnored() && windowState.isVisibleByPolicy() : mWindowContainer.isVisibleRequested(); } /** * Updates the window container that currently backs this source. * Loading Loading @@ -368,20 +378,9 @@ class InsetsSourceProvider { if (mWindowContainer == null) { return; } WindowState windowState = mWindowContainer.asWindowState(); boolean isServerVisible = windowState != null ? windowState.wouldBeVisibleIfPolicyIgnored() && windowState.isVisibleByPolicy() : mWindowContainer.isVisibleRequested(); final WindowState windowState = mWindowContainer.asWindowState(); final boolean isServerVisible = isSurfaceVisible(); if (android.view.inputmethod.Flags.refactorInsetsController()) { if (mControl != null && mControl.getType() == WindowInsets.Type.ime() && !mServerVisible && isServerVisible && windowState != null) { // in case the IME becomes visible, we need to check if it is already drawn and // does not have given insets pending. If it's not yet drawn, we do not set // server visibility isServerVisible = windowState.isDrawn() && !windowState.mGivenInsetsPending; } } final boolean serverVisibleChanged = mServerVisible != isServerVisible; setServerVisible(isServerVisible); if (mControl != null && mControlTarget != null) { Loading
services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java +32 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,9 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN; import static com.android.server.wm.WindowStateAnimator.NO_SURFACE; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; Loading Loading @@ -244,4 +247,33 @@ public class ImeInsetsSourceProviderTest extends WindowTestsBase { verify(displayWindowInsetsController, times(1)).setImeInputTargetRequestedVisibility( eq(true), any()); } @Test @RequiresFlagsEnabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER) public void testOnPostLayout_resetServerVisibilityWhenImeIsNotDrawn() { final WindowState ime = newWindowBuilder("ime", TYPE_INPUT_METHOD).build(); final WindowState inputTarget = newWindowBuilder("app", TYPE_APPLICATION).build(); makeWindowVisibleAndDrawn(ime); mImeProvider.setWindowContainer(ime, null, null); mImeProvider.setServerVisible(true); mImeProvider.setClientVisible(true); mImeProvider.updateVisibility(); mImeProvider.updateControlForTarget(inputTarget, true /* force */, null /* statsToken */); // Calling onPostLayout, as the drawn state is initially false. mImeProvider.onPostLayout(); assertTrue(mImeProvider.isSurfaceVisible()); // Reset window's drawn state ime.mWinAnimator.mDrawState = NO_SURFACE; mImeProvider.onPostLayout(); assertFalse(mImeProvider.isServerVisible()); assertFalse(mImeProvider.isSurfaceVisible()); // Set it back to drawn ime.mWinAnimator.mDrawState = HAS_DRAWN; mImeProvider.onPostLayout(); assertTrue(mImeProvider.isServerVisible()); assertTrue(mImeProvider.isSurfaceVisible()); } }