diff options
5 files changed, 77 insertions, 5 deletions
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index a528ba4b16bf..7b47efd47008 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -990,6 +990,8 @@ public class InputMethodService extends AbstractInputMethodService { } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (android.view.inputmethod.Flags.refactorInsetsController()) { + // After the IME window was hidden, we can remove its surface + scheduleImeSurfaceRemoval(); // The hide request first finishes the animation and then proceeds to the server // side, finally reaching here, marking this the end state. ImeTracker.forLogging().onHidden(statsToken); diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index c174fbe0bbcd..3659e785f590 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -1299,7 +1299,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation // Handle the pending show request for other insets types since the IME insets // has being requested hidden. handlePendingControlRequest(statsToken); - getImeSourceConsumer().removeSurface(); + if (!Flags.refactorInsetsController()) { + // the surface can't be removed until the end of the animation. This is handled by + // IMMS after the window was requested to be hidden. + getImeSourceConsumer().removeSurface(); + } } applyAnimation(typesReady, false /* show */, fromIme, false /* skipsCallbacks */, statsToken); diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java index e6361e10cfa7..6adceb96d977 100644 --- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java +++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java @@ -230,7 +230,9 @@ public class InsetsSourceConsumerTest { new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash, false /* initialVisible */, new Point(), Insets.NONE), new int[1], hideTypes, new int[1], new int[1]); - assertTrue(mRemoveSurfaceCalled); + if (!android.view.inputmethod.Flags.refactorInsetsController()) { + assertTrue(mRemoveSurfaceCalled); + } assertEquals(0, hideTypes[0]); }); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java index 8377a35a9e7d..87a4115ccd3a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java @@ -324,8 +324,10 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged } applyVisibilityToLeash(imeSourceControl); } - if (!mImeShowing) { - removeImeSurface(mDisplayId); + if (!android.view.inputmethod.Flags.refactorInsetsController()) { + if (!mImeShowing) { + removeImeSurface(mDisplayId); + } } } } else { @@ -663,7 +665,9 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged ImeTracker.forLogging().onProgress(mStatsToken, ImeTracker.PHASE_WM_ANIMATION_RUNNING); t.hide(animatingLeash); - removeImeSurface(mDisplayId); + if (!android.view.inputmethod.Flags.refactorInsetsController()) { + removeImeSurface(mDisplayId); + } if (android.view.inputmethod.Flags.refactorInsetsController()) { setVisibleDirectly(false /* visible */, statsToken); } diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java index 2d3f7231cc5c..b6aee3cfa5c5 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java @@ -40,10 +40,14 @@ import android.content.res.Configuration; import android.graphics.Insets; import android.os.Build; import android.os.RemoteException; +import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; import android.server.wm.WindowManagerStateHelper; import android.util.Log; +import android.view.View; +import android.view.WindowInsets; +import android.view.WindowInsetsAnimation; import android.view.WindowManagerGlobal; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.Flags; @@ -72,6 +76,7 @@ import org.junit.Test; import org.junit.rules.TestName; import org.junit.runner.RunWith; +import java.util.List; import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -245,6 +250,61 @@ public class InputMethodServiceTest { } /** + * This checks that the surface is removed after the window was hidden in + * InputMethodService#hideSoftInput + */ + @Test + @RequiresFlagsEnabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER) + public void testSurfaceRemovedAfterHideSoftInput() { + setShowImeWithHardKeyboard(true /* enabled */); + + // Triggers to show IME via public API. + verifyInputViewStatusOnMainSync(() -> mActivity.showImeWithWindowInsetsController(), + EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); + assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue(); + + final var window = mInputMethodService.getWindow().getWindow(); + assertWithMessage("IME window exists").that(window).isNotNull(); + assertWithMessage("IME window showing").that( + window.getDecorView().getVisibility()).isEqualTo(View.VISIBLE); + + mActivity.getWindow().getDecorView().setWindowInsetsAnimationCallback( + new WindowInsetsAnimation.Callback( + WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE) { + @NonNull + @Override + public WindowInsetsAnimation.Bounds onStart( + @NonNull WindowInsetsAnimation animation, + @NonNull WindowInsetsAnimation.Bounds bounds) { + return super.onStart(animation, bounds); + } + + @NonNull + @Override + public WindowInsets onProgress(@NonNull WindowInsets insets, + @NonNull List<WindowInsetsAnimation> runningAnimations) { + assertWithMessage("IME surface not removed during the animation").that( + window.getDecorView().getVisibility()).isEqualTo(View.VISIBLE); + return insets; + } + + @Override + public void onEnd(@NonNull WindowInsetsAnimation animation) { + assertWithMessage( + "IME surface not removed before the end of the animation").that( + window.getDecorView().getVisibility()).isEqualTo(View.VISIBLE); + super.onEnd(animation); + } + }); + + // Triggers to hide IME via public API. + verifyInputViewStatusOnMainSync(() -> mActivity.hideImeWithWindowInsetsController(), + EVENT_HIDE, true /* eventExpected */, false /* shown */, "IME is not shown"); + eventually(() -> assertWithMessage("IME window not showing").that( + window.getDecorView().getVisibility()).isEqualTo(View.GONE)); + } + + /** * This checks the result of calling IMS#requestShowSelf and IMS#requestHideSelf. */ @Test |