From 737c79151cb6fc005bbce145f91606af69065539 Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Thu, 29 Dec 2022 06:00:20 +0000 Subject: [PATCH] Fix WIC#hide(ime()) no-op after WIC#show(ime()) in Activity#onCreate In InsetsController#hide, ensure to request hide IME with calling ImeInsetsSurceConsumer#requestHide, in case the pending visible request will triggger show after setControl. Also, we modified PendingControlRequest to be able to remove from the show insets type when it has being requested invisible by InsetsController#hide(type), if the removed type contains the IME then we handle the pending show control request for other types since it is no longer needed to wait the IME ready to show. Also, make sure set mIsRequestedVisibleAwaitingControl as false when ImeInsetsSourceConsumer#notifyHidden to avoid the above pending visible request happens. Bug: 248456059 Test: atest CtsInputMethodTestCases Test: atest InputMethodStressTest:ImeOpenCloseStressTest Change-Id: Id3aebca3348888826bc5d3c6694e94cddb80b4d4 --- .../android/view/ImeInsetsSourceConsumer.java | 1 + core/java/android/view/InsetsController.java | 61 ++++++++++++++----- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java index f06ba3b422df9..e89be476a9f0c 100644 --- a/core/java/android/view/ImeInsetsSourceConsumer.java +++ b/core/java/android/view/ImeInsetsSourceConsumer.java @@ -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); } diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 829321e3652bc..8e8e28a65eb4d 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -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; @@ -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; } @@ -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; @@ -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; @@ -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 @@ -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); }