OSDN Git Service

Displays that have focused apps can also be top focused
authorLouis Chang <louischang@google.com>
Thu, 25 Apr 2019 09:14:20 +0000 (17:14 +0800)
committerLouis Chang <louischang@google.com>
Thu, 9 May 2019 05:21:35 +0000 (13:21 +0800)
There was no focus window during activity switches.
- While starting an activity, the previous top activity was paused and set
  the AppWindowToken.hiddenRequested to true (while #setVisibility)
- While finishing current top activity, the focused window was updated a
  bit early, which was before the next top activity resumed.

In both two cases, the focused window was set to null for a small amount of
time. So, we tried to look up the focus in other displays and resulted
the extra onWindowFocusChanged() calls for activities on other displays.

Bug: 131374329
Test: DisplayContentTests
Change-Id: Ia77bf697c237696cad7b42ca6b38157eff497b23

services/core/java/com/android/server/wm/DisplayContent.java
services/core/java/com/android/server/wm/RootWindowContainer.java
services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java

index 652f7ee..7a98903 100644 (file)
@@ -78,6 +78,8 @@ import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_W
 import static com.android.server.wm.DisplayContentProto.ABOVE_APP_WINDOWS;
 import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
 import static com.android.server.wm.DisplayContentProto.BELOW_APP_WINDOWS;
+import static com.android.server.wm.DisplayContentProto.CHANGING_APPS;
+import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
 import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES;
 import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO;
 import static com.android.server.wm.DisplayContentProto.DOCKED_STACK_DIVIDER_CONTROLLER;
@@ -85,14 +87,12 @@ import static com.android.server.wm.DisplayContentProto.DPI;
 import static com.android.server.wm.DisplayContentProto.FOCUSED_APP;
 import static com.android.server.wm.DisplayContentProto.ID;
 import static com.android.server.wm.DisplayContentProto.IME_WINDOWS;
+import static com.android.server.wm.DisplayContentProto.OPENING_APPS;
 import static com.android.server.wm.DisplayContentProto.PINNED_STACK_CONTROLLER;
 import static com.android.server.wm.DisplayContentProto.ROTATION;
 import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
 import static com.android.server.wm.DisplayContentProto.STACKS;
 import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER;
-import static com.android.server.wm.DisplayContentProto.OPENING_APPS;
-import static com.android.server.wm.DisplayContentProto.CHANGING_APPS;
-import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
@@ -2945,9 +2945,16 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
         forAllWindows(mScheduleToastTimeout, false /* traverseTopToBottom */);
     }
 
-    WindowState findFocusedWindowIfNeeded() {
-        return (mWmService.mPerDisplayFocusEnabled
-                || mWmService.mRoot.mTopFocusedAppByProcess.isEmpty()) ? findFocusedWindow() : null;
+    /**
+     * Looking for the focused window on this display if the top focused display hasn't been
+     * found yet (topFocusedDisplayId is INVALID_DISPLAY) or per-display focused was allowed.
+     *
+     * @param topFocusedDisplayId Id of the top focused display.
+     * @return The focused window or null if there isn't any or no need to seek.
+     */
+    WindowState findFocusedWindowIfNeeded(int topFocusedDisplayId) {
+        return (mWmService.mPerDisplayFocusEnabled || topFocusedDisplayId == INVALID_DISPLAY)
+                ? findFocusedWindow() : null;
     }
 
     WindowState findFocusedWindow() {
@@ -2971,10 +2978,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
      *             {@link WindowManagerService#UPDATE_FOCUS_WILL_PLACE_SURFACES},
      *             {@link WindowManagerService#UPDATE_FOCUS_REMOVING_FOCUS}
      * @param updateInputWindows Whether to sync the window information to the input module.
+     * @param topFocusedDisplayId Display id of current top focused display.
      * @return {@code true} if the focused window has changed.
      */
-    boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
-        WindowState newFocus = findFocusedWindowIfNeeded();
+    boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows,
+            int topFocusedDisplayId) {
+        WindowState newFocus = findFocusedWindowIfNeeded(topFocusedDisplayId);
         if (mCurrentFocus == newFocus) {
             return false;
         }
@@ -2994,7 +3003,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
         if (imWindowChanged) {
             mWmService.mWindowsChanged = true;
             setLayoutNeeded();
-            newFocus = findFocusedWindowIfNeeded();
+            newFocus = findFocusedWindowIfNeeded(topFocusedDisplayId);
         }
         if (mCurrentFocus != newFocus) {
             mWmService.mH.obtainMessage(REPORT_FOCUS_CHANGE, this).sendToTarget();
index 9f42324..8a5f52f 100644 (file)
@@ -170,7 +170,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
         int topFocusedDisplayId = INVALID_DISPLAY;
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final DisplayContent dc = mChildren.get(i);
-            changed |= dc.updateFocusedWindowLocked(mode, updateInputWindows);
+            changed |= dc.updateFocusedWindowLocked(mode, updateInputWindows, topFocusedDisplayId);
             final WindowState newFocus = dc.mCurrentFocus;
             if (newFocus != null) {
                 final int pidOfNewFocus = newFocus.mSession.mPid;
@@ -180,6 +180,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
                 if (topFocusedDisplayId == INVALID_DISPLAY) {
                     topFocusedDisplayId = dc.getDisplayId();
                 }
+            } else if (topFocusedDisplayId == INVALID_DISPLAY && dc.mFocusedApp != null) {
+                // The top-most display that has a focused app should still be the top focused
+                // display even when the app window is not ready yet (process not attached or
+                // window not added yet).
+                topFocusedDisplayId = dc.getDisplayId();
             }
         }
         if (topFocusedDisplayId == INVALID_DISPLAY) {
index e60e54c..04f897e 100644 (file)
@@ -380,6 +380,14 @@ public class DisplayContentTests extends WindowTestsBase {
         assertTrue(window1.isFocused());
         assertEquals(perDisplayFocusEnabled && targetSdk >= Q, window2.isFocused());
         assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
+
+        // Make sure top focused display not changed if there is a focused app.
+        window1.mAppToken.hiddenRequested = true;
+        window1.getDisplayContent().setFocusedApp(window1.mAppToken);
+        updateFocusedWindow();
+        assertTrue(!window1.isFocused());
+        assertEquals(window1.getDisplayId(),
+                mWm.mRoot.getTopFocusedDisplayContent().getDisplayId());
     }
 
     /**