Unregister IME callback in onBackInvoked immediately
By removing the IME callback in onBackInvoked immediately, a new back gesture that starts during the IME hide animation can already dispatch to a new back callback. Currently, back gestures that start during the (predictive back) IME hide animation are simply ignored. This CL fixes that.
Bug: 322836622
Flag: ACONFIG android.view.inputmethod.predictive_back_ime DISABLED
Test: separate CL
Change-Id: Iab628e23982915b5c5f17896436157794e90b649
diff --git a/core/java/android/view/ImeBackAnimationController.java b/core/java/android/view/ImeBackAnimationController.java
index 665fac1..911f7b2 100644
--- a/core/java/android/view/ImeBackAnimationController.java
+++ b/core/java/android/view/ImeBackAnimationController.java
@@ -31,9 +31,12 @@
import android.view.animation.BackGestureInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import android.view.inputmethod.ImeTracker;
import android.window.BackEvent;
import android.window.OnBackAnimationCallback;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
+
/**
* Controller for IME predictive back animation
*
@@ -192,6 +195,24 @@
mPostCommitAnimator.setDuration(
triggerBack ? POST_COMMIT_DURATION_MS : POST_COMMIT_CANCEL_DURATION_MS);
mPostCommitAnimator.start();
+ if (triggerBack) {
+ mInsetsController.setPredictiveBackImeHideAnimInProgress(true);
+ notifyHideIme();
+ }
+ }
+
+ private void notifyHideIme() {
+ ImeTracker.Token statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+ ImeTracker.ORIGIN_CLIENT,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL, true);
+ // This notifies the IME that it is being hidden. In response, the IME will unregister the
+ // animation callback, such that new back gestures happening during the post-commit phase of
+ // the hide animation can already dispatch to a new callback.
+ // Note that the IME will call hide() in InsetsController. InsetsController will not animate
+ // that hide request if it sees that ImeBackAnimationController is already animating
+ // the IME away
+ mInsetsController.getHost().getInputMethodManager()
+ .notifyImeHidden(mInsetsController.getHost().getWindowToken(), statsToken);
}
private void reset() {
@@ -200,6 +221,7 @@
mLastProgress = 0f;
mTriggerBack = false;
mIsPreCommitAnimationInProgress = false;
+ mInsetsController.setPredictiveBackImeHideAnimInProgress(false);
}
private void resetPostCommitAnimator() {
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 6caf4d6..3def604 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -243,7 +243,8 @@
* {@link InputMethodManager#showSoftInput(View, int)} is called.
*/
public void onShowRequested() {
- if (mAnimationState == ANIMATION_STATE_HIDE) {
+ if (mAnimationState == ANIMATION_STATE_HIDE
+ || mController.isPredictiveBackImeHideAnimInProgress()) {
mHasPendingRequest = true;
}
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 1f6ceca..8c00fbb 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -651,6 +651,7 @@
private @Appearance int mAppearanceControlled;
private @Appearance int mAppearanceFromResource;
private boolean mBehaviorControlled;
+ private boolean mIsPredictiveBackImeHideAnimInProgress;
private final Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;
private final ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
@@ -1027,6 +1028,14 @@
reportRequestedVisibleTypes();
}
+ void setPredictiveBackImeHideAnimInProgress(boolean isInProgress) {
+ mIsPredictiveBackImeHideAnimInProgress = isInProgress;
+ }
+
+ boolean isPredictiveBackImeHideAnimInProgress() {
+ return mIsPredictiveBackImeHideAnimInProgress;
+ }
+
@Override
public void show(@InsetsType int types) {
show(types, false /* fromIme */, null /* statsToken */);
@@ -1090,7 +1099,8 @@
}
continue;
}
- if (fromIme && animationType == ANIMATION_TYPE_USER) {
+ if (fromIme && animationType == ANIMATION_TYPE_USER
+ && !mIsPredictiveBackImeHideAnimInProgress) {
// App is already controlling the IME, don't cancel it.
if (isIme) {
ImeTracker.forLogging().onFailed(
@@ -1186,7 +1196,8 @@
}
}
if (!requestedVisible && animationType == ANIMATION_TYPE_NONE
- || animationType == ANIMATION_TYPE_HIDE) {
+ || animationType == ANIMATION_TYPE_HIDE || (animationType
+ == ANIMATION_TYPE_USER && mIsPredictiveBackImeHideAnimInProgress)) {
// no-op: already hidden or animating out (because window visibility is
// applied before starting animation).
if (isImeAnimation) {