Loading core/java/android/view/ImeInsetsSourceConsumer.java +1 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_NOTIFY_HIDDEN); getImm().notifyImeHidden(mController.getHost().getWindowToken(), statsToken); mIsRequestedVisibleAwaitingControl = false; Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0); } Loading core/java/android/view/InsetsController.java +47 −14 Original line number Diff line number Diff line Loading @@ -552,7 +552,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation this.useInsetsAnimationThread = useInsetsAnimationThread; } final @InsetsType int types; @InsetsType int types; final WindowInsetsAnimationControlListener listener; final long durationMs; final Interpolator interpolator; Loading Loading @@ -1006,19 +1006,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } // Handle pending request ready in case there was one set. if (fromIme && mPendingImeControlRequest != null) { PendingControlRequest pendingRequest = mPendingImeControlRequest; mPendingImeControlRequest = null; mHandler.removeCallbacks(mPendingControlTimeout); // 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.durationMs, pendingRequest.interpolator, pendingRequest.animationType, pendingRequest.layoutInsetsDuringAnimation, pendingRequest.useInsetsAnimationThread, statsToken); handlePendingControlRequest(statsToken); return; } Loading Loading @@ -1061,6 +1049,27 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation applyAnimation(typesReady, true /* show */, fromIme, statsToken); } /** * Handle the {@link #mPendingImeControlRequest} when * - The IME insets is ready to show. * - The IME insets has being requested invisible. */ private void handlePendingControlRequest(@Nullable ImeTracker.Token statsToken) { PendingControlRequest pendingRequest = mPendingImeControlRequest; mPendingImeControlRequest = null; mHandler.removeCallbacks(mPendingControlTimeout); // 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.durationMs, pendingRequest.interpolator, pendingRequest.animationType, pendingRequest.layoutInsetsDuringAnimation, pendingRequest.useInsetsAnimationThread, statsToken); } @Override public void hide(@InsetsType int types) { ImeTracker.Token statsToken = null; Loading @@ -1084,6 +1093,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0); } int typesReady = 0; boolean hasImeRequestedHidden = false; final boolean hadPendingImeControlRequest = mPendingImeControlRequest != null; for (int type = FIRST; type <= LAST; type = type << 1) { if ((types & type) == 0) { continue; Loading @@ -1091,6 +1102,22 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @AnimationType final int animationType = getAnimationType(type); final boolean requestedVisible = (type & mRequestedVisibleTypes) != 0; final boolean isImeAnimation = type == ime(); if (mPendingImeControlRequest != null && !requestedVisible) { // Remove the hide insets type from the pending show request. mPendingImeControlRequest.types &= ~type; if (mPendingImeControlRequest.types == 0) { abortPendingImeControlRequest(); } } if (isImeAnimation && !requestedVisible && animationType == ANIMATION_TYPE_NONE) { hasImeRequestedHidden = true; // Ensure to request hide IME in case there is any pending requested visible // being applied from setControl when receiving the insets control. if (hadPendingImeControlRequest || getImeSourceConsumer().isRequestedVisibleAwaitingControl()) { getImeSourceConsumer().requestHide(fromIme, statsToken); } } if (!requestedVisible && animationType == ANIMATION_TYPE_NONE || animationType == ANIMATION_TYPE_HIDE) { // no-op: already hidden or animating out (because window visibility is Loading @@ -1106,6 +1133,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } typesReady |= type; } if (hasImeRequestedHidden && mPendingImeControlRequest != null) { // Handle the pending show request for other insets types since the IME insets has being // requested hidden. handlePendingControlRequest(statsToken); getImeSourceConsumer().removeSurface(); } applyAnimation(typesReady, false /* show */, fromIme, statsToken); } Loading tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeOpenCloseStressTest.java +34 −8 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.inputmethod.stresstest; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED; import static com.android.inputmethod.stresstest.ImeStressTestUtil.INPUT_METHOD_MANAGER_HIDE_ON_CREATE; import static com.android.inputmethod.stresstest.ImeStressTestUtil.INPUT_METHOD_MANAGER_SHOW_ON_CREATE; import static com.android.inputmethod.stresstest.ImeStressTestUtil.REQUEST_FOCUS_ON_CREATE; Loading Loading @@ -209,8 +211,23 @@ public final class ImeOpenCloseStressTest { verifyShowBehavior(activity); } /** * Test IME hidden by calling show and hide IME consecutively with * {@link android.view.inputmethod.InputMethodManager} APIs in * {@link android.app.Activity#onCreate}. * * <p> Note for developers: Use {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_UNCHANGED} * window flag to avoid some softInputMode visibility flags may take presence over * {@link android.view.inputmethod.InputMethodManager} APIs (e.g. use showSoftInput to show * IME in {@link android.app.Activity#onCreate} but being hidden by * {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_ALWAYS_HIDDEN} window flag after the * activity window focused).</p> */ @Test public void testShowHideWithInputMethodManager_onCreate() { if (mSoftInputFlags != SOFT_INPUT_STATE_UNCHANGED) { return; } // Show and hide with InputMethodManager at onCreate() Intent intent = createIntent( Loading @@ -222,10 +239,7 @@ public final class ImeOpenCloseStressTest { INPUT_METHOD_MANAGER_HIDE_ON_CREATE)); TestActivity activity = TestActivity.start(intent); // TODO: The Ime is expected to show first and then hide. But show or hide // with InputMethodManager at onCreate() would always fail because the window // has not gained focus, so the actual behavior will be the same as auto-show. // verifyHideBehavior(activity); verifyHideBehavior(activity); } @Test Loading Loading @@ -352,8 +366,7 @@ public final class ImeOpenCloseStressTest { // Wait until IMMS / IMS handles messages. SystemClock.sleep(1000); mInstrumentation.waitForIdleSync(); // TODO(b/248456059): Ime should be hidden but is shown. // verifyHideBehavior(activity); verifyHideBehavior(activity); mInstrumentation.runOnMainSync(activity::showImeWithWindowInsetsController); verifyShowBehavior(activity); Loading Loading @@ -420,11 +433,25 @@ public final class ImeOpenCloseStressTest { verifyShowBehaviorNotRequestFocus(activity); } /** * Test IME hidden by calling show and hide IME consecutively with * {@link android.view.WindowInsetsController} APIs in {@link android.app.Activity#onCreate}. * * <p> Note for developers: Use {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_UNCHANGED} * window flag to avoid some softInputMode visibility flags may take presence over * {@link android.view.WindowInsetsController} APIs (e.g. use showSoftInput to show * IME in {@link android.app.Activity#onCreate} but being hidden by * {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_ALWAYS_HIDDEN} window flag after the * activity window focused).</p> */ @Test public void testHideWithWindowInsetsController_onCreate_requestFocus() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } if (mSoftInputFlags != SOFT_INPUT_STATE_UNCHANGED) { return; } // Show and hide with InputMethodManager at onCreate() Intent intent = createIntent( Loading @@ -436,8 +463,7 @@ public final class ImeOpenCloseStressTest { WINDOW_INSETS_CONTROLLER_HIDE_ON_CREATE)); TestActivity activity = TestActivity.start(intent); // TODO(b/248456059): Ime should be hidden but is shown. //verifyHideBehavior(activity); verifyHideBehavior(activity); } @Test Loading Loading
core/java/android/view/ImeInsetsSourceConsumer.java +1 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_NOTIFY_HIDDEN); getImm().notifyImeHidden(mController.getHost().getWindowToken(), statsToken); mIsRequestedVisibleAwaitingControl = false; Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0); } Loading
core/java/android/view/InsetsController.java +47 −14 Original line number Diff line number Diff line Loading @@ -552,7 +552,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation this.useInsetsAnimationThread = useInsetsAnimationThread; } final @InsetsType int types; @InsetsType int types; final WindowInsetsAnimationControlListener listener; final long durationMs; final Interpolator interpolator; Loading Loading @@ -1006,19 +1006,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } // Handle pending request ready in case there was one set. if (fromIme && mPendingImeControlRequest != null) { PendingControlRequest pendingRequest = mPendingImeControlRequest; mPendingImeControlRequest = null; mHandler.removeCallbacks(mPendingControlTimeout); // 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.durationMs, pendingRequest.interpolator, pendingRequest.animationType, pendingRequest.layoutInsetsDuringAnimation, pendingRequest.useInsetsAnimationThread, statsToken); handlePendingControlRequest(statsToken); return; } Loading Loading @@ -1061,6 +1049,27 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation applyAnimation(typesReady, true /* show */, fromIme, statsToken); } /** * Handle the {@link #mPendingImeControlRequest} when * - The IME insets is ready to show. * - The IME insets has being requested invisible. */ private void handlePendingControlRequest(@Nullable ImeTracker.Token statsToken) { PendingControlRequest pendingRequest = mPendingImeControlRequest; mPendingImeControlRequest = null; mHandler.removeCallbacks(mPendingControlTimeout); // 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.durationMs, pendingRequest.interpolator, pendingRequest.animationType, pendingRequest.layoutInsetsDuringAnimation, pendingRequest.useInsetsAnimationThread, statsToken); } @Override public void hide(@InsetsType int types) { ImeTracker.Token statsToken = null; Loading @@ -1084,6 +1093,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0); } int typesReady = 0; boolean hasImeRequestedHidden = false; final boolean hadPendingImeControlRequest = mPendingImeControlRequest != null; for (int type = FIRST; type <= LAST; type = type << 1) { if ((types & type) == 0) { continue; Loading @@ -1091,6 +1102,22 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @AnimationType final int animationType = getAnimationType(type); final boolean requestedVisible = (type & mRequestedVisibleTypes) != 0; final boolean isImeAnimation = type == ime(); if (mPendingImeControlRequest != null && !requestedVisible) { // Remove the hide insets type from the pending show request. mPendingImeControlRequest.types &= ~type; if (mPendingImeControlRequest.types == 0) { abortPendingImeControlRequest(); } } if (isImeAnimation && !requestedVisible && animationType == ANIMATION_TYPE_NONE) { hasImeRequestedHidden = true; // Ensure to request hide IME in case there is any pending requested visible // being applied from setControl when receiving the insets control. if (hadPendingImeControlRequest || getImeSourceConsumer().isRequestedVisibleAwaitingControl()) { getImeSourceConsumer().requestHide(fromIme, statsToken); } } if (!requestedVisible && animationType == ANIMATION_TYPE_NONE || animationType == ANIMATION_TYPE_HIDE) { // no-op: already hidden or animating out (because window visibility is Loading @@ -1106,6 +1133,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } typesReady |= type; } if (hasImeRequestedHidden && mPendingImeControlRequest != null) { // Handle the pending show request for other insets types since the IME insets has being // requested hidden. handlePendingControlRequest(statsToken); getImeSourceConsumer().removeSurface(); } applyAnimation(typesReady, false /* show */, fromIme, statsToken); } Loading
tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeOpenCloseStressTest.java +34 −8 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.inputmethod.stresstest; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED; import static com.android.inputmethod.stresstest.ImeStressTestUtil.INPUT_METHOD_MANAGER_HIDE_ON_CREATE; import static com.android.inputmethod.stresstest.ImeStressTestUtil.INPUT_METHOD_MANAGER_SHOW_ON_CREATE; import static com.android.inputmethod.stresstest.ImeStressTestUtil.REQUEST_FOCUS_ON_CREATE; Loading Loading @@ -209,8 +211,23 @@ public final class ImeOpenCloseStressTest { verifyShowBehavior(activity); } /** * Test IME hidden by calling show and hide IME consecutively with * {@link android.view.inputmethod.InputMethodManager} APIs in * {@link android.app.Activity#onCreate}. * * <p> Note for developers: Use {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_UNCHANGED} * window flag to avoid some softInputMode visibility flags may take presence over * {@link android.view.inputmethod.InputMethodManager} APIs (e.g. use showSoftInput to show * IME in {@link android.app.Activity#onCreate} but being hidden by * {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_ALWAYS_HIDDEN} window flag after the * activity window focused).</p> */ @Test public void testShowHideWithInputMethodManager_onCreate() { if (mSoftInputFlags != SOFT_INPUT_STATE_UNCHANGED) { return; } // Show and hide with InputMethodManager at onCreate() Intent intent = createIntent( Loading @@ -222,10 +239,7 @@ public final class ImeOpenCloseStressTest { INPUT_METHOD_MANAGER_HIDE_ON_CREATE)); TestActivity activity = TestActivity.start(intent); // TODO: The Ime is expected to show first and then hide. But show or hide // with InputMethodManager at onCreate() would always fail because the window // has not gained focus, so the actual behavior will be the same as auto-show. // verifyHideBehavior(activity); verifyHideBehavior(activity); } @Test Loading Loading @@ -352,8 +366,7 @@ public final class ImeOpenCloseStressTest { // Wait until IMMS / IMS handles messages. SystemClock.sleep(1000); mInstrumentation.waitForIdleSync(); // TODO(b/248456059): Ime should be hidden but is shown. // verifyHideBehavior(activity); verifyHideBehavior(activity); mInstrumentation.runOnMainSync(activity::showImeWithWindowInsetsController); verifyShowBehavior(activity); Loading Loading @@ -420,11 +433,25 @@ public final class ImeOpenCloseStressTest { verifyShowBehaviorNotRequestFocus(activity); } /** * Test IME hidden by calling show and hide IME consecutively with * {@link android.view.WindowInsetsController} APIs in {@link android.app.Activity#onCreate}. * * <p> Note for developers: Use {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_UNCHANGED} * window flag to avoid some softInputMode visibility flags may take presence over * {@link android.view.WindowInsetsController} APIs (e.g. use showSoftInput to show * IME in {@link android.app.Activity#onCreate} but being hidden by * {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_ALWAYS_HIDDEN} window flag after the * activity window focused).</p> */ @Test public void testHideWithWindowInsetsController_onCreate_requestFocus() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } if (mSoftInputFlags != SOFT_INPUT_STATE_UNCHANGED) { return; } // Show and hide with InputMethodManager at onCreate() Intent intent = createIntent( Loading @@ -436,8 +463,7 @@ public final class ImeOpenCloseStressTest { WINDOW_INSETS_CONTROLLER_HIDE_ON_CREATE)); TestActivity activity = TestActivity.start(intent); // TODO(b/248456059): Ime should be hidden but is shown. //verifyHideBehavior(activity); verifyHideBehavior(activity); } @Test Loading