Merge "Fix few typos."
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a618290..67cac98 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19733,7 +19733,7 @@
         mStackSupervisor.setDisplayOverrideConfiguration(mTempConfig, displayId);
 
         final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
-        if (isDensityChange) {
+        if (isDensityChange && displayId == DEFAULT_DISPLAY) {
             // Reset the unsupported display size dialog.
             mUiHandler.sendEmptyMessage(SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG);
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2c315445..2f9868e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1588,9 +1588,24 @@
         // TODO(multidisplay): Needs some serious rethought when the target and IME are not on the
         // same display. Or even when the current IME/target are not on the same screen as the next
         // IME/target. For now only look for input windows on the main screen.
-        mUpdateImeTarget = updateImeTarget;
-        WindowState target = getWindow(mComputeImeTargetPredicate);
 
+        // The target candidate provided by the IME tells us which window token, but not which
+        // window within the token (e.g. child windows...). So, we use the token to look-up the
+        // best target window.
+        // TODO: Have the input method service report the right window with the token vs. just the
+        // base window of the token.
+        final WindowState baseWin = mService.getWindow(mService.mInputMethodTargetCandidate);
+        final WindowToken targetToken = baseWin != null ? baseWin.mToken : null;
+        WindowState target = targetToken != null ?
+                targetToken.getWindow(mComputeImeTargetPredicate) : null;
+        // If there isn't a better candidate in the token (maybe because they are not visible), then
+        // fall back to targeting the base window of the token, so the IME can still maintain the
+        // right z-order based on the last person that set it vs. changing its z-order to the very
+        // up since there if target is null.
+        // TODO: Consider z-ordering IME to bottom instead of top if there is no visible target.
+        // Also, consider tying the visible the visibility of the IME to the current target. I.e if
+        // target isn't visible, then IME shouldn't be visible.
+        target = target == null ? baseWin : target;
 
         // Yet more tricksyness!  If this window is a "starting" window, we do actually want
         // to be on top of it, but it is not -really- where input will go. So look down below
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2f1aab6..2a4dfc4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 import static android.Manifest.permission.MANAGE_APP_TOKENS;
 import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
@@ -30,7 +29,6 @@
 import static android.content.Intent.EXTRA_UID;
 import static android.content.Intent.EXTRA_USER_HANDLE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.UserHandle.USER_NULL;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.DOCKED_INVALID;
@@ -69,8 +67,6 @@
 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
 import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
 import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.KeyguardDisableHandler.KEYGUARD_POLICY_CHANGED;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
@@ -112,7 +108,6 @@
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
-import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -626,9 +621,14 @@
     WindowState mCurrentFocus = null;
     WindowState mLastFocus = null;
 
-    /** This just indicates the window the input method is on top of, not
-     * necessarily the window its input is going to. */
+    // TODO: All the IME window tracking should be moved to DisplayContent and tracked per display.
+    // This just indicates the window the input method is on top of, not necessarily the window its
+    // input is going to.
     WindowState mInputMethodTarget = null;
+    // The binder token currently using the IME as determined by the input method service.
+    // Window manager uses this to determine the final input method target
+    // (almost always this candidate) for z-ordering.
+    IBinder mInputMethodTargetCandidate = null;
 
     /** If true hold off on modifying the animation layer of mInputMethodTarget */
     boolean mInputMethodTargetWaitingAnim;
@@ -6951,8 +6951,9 @@
             pw.print("  mLastFocus="); pw.println(mLastFocus);
         }
         pw.print("  mFocusedApp="); pw.println(mFocusedApp);
-        if (mInputMethodTarget != null) {
-            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
+        if (mInputMethodTarget != null || mInputMethodTargetCandidate != null) {
+            pw.println("  mInputMethodTarget=" + mInputMethodTarget
+                    + " mInputMethodTargetCandidate=" + getWindow(mInputMethodTargetCandidate));
         }
         pw.print("  mInTouchMode="); pw.print(mInTouchMode);
                 pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
@@ -7819,11 +7820,28 @@
         @Override
         public void updateInputMethodWindowStatus(@NonNull IBinder imeToken,
                 boolean imeWindowVisible, @Nullable IBinder targetWindowToken) {
-            // TODO (b/34628091): Use this method to address the window animation issue.
-            if (DEBUG_INPUT_METHOD) {
-                Slog.w(TAG_WM, "updateInputMethodWindowStatus: imeToken=" + imeToken
-                        + " imeWindowVisible=" + imeWindowVisible
-                        + " targetWindowToken=" + targetWindowToken);
+            synchronized (mWindowMap) {
+                final WindowState newTargetWin = getWindow(targetWindowToken);
+                final WindowState currentTargetWin = getWindow(mInputMethodTargetCandidate);
+
+                if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "updateInputMethodWindowStatus: imeToken="
+                        + imeToken + " imeWindowVisible=" + imeWindowVisible
+                        + " targetWindowToken=" + targetWindowToken
+                        + " newTargetWin=" + newTargetWin
+                        + " currentTargetWin=" + currentTargetWin);
+
+                if (newTargetWin == currentTargetWin) {
+                    return;
+                }
+
+                final DisplayContent dc = newTargetWin != null
+                        ? newTargetWin.getDisplayContent() : currentTargetWin.getDisplayContent();
+
+                // It is possible the window for the target candidate isn't added yet, so we
+                // remember the token instead and use it to look-up the window each time we compute
+                // the ime target.
+                mInputMethodTargetCandidate = targetWindowToken;
+                dc.computeImeTarget(true /* updateImeTarget */);
             }
         }
 
@@ -7869,6 +7887,10 @@
         }
     }
 
+    WindowState getWindow(IBinder binder) {
+        return binder == null ? null : mWindowMap.get(binder);
+    }
+
     void registerAppFreezeListener(AppFreezeListener listener) {
         if (!mAppFreezeListeners.contains(listener)) {
             mAppFreezeListeners.add(listener);
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index bd3271b..73ad7c2 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -22,6 +22,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
 import org.junit.Test;
@@ -146,6 +147,7 @@
         final WindowState appWin = createWindow(null, TYPE_APPLICATION, sDisplayContent, "appWin");
         appWin.setHasSurface(true);
         assertTrue(appWin.canBeImeTarget());
+        sWm.mInputMethodTargetCandidate = appWin.mClient.asBinder();
         WindowState imeTarget = sDisplayContent.computeImeTarget(false /* updateImeTarget */);
         assertEquals(appWin, imeTarget);
 
@@ -156,6 +158,20 @@
         assertTrue(childWin.canBeImeTarget());
         imeTarget = sDisplayContent.computeImeTarget(false /* updateImeTarget */);
         assertEquals(childWin, imeTarget);
+
+        final WindowState appWin2 =
+                createWindow(null, TYPE_APPLICATION, sDisplayContent, "appWin2");
+        appWin2.setHasSurface(true);
+        assertTrue(appWin2.canBeImeTarget());
+        // Verify that the IME target isn't adjusted since mInputMethodTargetCandidate didn't change
+        // to the new app.
+        imeTarget = sDisplayContent.computeImeTarget(false /* updateImeTarget */);
+        assertNotEquals(appWin2, imeTarget);
+
+        sWm.mInputMethodTargetCandidate = appWin2.mClient.asBinder();
+        // Verify app is not IME target since its token is set as a candidate.
+        imeTarget = sDisplayContent.computeImeTarget(false /* updateImeTarget */);
+        assertEquals(appWin2, imeTarget);
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 52e10a5..b9c2eed 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -69,7 +69,6 @@
 class WindowTestsBase {
     static WindowManagerService sWm = null;
     static TestWindowManagerPolicy sPolicy = null;
-    private final static IWindow sIWindow = new TestIWindow();
     private final static Session sMockSession = mock(Session.class);
     private static int sNextDisplayId = Display.DEFAULT_DISPLAY + 1;
     static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
@@ -148,6 +147,7 @@
         }
 
         sWm.mInputMethodTarget = null;
+        sWm.mInputMethodTargetCandidate = null;
     }
 
     private static WindowState createCommonWindow(WindowState parent, int type, String name) {
@@ -237,11 +237,12 @@
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
         attrs.setTitle(name);
 
-        final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
-                0, attrs, 0, 0, ownerCanAddInternalSystemWindow);
+        final WindowState w = new WindowState(sWm, sMockSession, new TestIWindow(), token, parent,
+                OP_NONE, 0, attrs, 0, 0, ownerCanAddInternalSystemWindow);
         // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
         // adding it to the token...
         token.addWindow(w);
+        sWm.mWindowMap.put(w.mClient.asBinder(), w);
         return w;
     }
 
@@ -463,8 +464,9 @@
         boolean resizeReported;
 
         TestWindowState(WindowManager.LayoutParams attrs, WindowToken token) {
-            super(sWm, sMockSession, sIWindow, token, null, OP_NONE, 0, attrs, 0, 0,
+            super(sWm, sMockSession, new TestIWindow(), token, null, OP_NONE, 0, attrs, 0, 0,
                     false /* ownerCanAddInternalSystemWindow */);
+            sWm.mWindowMap.put(mClient.asBinder(), this);
         }
 
         @Override