Make canBeImeTarget be compatible with legacy behavior
And let PerDisplay can adjust animation parameters while the insets
source control is changed during animation.
Fix: 151759336
Test: atest WindowStateTests
Change-Id: Ic2a308e6b7ec39b4b8645751e31addd26ddf3735
(cherry picked from commit 1ea1ea6a04536238d56a7107badc222500746c8a)
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index c2ee21d..9172029 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1249,6 +1249,7 @@
WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars());
mWindow.getWindow().getAttributes().setFitInsetsSides(Side.all() & ~Side.BOTTOM);
+ mWindow.getWindow().setStatusBarColor(0);
// IME layout should always be inset by navigation bar, no matter its current visibility,
// unless automotive requests it, since automotive may hide the navigation bar.
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index 5411839..18fb953 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -97,7 +97,7 @@
}
if (mSystemWindows.mDisplayController.getDisplayLayout(displayId).rotation()
!= pd.mRotation && isImeShowing(displayId)) {
- pd.startAnimation(true);
+ pd.startAnimation(true /* show */, false /* force */);
}
}
@@ -200,7 +200,14 @@
continue;
}
if (activeControl.getType() == InsetsState.ITYPE_IME) {
- mImeSourceControl = activeControl;
+ synchronized (this) {
+ mImeSourceControl = activeControl;
+ if (mAnimation != null) {
+ // The surface position of IME might have been changed during
+ // animation, so start animation again to update the position.
+ startAnimation(mImeShowing, true /* force */);
+ }
+ }
}
}
}
@@ -212,7 +219,7 @@
return;
}
if (DEBUG) Slog.d(TAG, "Got showInsets for ime");
- startAnimation(true /* show */);
+ startAnimation(true /* show */, false /* force */);
}
@Override
@@ -221,7 +228,7 @@
return;
}
if (DEBUG) Slog.d(TAG, "Got hideInsets for ime");
- startAnimation(false /* show */);
+ startAnimation(false /* show */, false /* force */);
}
/**
@@ -239,111 +246,119 @@
return imeSource.getFrame().top + (int) surfaceOffset;
}
- private void startAnimation(final boolean show) {
+ private void startAnimation(final boolean show, final boolean force) {
final InsetsSource imeSource = mInsetsState.getSource(InsetsState.ITYPE_IME);
if (imeSource == null || mImeSourceControl == null) {
return;
}
mHandler.post(() -> {
- if (DEBUG) {
- Slog.d(TAG, "Run startAnim show:" + show + " was:"
- + (mAnimationDirection == DIRECTION_SHOW ? "SHOW"
- : (mAnimationDirection == DIRECTION_HIDE ? "HIDE" : "NONE")));
- }
- if ((mAnimationDirection == DIRECTION_SHOW && show)
- || (mAnimationDirection == DIRECTION_HIDE && !show)) {
- return;
- }
- boolean seek = false;
- float seekValue = 0;
- if (mAnimation != null) {
- if (mAnimation.isRunning()) {
- seekValue = (float) mAnimation.getAnimatedValue();
- seek = true;
+ synchronized (this) {
+ if (DEBUG) {
+ Slog.d(TAG, "Run startAnim show:" + show + " was:"
+ + (mAnimationDirection == DIRECTION_SHOW ? "SHOW"
+ : (mAnimationDirection == DIRECTION_HIDE ? "HIDE" : "NONE")));
}
- mAnimation.cancel();
- }
- mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
- final float defaultY = mImeSourceControl.getSurfacePosition().y;
- final float x = mImeSourceControl.getSurfacePosition().x;
- final float hiddenY = defaultY + imeSource.getFrame().height();
- final float shownY = defaultY;
- final float startY = show ? hiddenY : shownY;
- final float endY = show ? shownY : hiddenY;
- if (mImeShowing && show) {
- // IME is already showing, so set seek to end
- seekValue = shownY;
- seek = true;
- }
- mImeShowing = show;
- mAnimation = ValueAnimator.ofFloat(startY, endY);
- mAnimation.setDuration(
- show ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS);
- if (seek) {
- mAnimation.setCurrentFraction((seekValue - startY) / (endY - startY));
- }
+ if (!force && (mAnimationDirection == DIRECTION_SHOW && show)
+ || (mAnimationDirection == DIRECTION_HIDE && !show)) {
+ return;
+ }
+ boolean seek = false;
+ float seekValue = 0;
+ if (mAnimation != null) {
+ if (mAnimation.isRunning()) {
+ seekValue = (float) mAnimation.getAnimatedValue();
+ seek = true;
+ }
+ mAnimation.cancel();
+ }
+ mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
+ final float defaultY = mImeSourceControl.getSurfacePosition().y;
+ final float x = mImeSourceControl.getSurfacePosition().x;
+ final float hiddenY = defaultY + imeSource.getFrame().height();
+ final float shownY = defaultY;
+ final float startY = show ? hiddenY : shownY;
+ final float endY = show ? shownY : hiddenY;
+ mImeShowing = show;
+ mAnimation = ValueAnimator.ofFloat(startY, endY);
+ mAnimation.setDuration(
+ show ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS);
+ if (seek) {
+ mAnimation.setCurrentFraction((seekValue - startY) / (endY - startY));
+ }
- mAnimation.addUpdateListener(animation -> {
- SurfaceControl.Transaction t = mTransactionPool.acquire();
- float value = (float) animation.getAnimatedValue();
- t.setPosition(mImeSourceControl.getLeash(), x, value);
- dispatchPositionChanged(mDisplayId, imeTop(imeSource, value), t);
- t.apply();
- mTransactionPool.release(t);
- });
- mAnimation.setInterpolator(INTERPOLATOR);
- mAnimation.addListener(new AnimatorListenerAdapter() {
- private boolean mCancelled = false;
- @Override
- public void onAnimationStart(Animator animation) {
- SurfaceControl.Transaction t = mTransactionPool.acquire();
- t.setPosition(mImeSourceControl.getLeash(), x, startY);
- if (DEBUG) {
- Slog.d(TAG, "onAnimationStart d:" + mDisplayId + " top:"
- + imeTop(imeSource, hiddenY) + "->" + imeTop(imeSource, shownY)
- + " showing:" + (mAnimationDirection == DIRECTION_SHOW));
+ mAnimation.addUpdateListener(animation -> {
+ synchronized (this) {
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ float value = (float) animation.getAnimatedValue();
+ t.setPosition(mImeSourceControl.getLeash(), x, value);
+ dispatchPositionChanged(mDisplayId, imeTop(imeSource, value), t);
+ t.apply();
+ mTransactionPool.release(t);
}
- dispatchStartPositioning(mDisplayId, imeTop(imeSource, hiddenY),
- imeTop(imeSource, shownY), mAnimationDirection == DIRECTION_SHOW,
- t);
- if (mAnimationDirection == DIRECTION_SHOW) {
- t.show(mImeSourceControl.getLeash());
- }
- t.apply();
- mTransactionPool.release(t);
- }
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancelled = true;
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- if (DEBUG) Slog.d(TAG, "onAnimationEnd " + mCancelled);
- SurfaceControl.Transaction t = mTransactionPool.acquire();
- if (!mCancelled) {
- t.setPosition(mImeSourceControl.getLeash(), x, endY);
- }
- dispatchEndPositioning(mDisplayId, mCancelled, t);
- if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
- t.hide(mImeSourceControl.getLeash());
- }
- t.apply();
- mTransactionPool.release(t);
+ });
+ mAnimation.setInterpolator(INTERPOLATOR);
+ mAnimation.addListener(new AnimatorListenerAdapter() {
+ private boolean mCancelled = false;
- mAnimationDirection = DIRECTION_NONE;
- mAnimation = null;
+ @Override
+ public void onAnimationStart(Animator animation) {
+ synchronized (this) {
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ t.setPosition(mImeSourceControl.getLeash(), x, startY);
+ if (DEBUG) {
+ Slog.d(TAG, "onAnimationStart d:" + mDisplayId
+ + " top:" + imeTop(imeSource, hiddenY)
+ + "->" + imeTop(imeSource, shownY)
+ + " showing:"
+ + (mAnimationDirection == DIRECTION_SHOW));
+ }
+ dispatchStartPositioning(mDisplayId, imeTop(imeSource, hiddenY),
+ imeTop(imeSource, shownY),
+ mAnimationDirection == DIRECTION_SHOW, t);
+ if (mAnimationDirection == DIRECTION_SHOW) {
+ t.show(mImeSourceControl.getLeash());
+ }
+ t.apply();
+ mTransactionPool.release(t);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ synchronized (this) {
+ if (DEBUG) Slog.d(TAG, "onAnimationEnd " + mCancelled);
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ if (!mCancelled) {
+ t.setPosition(mImeSourceControl.getLeash(), x, endY);
+ }
+ dispatchEndPositioning(mDisplayId, mCancelled, t);
+ if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
+ t.hide(mImeSourceControl.getLeash());
+ }
+ t.apply();
+ mTransactionPool.release(t);
+
+ mAnimationDirection = DIRECTION_NONE;
+ mAnimation = null;
+ }
+ }
+ });
+ if (!show) {
+ // When going away, queue up insets change first, otherwise any bounds
+ // changes can have a "flicker" of ime-provided insets.
+ setVisibleDirectly(false /* visible */);
}
- });
- if (!show) {
- // When going away, queue up insets change first, otherwise any bounds changes
- // can have a "flicker" of ime-provided insets.
- setVisibleDirectly(false /* visible */);
- }
- mAnimation.start();
- if (show) {
- // When showing away, queue up insets change last, otherwise any bounds changes
- // can have a "flicker" of ime-provided insets.
- setVisibleDirectly(true /* visible */);
+ mAnimation.start();
+ if (show) {
+ // When showing away, queue up insets change last, otherwise any bounds
+ // changes can have a "flicker" of ime-provided insets.
+ setVisibleDirectly(true /* visible */);
+ }
}
});
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 161152b..cf8773b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -131,6 +131,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.H.WINDOW_STATE_BLAST_SYNC_TIMEOUT;
import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
@@ -138,7 +139,6 @@
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
-import static com.android.server.wm.WindowManagerService.H.WINDOW_STATE_BLAST_SYNC_TIMEOUT;
import static com.android.server.wm.WindowStateAnimator.COMMIT_DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
@@ -2270,9 +2270,9 @@
return false;
}
- if (PixelFormat.formatHasAlpha(mAttrs.format) && mAttrs.alpha == 0) {
- // Support legacy use cases where completely transparent windows can still be ime target
- // with FLAG_NOT_FOCUSABLE and ALT_FOCUSABLE_IM set.
+ if (PixelFormat.formatHasAlpha(mAttrs.format)) {
+ // Support legacy use cases where transparent windows can still be ime target with
+ // FLAG_NOT_FOCUSABLE and ALT_FOCUSABLE_IM set.
// Certain apps listen for IME insets using transparent windows and ADJUST_NOTHING to
// manually synchronize app content to IME animation b/144619551.
// TODO(b/145812508): remove this once new focus management is complete b/141738570
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 85e4a16..e95ccab3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -251,11 +251,9 @@
// b/145812508: special legacy use-case for transparent/translucent windows.
appWindow.mAttrs.format = PixelFormat.TRANSPARENT;
- appWindow.mAttrs.alpha = 0;
assertTrue(appWindow.canBeImeTarget());
appWindow.mAttrs.format = PixelFormat.OPAQUE;
- appWindow.mAttrs.alpha = 1;
appWindow.mAttrs.flags &= ~FLAG_ALT_FOCUSABLE_IM;
assertFalse(appWindow.canBeImeTarget());
appWindow.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE;