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;