From 1e5b10a21780e09d9f7c762edffbdee4565af52c Mon Sep 17 00:00:00 2001 From: Tiger Huang Date: Mon, 30 Jul 2018 20:19:51 +0800 Subject: Track focus changes on external displays (2/4) Let each DisplayContent has its own focused window and focused app. This change also moves the last tapped display to the top. Test: atest ActivityManagerMultiDisplayTests ActivityStackSupervisorTests ActivityStackTests CtsWindowManagerDeviceTestCases DisplayContentTests PointerCaptureTest Bug: 111361570 Change-Id: I776cabaeaf41ff4240f504fb1430d3e40892023d --- core/java/android/view/IWindowManager.aidl | 1 - .../android/server/windowmanagerservice.proto | 1 + services/art-profile | 2 +- .../com/android/server/am/ActivityDisplay.java | 4 + .../java/com/android/server/am/ActivityStack.java | 2 +- .../android/server/am/ActivityStackSupervisor.java | 2 +- .../server/am/ActivityTaskManagerService.java | 3 +- .../android/server/input/InputManagerService.java | 37 ++- .../android/server/policy/PhoneWindowManager.java | 1 + .../android/server/wm/AccessibilityController.java | 3 +- .../server/wm/AppWindowContainerController.java | 3 +- .../java/com/android/server/wm/AppWindowToken.java | 21 +- .../java/com/android/server/wm/DisplayContent.java | 222 ++++++++++++++-- .../android/server/wm/DisplayWindowController.java | 39 +++ .../java/com/android/server/wm/InputMonitor.java | 16 +- .../com/android/server/wm/RootWindowContainer.java | 93 ++++--- .../server/wm/TaskPositioningController.java | 6 +- .../server/wm/TaskTapPointerEventListener.java | 12 +- .../com/android/server/wm/WindowContainer.java | 8 + .../android/server/wm/WindowManagerService.java | 289 +++++---------------- .../java/com/android/server/wm/WindowState.java | 29 ++- .../com/android/server/wm/WindowSurfacePlacer.java | 1 + .../java/com/android/server/wm/WindowToken.java | 1 + ...om_android_server_input_InputManagerService.cpp | 27 +- .../server/am/ActivityStackSupervisorTests.java | 1 + .../com/android/server/am/ActivityStackTests.java | 7 +- .../com/android/server/wm/DisplayContentTests.java | 46 ++-- .../tests/WindowManagerPermissionTests.java | 10 - 28 files changed, 498 insertions(+), 389 deletions(-) diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 3bab87aea644..3e559d9e106f 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -87,7 +87,6 @@ interface IWindowManager void setEventDispatching(boolean enabled); void addWindowToken(IBinder token, int type, int displayId); void removeWindowToken(IBinder token, int displayId); - void setFocusedApp(IBinder token, boolean moveFocusNow); void prepareAppTransition(int transit, boolean alwaysKeepCurrent); int getPendingAppTransition(); void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim, diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index d33ea0ce503d..c1c86f088873 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -158,6 +158,7 @@ message DisplayContentProto { optional ScreenRotationAnimationProto screen_rotation_animation = 12; optional DisplayFramesProto display_frames = 13; optional int32 surface_size = 14; + optional string focused_app = 15; } /* represents DisplayFrames */ diff --git a/services/art-profile b/services/art-profile index 3c60eee4a2a9..328f8f7a37a7 100644 --- a/services/art-profile +++ b/services/art-profile @@ -2254,8 +2254,8 @@ HPLcom/android/server/wm/DisplayContent;->lambda$new$7(Lcom/android/server/wm/Di HPLcom/android/server/wm/DisplayContent;->lambda$new$8(Lcom/android/server/wm/DisplayContent;Lcom/android/server/wm/WindowState;)V HPLcom/android/server/wm/DisplayContent;->prepareSurfaces()V HPLcom/android/server/wm/DisplayContent;->resetAnimationBackgroundAnimator()V -HPLcom/android/server/wm/DisplayContent;->setTouchExcludeRegion(Lcom/android/server/wm/Task;)V HPLcom/android/server/wm/DisplayContent;->skipTraverseChild(Lcom/android/server/wm/WindowContainer;)Z +HPLcom/android/server/wm/DisplayContent;->updateTouchExcludeRegion()V HPLcom/android/server/wm/DockedStackDividerController;->isResizing()Z HPLcom/android/server/wm/DragDropController;->dragDropActiveLocked()Z HPLcom/android/server/wm/InputMonitor$UpdateInputForAllWindowsConsumer;->accept(Lcom/android/server/wm/WindowState;)V diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java index fab967c01086..9d981f89034c 100644 --- a/services/core/java/com/android/server/am/ActivityDisplay.java +++ b/services/core/java/com/android/server/am/ActivityDisplay.java @@ -920,6 +920,10 @@ class ActivityDisplay extends ConfigurationContainer && (mSupervisor.mService.mRunningVoice == null); } + void setFocusedApp(ActivityRecord r, boolean moveFocusNow) { + mWindowContainerController.setFocusedApp(r.appToken, moveFocusNow); + } + /** * @return the stack currently above the {@param stack}. Can be null if the {@param stack} is * already top-most. diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 29b04ccdab08..a06ebb6c6f2f 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -5434,7 +5434,7 @@ class ActivityStack extends ConfigurationContai // Do not sleep activities in this stack if we're marked as focused and the keyguard // is in the process of going away. - if (mStackSupervisor.getTopDisplayFocusedStack() == this + if (isFocusedStackOnDisplay() && mStackSupervisor.getKeyguardController().isKeyguardGoingAway()) { return false; } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 9688d263643c..98a0ea79f8df 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -3588,7 +3588,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D stack.goToSleepIfPossible(false /* shuttingDown */); } else { stack.awakeFromSleepingLocked(); - if (isTopDisplayFocusedStack(stack) && !getKeyguardController() + if (stack.isFocusedStackOnDisplay() && !getKeyguardController() .isKeyguardOrAodShowing(display.mDisplayId)) { // If the keyguard is unlocked - resume immediately. // It is possible that the display will not be awake at the time we diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java index 36261b505a94..b4f328bf153c 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java @@ -4846,8 +4846,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { updateResumedAppTrace(r); mLastResumedActivity = r; - // TODO(b/111361570): Support multiple focused apps in WM - mWindowManager.setFocusedApp(r.appToken, true); + r.getDisplay().setFocusedApp(r, true); applyUpdateLockStateLocked(r); applyUpdateVrModeLocked(r); diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 5bd095d952b0..4913e8bda6ad 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -209,7 +209,8 @@ public class InputManagerService extends IInputManager.Stub private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen); private static native void nativeSetSystemUiVisibility(long ptr, int visibility); private static native void nativeSetFocusedApplication(long ptr, - InputApplicationHandle application); + int displayId, InputApplicationHandle application); + private static native void nativeSetFocusedDisplay(long ptr, int displayId); private static native boolean nativeTransferTouchFocus(long ptr, InputChannel fromChannel, InputChannel toChannel); private static native void nativeSetPointerSpeed(long ptr, int speed); @@ -1431,21 +1432,27 @@ public class InputManagerService extends IInputManager.Stub } } - public void setInputWindows(InputWindowHandle[] windowHandles, - InputWindowHandle focusedWindowHandle, int displayId) { + public void setInputWindows(InputWindowHandle[] windowHandles, int displayId) { + nativeSetInputWindows(mPtr, windowHandles, displayId); + } + + public void setFocusedApplication(int displayId, InputApplicationHandle application) { + nativeSetFocusedApplication(mPtr, displayId, application); + } + + public void setFocusedWindow(InputWindowHandle focusedWindowHandle) { final IWindow newFocusedWindow = focusedWindowHandle != null ? focusedWindowHandle.clientWindow : null; if (mFocusedWindow != newFocusedWindow) { - mFocusedWindow = newFocusedWindow; if (mFocusedWindowHasCapture) { setPointerCapture(false); } + mFocusedWindow = newFocusedWindow; } - nativeSetInputWindows(mPtr, windowHandles, displayId); } - public void setFocusedApplication(InputApplicationHandle application) { - nativeSetFocusedApplication(mPtr, application); + public void setFocusedDisplay(int displayId) { + nativeSetFocusedDisplay(mPtr, displayId); } @Override @@ -1460,16 +1467,18 @@ public class InputManagerService extends IInputManager.Stub return; } setPointerCapture(enabled); - try { - mFocusedWindow.dispatchPointerCaptureChanged(enabled); - } catch (RemoteException ex) { - /* ignore */ - } } private void setPointerCapture(boolean enabled) { - mFocusedWindowHasCapture = enabled; - nativeSetPointerCapture(mPtr, enabled); + if (mFocusedWindowHasCapture != enabled) { + mFocusedWindowHasCapture = enabled; + try { + mFocusedWindow.dispatchPointerCaptureChanged(enabled); + } catch (RemoteException ex) { + /* ignore */ + } + nativeSetPointerCapture(mPtr, enabled); + } } public void setInputDispatchMode(boolean enabled, boolean frozen) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 2557f46ba34b..b84779c767b9 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4777,6 +4777,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom; // ...with content insets above the nav bar cf.bottom = vf.bottom = displayFrames.mStable.bottom; + // TODO (b/111364446): Support showing IME on non-default displays if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) { // The status bar forces the navigation bar while it's visible. Make sure the IME // avoids the navigation bar in that case. diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index e4491113cfb8..74922f650ad8 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -1043,7 +1043,8 @@ final class AccessibilityController { // Do not send the windows if there is no current focus as // the window manager is still looking for where to put it. // We will do the work when we get a focus change callback. - if (mService.mCurrentFocus == null) { + // TODO(b/112273690): Support multiple displays + if (mService.getDefaultDisplayContentLocked().mCurrentFocus == null) { return; } diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java index 36280dd98180..330c54ca4c1d 100644 --- a/services/core/java/com/android/server/wm/AppWindowContainerController.java +++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java @@ -407,8 +407,7 @@ public class AppWindowContainerController if (mService.mAppTransition.getAppTransition() == WindowManager.TRANSIT_TASK_OPEN_BEHIND) { // We're launchingBehind, add the launching activity to mOpeningApps. - final WindowState win = - mService.getDefaultDisplayContentLocked().findFocusedWindow(); + final WindowState win = mContainer.getDisplayContent().findFocusedWindow(); if (win != null) { final AppWindowToken focusedToken = win.mAppToken; if (focusedToken != null) { diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index fc7610239fa3..e57fea31f1a8 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -679,11 +679,12 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree removed = true; stopFreezingScreen(true, true); - if (mService.mFocusedApp == this) { - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + this); - mService.mFocusedApp = null; + final DisplayContent dc = getDisplayContent(); + if (dc.mFocusedApp == this) { + if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + this + + " displayId=" + dc.getDisplayId()); + dc.setFocusedApp(null); mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); - getDisplayContent().getInputMonitor().setFocusedAppLw(null); } if (!delayed) { @@ -1064,6 +1065,18 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } } + @Override + void onDisplayChanged(DisplayContent dc) { + DisplayContent prevDc = mDisplayContent; + super.onDisplayChanged(dc); + if (prevDc != null && prevDc.mFocusedApp == this) { + prevDc.setFocusedApp(null); + if (dc.getTopStack().getTopChild().getTopChild() == this) { + dc.setFocusedApp(this); + } + } + } + /** * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index a762fe9362c5..730e42208616 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -70,6 +70,7 @@ 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; 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.PINNED_STACK_CONTROLLER; @@ -98,12 +99,17 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; 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.CUSTOM_SCREEN_ROTATION; +import static com.android.server.wm.WindowManagerService.H.REPORT_FOCUS_CHANGE; +import static com.android.server.wm.WindowManagerService.H.REPORT_LOSING_FOCUS; import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION; import static com.android.server.wm.WindowManagerService.H.UPDATE_DOCKED_STACK_DIVIDER; import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT; import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD; import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION; import static com.android.server.wm.WindowManagerService.SEAMLESS_ROTATION_TIMEOUT_DURATION; +import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES; +import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS; +import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_ACTIVE; import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT; @@ -370,6 +376,36 @@ class DisplayContent extends WindowContainer mLosingFocus = new ArrayList<>(); + + /** + * The foreground app of this display. Windows below this app cannot be the focused window. If + * the user taps on the area outside of the task of the focused app, we will notify AM about the + * new task the user wants to interact with. + */ + AppWindowToken mFocusedApp = null; + + /** Windows added since {@link #mCurrentFocus} was set to null. Used for ANR blaming. */ + final ArrayList mWinAddedSinceNullFocus = new ArrayList<>(); + + /** Windows removed since {@link #mCurrentFocus} was set to null. Used for ANR blaming. */ + final ArrayList mWinRemovedSinceNullFocus = new ArrayList<>(); + /** * We organize all top-level Surfaces in to the following layers. * mOverlayLayer contains a few Surfaces which are always on top of others @@ -466,7 +502,7 @@ class DisplayContent extends WindowContainer mFindFocusedWindow = w -> { - final AppWindowToken focusedApp = mService.mFocusedApp; + final AppWindowToken focusedApp = mFocusedApp; if (DEBUG_FOCUS) Slog.v(TAG_WM, "Looking for focus: " + w + ", flags=" + w.mAttrs.flags + ", canReceive=" + w.canReceiveKeys()); @@ -625,8 +661,6 @@ class DisplayContent extends WindowContainer= 0; --stackNdx) { + for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; + --stackNdx) { final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx); stack.setTouchExcludeRegion(focusedTask, delta, mTouchExcludeRegion, mDisplayFrames.mContent, mTmpRect2); } // If we removed the focused task above, add it back and only leave its - // outside touch area in the exclusion. TapDectector is not interested in + // outside touch area in the exclusion. TapDetector is not interested in // any touch inside the focused task itself. if (!mTmpRect2.isEmpty()) { mTouchExcludeRegion.op(mTmpRect2, Region.Op.UNION); @@ -2096,12 +2129,7 @@ class DisplayContent extends WindowContainer= 0; i--) { final WindowState win = mTapExcludedWindows.get(i); @@ -2372,6 +2400,9 @@ class DisplayContent extends WindowContainer= 0; i--) { + final WindowState w = mLosingFocus.get(i); + pw.print(" Losing #"); pw.print(i); pw.print(' '); + pw.print(w); + if (dumpAll) { + pw.println(":"); + w.dump(pw, " ", true); + } else { + pw.println(); + } + } + } + pw.print(" mFocusedApp="); pw.println(mFocusedApp); + pw.println(); pw.println(prefix + "Application tokens in top down Z order:"); for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) { @@ -2543,6 +2595,132 @@ class DisplayContent extends WindowContainer { @@ -414,8 +408,7 @@ final class InputMonitor { } // Send windows to native code. - mService.mInputManager.setInputWindows(mInputWindowHandles, mFocusedInputWindowHandle, - mDisplayId); + mService.mInputManager.setInputWindows(mInputWindowHandles, mDisplayId); clearInputWindowHandlesLw(); @@ -435,7 +428,6 @@ final class InputMonitor { final int flags = w.mAttrs.flags; final int privateFlags = w.mAttrs.privateFlags; final int type = w.mAttrs.type; - // TODO(b/111361570): multi-display focus, one focus window per display. final boolean hasFocus = w.isFocused(); final boolean isVisible = w.isVisibleLw(); diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index a9571be9599d..3fef87dce460 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -17,19 +17,20 @@ package com.android.server.wm; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE; import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; -import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.RootWindowContainerProto.DISPLAYS; import static com.android.server.wm.RootWindowContainerProto.WINDOWS; import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; @@ -41,9 +42,9 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON; 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.REPORT_LOSING_FOCUS; import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION; import static com.android.server.wm.WindowManagerService.H.WINDOW_FREEZE_TIMEOUT; +import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE; @@ -124,6 +125,10 @@ class RootWindowContainer extends WindowContainer { private String mCloseSystemDialogsReason; + // The ID of the display which is responsible for receiving display-unspecified key and pointer + // events. + private int mTopFocusedDisplayId = INVALID_DISPLAY; + // Only a seperate transaction until we seperate the apply surface changes // transaction from the global transaction. private final SurfaceControl.Transaction mDisplayTransaction = new SurfaceControl.Transaction(); @@ -153,23 +158,40 @@ class RootWindowContainer extends WindowContainer { mWallpaperController = new WallpaperController(mService); } - WindowState computeFocusedWindow() { - // While the keyguard is showing, we must focus anything besides the main display. - // Otherwise we risk input not going to the keyguard when the user expects it to. - final boolean forceDefaultDisplay = mService.isKeyguardShowingAndNotOccluded(); - + boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) { + boolean changed = false; + int topFocusedDisplayId = INVALID_DISPLAY; for (int i = mChildren.size() - 1; i >= 0; i--) { final DisplayContent dc = mChildren.get(i); - final WindowState win = dc.findFocusedWindow(); - if (win != null) { - if (forceDefaultDisplay && !dc.isDefaultDisplay) { - EventLog.writeEvent(0x534e4554, "71786287", win.mOwnerUid, ""); - continue; - } - return win; + changed |= dc.updateFocusedWindowLocked(mode, updateInputWindows, + topFocusedDisplayId != INVALID_DISPLAY /* focusFound */); + if (topFocusedDisplayId == INVALID_DISPLAY && dc.mCurrentFocus != null) { + topFocusedDisplayId = dc.getDisplayId(); } } - return null; + if (topFocusedDisplayId == INVALID_DISPLAY) { + topFocusedDisplayId = DEFAULT_DISPLAY; + } + if (mTopFocusedDisplayId != topFocusedDisplayId) { + mTopFocusedDisplayId = topFocusedDisplayId; + mService.mInputManager.setFocusedDisplay(topFocusedDisplayId); + if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "New topFocusedDisplayId=" + + topFocusedDisplayId); + } + final WindowState topFocusedWindow = getTopFocusedDisplayContent().mCurrentFocus; + mService.mInputManager.setFocusedWindow( + topFocusedWindow != null ? topFocusedWindow.mInputWindowHandle : null); + return changed; + } + + DisplayContent getTopFocusedDisplayContent() { + return getDisplayContent(mTopFocusedDisplayId == INVALID_DISPLAY + ? DEFAULT_DISPLAY : mTopFocusedDisplayId); + } + + @Override + void onChildPositionChanged() { + mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /* updateInputWindows */); } DisplayContent getDisplayContent(int displayId) { @@ -636,7 +658,6 @@ class RootWindowContainer extends WindowContainer { if (mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, false /*updateInputWindows*/)) { updateInputWindowsNeeded = true; - defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM; } } @@ -646,7 +667,7 @@ class RootWindowContainer extends WindowContainer { defaultDisplay.pendingLayoutChanges); } - final ArraySet touchExcludeRegionUpdateDisplays = handleResizingWindows(); + handleResizingWindows(); if (DEBUG_ORIENTATION && mService.mDisplayFrozen) Slog.v(TAG, "With display frozen, orientationChangeComplete=" + mOrientationChangeComplete); @@ -765,17 +786,7 @@ class RootWindowContainer extends WindowContainer { dc.getInputMonitor().updateInputWindowsLw(false /*force*/); }); } - mService.setFocusTaskRegionLocked(null); - if (touchExcludeRegionUpdateDisplays != null) { - final DisplayContent focusedDc = mService.mFocusedApp != null - ? mService.mFocusedApp.getDisplayContent() : null; - for (DisplayContent dc : touchExcludeRegionUpdateDisplays) { - // The focused DisplayContent was recalcuated in setFocusTaskRegionLocked - if (focusedDc != dc) { - dc.setTouchExcludeRegion(null /* focusedTask */); - } - } - } + forAllDisplays(DisplayContent::updateTouchExcludeRegion); // Check to see if we are now in a state where the screen should // be enabled, because the window obscured flags have changed. @@ -808,16 +819,10 @@ class RootWindowContainer extends WindowContainer { mService.getDefaultDisplayRotation()); } - boolean focusDisplayed = false; - final int count = mChildren.size(); for (int j = 0; j < count; ++j) { final DisplayContent dc = mChildren.get(j); - focusDisplayed |= dc.applySurfaceChangesTransaction(recoveringMemory); - } - - if (focusDisplayed) { - mService.mH.sendEmptyMessage(REPORT_LOSING_FOCUS); + dc.applySurfaceChangesTransaction(recoveringMemory); } // Give the display manager a chance to adjust properties like display rotation if it needs @@ -828,12 +833,8 @@ class RootWindowContainer extends WindowContainer { /** * Handles resizing windows during surface placement. - * - * @return A set of any DisplayContent whose touch exclude region needs to be recalculated due - * to a tap-exclude window resizing, or null if no such DisplayContents were found. */ - private ArraySet handleResizingWindows() { - ArraySet touchExcludeRegionUpdateSet = null; + private void handleResizingWindows() { for (int i = mService.mResizingWindows.size() - 1; i >= 0; i--) { WindowState win = mService.mResizingWindows.get(i); if (win.mAppFreezing) { @@ -842,15 +843,7 @@ class RootWindowContainer extends WindowContainer { } win.reportResized(); mService.mResizingWindows.remove(i); - if (WindowManagerService.excludeWindowTypeFromTapOutTask(win.mAttrs.type)) { - final DisplayContent dc = win.getDisplayContent(); - if (touchExcludeRegionUpdateSet == null) { - touchExcludeRegionUpdateSet = new ArraySet<>(); - } - touchExcludeRegionUpdateSet.add(dc); - } } - return touchExcludeRegionUpdateSet; } /** @@ -1004,6 +997,10 @@ class RootWindowContainer extends WindowContainer { } } + void dumpTopFocusedDisplayId(PrintWriter pw) { + pw.print(" mTopFocusedDisplayId="); pw.println(mTopFocusedDisplayId); + } + void dumpLayoutNeededDisplayIds(PrintWriter pw) { if (!isLayoutNeeded()) { return; diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java index 33416f66f85b..b7e37b2fd47a 100644 --- a/services/core/java/com/android/server/wm/TaskPositioningController.java +++ b/services/core/java/com/android/server/wm/TaskPositioningController.java @@ -131,9 +131,9 @@ class TaskPositioningController { // of the app, it may not have focus since there might be other windows // on top (eg. a dialog window). WindowState transferFocusFromWin = win; - if (mService.mCurrentFocus != null && mService.mCurrentFocus != win - && mService.mCurrentFocus.mAppToken == win.mAppToken) { - transferFocusFromWin = mService.mCurrentFocus; + if (displayContent.mCurrentFocus != null && displayContent.mCurrentFocus != win + && displayContent.mCurrentFocus.mAppToken == win.mAppToken) { + transferFocusFromWin = displayContent.mCurrentFocus; } if (!mInputManager.transferTouchFocus( transferFocusFromWin.mInputChannel, mTaskPositioner.mServerChannel)) { diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java index f1e1592da83e..52f8510d6a99 100644 --- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java +++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java @@ -19,12 +19,12 @@ package com.android.server.wm; import android.graphics.Rect; import android.graphics.Region; import android.hardware.input.InputManager; +import android.os.Handler; import android.view.MotionEvent; import android.view.WindowManagerPolicyConstants.PointerEventListener; import com.android.server.wm.WindowManagerService.H; -import static android.view.Display.DEFAULT_DISPLAY; import static android.view.PointerIcon.TYPE_NOT_SPECIFIED; import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW; import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW; @@ -36,6 +36,8 @@ public class TaskTapPointerEventListener implements PointerEventListener { final private Region mTouchExcludeRegion = new Region(); private final WindowManagerService mService; private final DisplayContent mDisplayContent; + private final Handler mHandler; + private final Runnable mMoveDisplayToTop; private final Rect mTmpRect = new Rect(); private int mPointerIconType = TYPE_NOT_SPECIFIED; @@ -43,6 +45,13 @@ public class TaskTapPointerEventListener implements PointerEventListener { DisplayContent displayContent) { mService = service; mDisplayContent = displayContent; + mHandler = new Handler(mService.mH.getLooper()); + mMoveDisplayToTop = () -> { + synchronized (mService.mWindowMap) { + mDisplayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, + mDisplayContent, true /* includingParents */); + } + }; } @Override @@ -61,6 +70,7 @@ public class TaskTapPointerEventListener implements PointerEventListener { mService.mTaskPositioningController.handleTapOutsideTask( mDisplayContent, x, y); } + mHandler.post(mMoveDisplayToTop); } } break; diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 4883f972f1e5..46999a2a847e 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -273,6 +273,7 @@ class WindowContainer extends ConfigurationContainer< parent.mTreeWeight += child.mTreeWeight; parent = parent.getParent(); } + onChildPositionChanged(); } /** @@ -298,6 +299,7 @@ class WindowContainer extends ConfigurationContainer< parent.mTreeWeight -= child.mTreeWeight; parent = parent.getParent(); } + onChildPositionChanged(); } /** @@ -455,8 +457,14 @@ class WindowContainer extends ConfigurationContainer< mChildren.remove(child); mChildren.add(position, child); } + onChildPositionChanged(); } + /** + * Notify that a child's position has changed. Possible changes are adding or removing a child. + */ + void onChildPositionChanged() { } + /** * Update override configuration and recalculate full config. * @see #mOverrideConfiguration diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 942e47b4725f..fc33a4f4d7ac 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -498,12 +498,6 @@ public class WindowManagerService extends IWindowManager.Stub */ final ArrayList mDestroyPreservedSurface = new ArrayList<>(); - /** - * Windows that have lost input focus and are waiting for the new - * focus window to be displayed before they are told about this. - */ - ArrayList mLosingFocus = new ArrayList<>(); - /** * This is set when we have run out of memory, and will either be an empty * list or contain windows that need to be force removed. @@ -639,14 +633,6 @@ public class WindowManagerService extends IWindowManager.Stub */ final Handler mAnimationHandler = new Handler(AnimationThread.getHandler().getLooper()); - WindowState mCurrentFocus = null; - WindowState mLastFocus = null; - - /** Windows added since {@link #mCurrentFocus} was set to null. Used for ANR blaming. */ - private final ArrayList mWinAddedSinceNullFocus = new ArrayList<>(); - /** Windows removed since {@link #mCurrentFocus} was set to null. Used for ANR blaming. */ - private final ArrayList mWinRemovedSinceNullFocus = new ArrayList<>(); - /** This just indicates the window the input method is on top of, not * necessarily the window its input is going to. */ WindowState mInputMethodTarget = null; @@ -721,9 +707,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - // TODO: Move to RootWindowContainer - AppWindowToken mFocusedApp = null; - PowerManager mPowerManager; PowerManagerInternal mPowerManagerInternal; @@ -1371,8 +1354,8 @@ public class WindowManagerService extends IWindowManager.Stub // the screen after the activity goes away. if (addToastWindowRequiresToken || (attrs.flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0 - || mCurrentFocus == null - || mCurrentFocus.mOwnerUid != callingUid) { + || displayContent.mCurrentFocus == null + || displayContent.mCurrentFocus.mOwnerUid != callingUid) { mH.sendMessageDelayed( mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win), win.mAttrs.hideTimeoutMilliseconds); @@ -1382,8 +1365,8 @@ public class WindowManagerService extends IWindowManager.Stub // From now on, no exceptions or errors allowed! res = WindowManagerGlobal.ADD_OKAY; - if (mCurrentFocus == null) { - mWinAddedSinceNullFocus.add(win); + if (displayContent.mCurrentFocus == null) { + displayContent.mWinAddedSinceNullFocus.add(win); } if (excludeWindowTypeFromTapOutTask(type)) { @@ -1504,7 +1487,7 @@ public class WindowManagerService extends IWindowManager.Stub win.getParent().assignChildLayers(); if (focusChanged) { - displayContent.getInputMonitor().setInputFocusLw(mCurrentFocus, + displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus, false /*updateInputWindows*/); } displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/); @@ -1679,8 +1662,9 @@ public class WindowManagerService extends IWindowManager.Stub win.resetAppOpsState(); - if (mCurrentFocus == null) { - mWinRemovedSinceNullFocus.add(win); + final DisplayContent dc = win.getDisplayContent(); + if (dc.mCurrentFocus == null) { + dc.mWinRemovedSinceNullFocus.add(win); } mPendingRemove.remove(win); mResizingWindows.remove(win); @@ -1716,7 +1700,6 @@ public class WindowManagerService extends IWindowManager.Stub atoken.postWindowRemoveStartingWindowCleanup(win); } - final DisplayContent dc = win.getDisplayContent(); if (win.mAttrs.type == TYPE_WALLPAPER) { dc.mWallpaperController.clearLastWallpaperTimeoutTime(); dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; @@ -1978,9 +1961,9 @@ public class WindowManagerService extends IWindowManager.Stub boolean imMayMove = (flagChanges & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0 || becameVisible; final boolean isDefaultDisplay = win.isDefaultDisplay(); - boolean focusMayChange = isDefaultDisplay && (win.mViewVisibility != viewVisibility + boolean focusMayChange = win.mViewVisibility != viewVisibility || ((flagChanges & FLAG_NOT_FOCUSABLE) != 0) - || (!win.mRelayoutCalled)); + || (!win.mRelayoutCalled); boolean wallpaperMayMove = win.mViewVisibility != viewVisibility && (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0; @@ -2025,8 +2008,7 @@ public class WindowManagerService extends IWindowManager.Stub } result |= RELAYOUT_RES_SURFACE_CHANGED; if (!win.mWillReplaceWindow) { - focusMayChange = tryStartExitingAnimation(win, winAnimator, isDefaultDisplay, - focusMayChange); + focusMayChange = tryStartExitingAnimation(win, winAnimator, focusMayChange); } } @@ -2051,7 +2033,7 @@ public class WindowManagerService extends IWindowManager.Stub return 0; } if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { - focusMayChange = isDefaultDisplay; + focusMayChange = true; } final DisplayContent displayContent = win.getDisplayContent(); if (win.mAttrs.type == TYPE_INPUT_METHOD @@ -2199,7 +2181,7 @@ public class WindowManagerService extends IWindowManager.Stub } private boolean tryStartExitingAnimation(WindowState win, WindowStateAnimator winAnimator, - boolean isDefaultDisplay, boolean focusMayChange) { + boolean focusMayChange) { // Try starting an animation; if there isn't one, we // can destroy the surface right away. int transit = WindowManagerPolicy.TRANSIT_EXIT; @@ -2207,7 +2189,7 @@ public class WindowManagerService extends IWindowManager.Stub transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; } if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) { - focusMayChange = isDefaultDisplay; + focusMayChange = true; win.mAnimatingExit = true; } else if (win.isAnimating()) { // Currently in a hide animation... turn this into @@ -2504,57 +2486,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - void setFocusTaskRegionLocked(AppWindowToken previousFocus) { - final Task focusedTask = mFocusedApp != null ? mFocusedApp.getTask() : null; - final Task previousTask = previousFocus != null ? previousFocus.getTask() : null; - final DisplayContent focusedDisplayContent = - focusedTask != null ? focusedTask.getDisplayContent() : null; - final DisplayContent previousDisplayContent = - previousTask != null ? previousTask.getDisplayContent() : null; - if (previousDisplayContent != null && previousDisplayContent != focusedDisplayContent) { - previousDisplayContent.setTouchExcludeRegion(null); - } - if (focusedDisplayContent != null) { - focusedDisplayContent.setTouchExcludeRegion(focusedTask); - } - } - - @Override - public void setFocusedApp(IBinder token, boolean moveFocusNow) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "setFocusedApp()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - synchronized(mWindowMap) { - final AppWindowToken newFocus; - if (token == null) { - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Clearing focused app, was " + mFocusedApp); - newFocus = null; - } else { - newFocus = mRoot.getAppWindowToken(token); - if (newFocus == null) { - Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token); - } - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Set focused app to: " + newFocus - + " old focus=" + mFocusedApp + " moveFocusNow=" + moveFocusNow); - } - - final boolean changed = mFocusedApp != newFocus; - if (changed) { - AppWindowToken prev = mFocusedApp; - mFocusedApp = newFocus; - mFocusedApp.getDisplayContent().getInputMonitor().setFocusedAppLw(newFocus); - setFocusTaskRegionLocked(prev); - } - - if (moveFocusNow && changed) { - final long origId = Binder.clearCallingIdentity(); - updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); - Binder.restoreCallingIdentity(origId); - } - } - } - @Override public void prepareAppTransition(@TransitionType int transit, boolean alwaysKeepCurrent) { prepareAppTransition(transit, alwaysKeepCurrent, 0 /* flags */, false /* forceOverride */); @@ -4395,7 +4326,8 @@ public class WindowManagerService extends IWindowManager.Stub } private WindowState getFocusedWindowLocked() { - return mCurrentFocus; + // Return the focused window in the focused display. + return mRoot.getTopFocusedDisplayContent().mCurrentFocus; } TaskStack getImeFocusStackLocked() { @@ -4403,8 +4335,11 @@ public class WindowManagerService extends IWindowManager.Stub // Also don't use mInputMethodTarget's stack, because some window with FLAG_NOT_FOCUSABLE // and FLAG_ALT_FOCUSABLE_IM flags both set might be set to IME target so they're moved // to make room for IME, but the window is not the focused window that's taking input. - return (mFocusedApp != null && mFocusedApp.getTask() != null) ? - mFocusedApp.getTask().mStack : null; + // TODO (b/111080190): Consider the case of multiple IMEs on multi-display. + final DisplayContent topFocusedDisplay = mRoot.getTopFocusedDisplayContent(); + final AppWindowToken focusedApp = topFocusedDisplay.mFocusedApp; + return (focusedApp != null && focusedApp.getTask() != null) + ? focusedApp.getTask().mStack : null; } public boolean detectSafeMode() { @@ -4601,6 +4536,7 @@ public class WindowManagerService extends IWindowManager.Stub } switch (msg.what) { case REPORT_FOCUS_CHANGE: { + final DisplayContent displayContent = (DisplayContent) msg.obj; WindowState lastFocus; WindowState newFocus; @@ -4608,24 +4544,22 @@ public class WindowManagerService extends IWindowManager.Stub synchronized(mWindowMap) { // TODO(multidisplay): Accessibility supported only of default desiplay. - if (mAccessibilityController != null && getDefaultDisplayContentLocked() - .getDisplayId() == DEFAULT_DISPLAY) { + if (mAccessibilityController != null && displayContent.isDefaultDisplay) { accessibilityController = mAccessibilityController; } - lastFocus = mLastFocus; - newFocus = mCurrentFocus; + lastFocus = displayContent.mLastFocus; + newFocus = displayContent.mCurrentFocus; if (lastFocus == newFocus) { // Focus is not changing, so nothing to do. return; } - mLastFocus = newFocus; + displayContent.mLastFocus = newFocus; if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Focus moving from " + lastFocus + - " to " + newFocus); - if (newFocus != null && lastFocus != null - && !newFocus.isDisplayedLw()) { - //Slog.i(TAG_WM, "Delaying loss of focus..."); - mLosingFocus.add(lastFocus); + " to " + newFocus + " displayId=" + displayContent.getDisplayId()); + if (newFocus != null && lastFocus != null && !newFocus.isDisplayedLw()) { + if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Delaying loss of focus..."); + displayContent.mLosingFocus.add(lastFocus); lastFocus = null; } } @@ -4636,8 +4570,6 @@ public class WindowManagerService extends IWindowManager.Stub accessibilityController.onWindowFocusChangedNotLocked(); } - //System.out.println("Changing focus from " + lastFocus - // + " to " + newFocus); if (newFocus != null) { if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Gaining focus: " + newFocus); newFocus.reportFocusChangedSerialized(true, mInTouchMode); @@ -4651,15 +4583,16 @@ public class WindowManagerService extends IWindowManager.Stub } break; case REPORT_LOSING_FOCUS: { + final DisplayContent displayContent = (DisplayContent) msg.obj; ArrayList losers; synchronized(mWindowMap) { - losers = mLosingFocus; - mLosingFocus = new ArrayList(); + losers = displayContent.mLosingFocus; + displayContent.mLosingFocus = new ArrayList<>(); } final int N = losers.size(); - for (int i=0; i 0) { - pw.println(); - pw.println(" Windows losing focus:"); - for (int i=mLosingFocus.size()-1; i>=0; i--) { - WindowState w = mLosingFocus.get(i); - if (windows == null || windows.contains(w)) { - pw.print(" Losing #"); pw.print(i); pw.print(' '); - pw.print(w); - if (dumpAll) { - pw.println(":"); - w.dump(pw, " ", true); - } else { - pw.println(); - } - } - } - } if (mResizingWindows.size() > 0) { pw.println(); pw.println(" Windows waiting to resize:"); @@ -6344,11 +6183,7 @@ public class WindowManagerService extends IWindowManager.Stub pw.println(); pw.print(" mGlobalConfiguration="); pw.println(mRoot.getConfiguration()); pw.print(" mHasPermanentDpad="); pw.println(mHasPermanentDpad); - pw.print(" mCurrentFocus="); pw.println(mCurrentFocus); - if (mLastFocus != mCurrentFocus) { - pw.print(" mLastFocus="); pw.println(mLastFocus); - } - pw.print(" mFocusedApp="); pw.println(mFocusedApp); + mRoot.dumpTopFocusedDisplayId(pw); if (mInputMethodTarget != null) { pw.print(" mInputMethodTarget="); pw.println(mInputMethodTarget); } @@ -6479,11 +6314,17 @@ public class WindowManagerService extends IWindowManager.Stub if (reason != null) { pw.println(" Reason: " + reason); } - if (!mWinAddedSinceNullFocus.isEmpty()) { - pw.println(" Windows added since null focus: " + mWinAddedSinceNullFocus); - } - if (!mWinRemovedSinceNullFocus.isEmpty()) { - pw.println(" Windows removed since null focus: " + mWinRemovedSinceNullFocus); + for (int i = mRoot.getChildCount() - 1; i >= 0; i--) { + final DisplayContent dc = mRoot.getChildAt(i); + final int displayId = dc.getDisplayId(); + if (!dc.mWinAddedSinceNullFocus.isEmpty()) { + pw.println(" Windows added in display #" + displayId + " since null focus: " + + dc.mWinAddedSinceNullFocus); + } + if (!dc.mWinRemovedSinceNullFocus.isEmpty()) { + pw.println(" Windows removed in display #" + displayId + " since null focus: " + + dc.mWinRemovedSinceNullFocus); + } } pw.println(); dumpWindowsNoHeaderLocked(pw, true, null); @@ -6818,9 +6659,9 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setDockedStackDividerTouchRegion(Rect touchRegion) { synchronized (mWindowMap) { - getDefaultDisplayContentLocked().getDockedDividerController() - .setTouchRegion(touchRegion); - setFocusTaskRegionLocked(null); + final DisplayContent dc = getDefaultDisplayContentLocked(); + dc.getDockedDividerController().setTouchRegion(touchRegion); + dc.updateTouchExcludeRegion(); } } @@ -7373,7 +7214,14 @@ public class WindowManagerService extends IWindowManager.Stub @Override public boolean isUidFocused(int uid) { synchronized (mWindowMap) { - return mCurrentFocus != null ? uid == mCurrentFocus.getOwningUid() : false; + for (int i = mRoot.getChildCount() - 1; i >= 0; i--) { + final DisplayContent displayContent = mRoot.getChildAt(i); + if (displayContent.mCurrentFocus != null + && uid == displayContent.mCurrentFocus.getOwningUid()) { + return true; + } + } + return false; } } @@ -7396,8 +7244,9 @@ public class WindowManagerService extends IWindowManager.Stub // press home. Sometimes the IME won't go down.) // Would be nice to fix this more correctly, but it's // way at the end of a release, and this should be good enough. - if (mCurrentFocus != null && mCurrentFocus.mSession.mUid == uid - && mCurrentFocus.mSession.mPid == pid) { + final WindowState currentFocus = mRoot.getTopFocusedDisplayContent().mCurrentFocus; + if (currentFocus != null && currentFocus.mSession.mUid == uid + && currentFocus.mSession.mPid == pid) { return true; } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index a4bac31bbcee..8276952d8a6c 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1833,7 +1833,7 @@ class WindowState extends WindowContainer implements WindowManagerP if (startingWindow && DEBUG_STARTING_WINDOW) Slog.d(TAG_WM, "Starting window removed " + this); - if (localLOGV || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && this == mService.mCurrentFocus) + if (localLOGV || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && isFocused()) Slog.v(TAG_WM, "Remove " + this + " client=" + Integer.toHexString(System.identityHashCode(mClient.asBinder())) + ", surfaceController=" + mWinAnimator.mSurfaceController + " Callers=" @@ -1945,7 +1945,7 @@ class WindowState extends WindowContainer implements WindowManagerP if (wasVisible && mService.updateOrientationFromAppTokensLocked(displayId)) { mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget(); } - mService.updateFocusedWindowLocked(mService.mCurrentFocus == this + mService.updateFocusedWindowLocked(isFocused() ? UPDATE_FOCUS_REMOVING_FOCUS : UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); @@ -2180,7 +2180,7 @@ class WindowState extends WindowContainer implements WindowManagerP mPolicyVisibility = mPolicyVisibilityAfterAnim; if (!mPolicyVisibility) { mWinAnimator.hide("checkPolicyVisibilityChange"); - if (mService.mCurrentFocus == this) { + if (isFocused()) { if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "setAnimationLocked: setting mFocusMayChange true"); mService.mFocusMayChange = true; @@ -2482,6 +2482,7 @@ class WindowState extends WindowContainer implements WindowManagerP } } mPolicyVisibilityAfterAnim = false; + final boolean isFocused = isFocused(); if (!doAnimation) { if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility false: " + this); mPolicyVisibility = false; @@ -2489,7 +2490,7 @@ class WindowState extends WindowContainer implements WindowManagerP // for it to be displayed before enabling the display, that // we allow the display to be enabled now. mService.enableScreenIfNeededLocked(); - if (mService.mCurrentFocus == this) { + if (isFocused) { if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "WindowState.hideLw: setting mFocusMayChange true"); mService.mFocusMayChange = true; @@ -2498,7 +2499,7 @@ class WindowState extends WindowContainer implements WindowManagerP if (requestAnim) { mService.scheduleAnimationLocked(); } - if (mService.mCurrentFocus == this) { + if (isFocused) { mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /* updateImWindows */); } return true; @@ -2994,10 +2995,8 @@ class WindowState extends WindowContainer implements WindowManagerP } } - public boolean isFocused() { - synchronized(mService.mWindowMap) { - return mService.mCurrentFocus == this; - } + boolean isFocused() { + return getDisplayContent().mCurrentFocus == this; } @Override @@ -4435,7 +4434,12 @@ class WindowState extends WindowContainer implements WindowManagerP @Override public boolean isFocused() { final WindowState outer = mOuter.get(); - return outer != null && outer.isFocused(); + if (outer != null) { + synchronized (outer.mService.mWindowMap) { + return outer.isFocused(); + } + } + return false; } } @@ -4663,10 +4667,7 @@ class WindowState extends WindowContainer implements WindowManagerP mTapExcludeRegionHolder.updateRegion(regionId, left, top, width, height); // Trigger touch exclude region update on current display. - final boolean isAppFocusedOnDisplay = mService.mFocusedApp != null - && mService.mFocusedApp.getDisplayContent() == currentDisplay; - currentDisplay.setTouchExcludeRegion(isAppFocusedOnDisplay ? mService.mFocusedApp.getTask() - : null); + currentDisplay.updateTouchExcludeRegion(); } /** Union the region with current tap exclude region that this window provides. */ diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index 080a3a269947..24ac07adf371 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -763,6 +763,7 @@ class WindowSurfacePlacer { private void processApplicationsAnimatingInPlace(int transit) { if (transit == TRANSIT_TASK_IN_PLACE) { + // TODO (b/111362605): non-default-display transition. // Find the focused window final WindowState win = mService.getDefaultDisplayContentLocked().findFocusedWindow(); if (win != null) { diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index fefd305bc6d6..0cf79b63e9dc 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -255,6 +255,7 @@ class WindowToken extends WindowContainer { super.removeImmediately(); } + @Override void onDisplayChanged(DisplayContent dc) { dc.reParentWindowToken(this); mDisplayContent = dc; diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index a754d2aa96b1..1f2eef4eaf49 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -221,7 +221,8 @@ public: status_t unregisterInputChannel(JNIEnv* env, const sp& inputChannel); void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray, int32_t displayId); - void setFocusedApplication(JNIEnv* env, jobject applicationHandleObj); + void setFocusedApplication(JNIEnv* env, int32_t displayId, jobject applicationHandleObj); + void setFocusedDisplay(JNIEnv* env, int32_t displayId); void setInputDispatchMode(bool enabled, bool frozen); void setSystemUiVisibility(int32_t visibility); void setPointerSpeed(int32_t speed); @@ -771,10 +772,15 @@ void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleO } } -void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationHandleObj) { +void NativeInputManager::setFocusedApplication(JNIEnv* env, int32_t displayId, + jobject applicationHandleObj) { sp applicationHandle = android_server_InputApplicationHandle_getHandle(env, applicationHandleObj); - mInputManager->getDispatcher()->setFocusedApplication(applicationHandle); + mInputManager->getDispatcher()->setFocusedApplication(displayId, applicationHandle); +} + +void NativeInputManager::setFocusedDisplay(JNIEnv* env, int32_t displayId) { + mInputManager->getDispatcher()->setFocusedDisplay(displayId); } void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) { @@ -1413,10 +1419,17 @@ static void nativeSetInputWindows(JNIEnv* env, jclass /* clazz */, } static void nativeSetFocusedApplication(JNIEnv* env, jclass /* clazz */, - jlong ptr, jobject applicationHandleObj) { + jlong ptr, jint displayId, jobject applicationHandleObj) { + NativeInputManager* im = reinterpret_cast(ptr); + + im->setFocusedApplication(env, displayId, applicationHandleObj); +} + +static void nativeSetFocusedDisplay(JNIEnv* env, jclass /* clazz */, + jlong ptr, jint displayId) { NativeInputManager* im = reinterpret_cast(ptr); - im->setFocusedApplication(env, applicationHandleObj); + im->setFocusedDisplay(env, displayId); } static void nativeSetPointerCapture(JNIEnv* env, jclass /* clazz */, jlong ptr, @@ -1638,8 +1651,10 @@ static const JNINativeMethod gInputManagerMethods[] = { (void*) nativeToggleCapsLock }, { "nativeSetInputWindows", "(J[Lcom/android/server/input/InputWindowHandle;I)V", (void*) nativeSetInputWindows }, - { "nativeSetFocusedApplication", "(JLcom/android/server/input/InputApplicationHandle;)V", + { "nativeSetFocusedApplication", "(JILcom/android/server/input/InputApplicationHandle;)V", (void*) nativeSetFocusedApplication }, + { "nativeSetFocusedDisplay", "(JI)V", + (void*) nativeSetFocusedDisplay }, { "nativeSetPointerCapture", "(JZ)V", (void*) nativeSetPointerCapture }, { "nativeSetInputDispatchMode", "(JZZ)V", diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java index 0345a81b5bec..3d0bdc9b2d18 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java @@ -232,6 +232,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { doReturn(displaySleeping).when(display).isSleeping(); doReturn(keyguardShowing).when(keyguard).isKeyguardOrAodShowing(anyInt()); + doReturn(isFocusedStack).when(stack).isFocusedStackOnDisplay(); doReturn(isFocusedStack ? stack : null).when(display).getFocusedStack(); mSupervisor.applySleepTokensLocked(true); verify(stack, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleepingLocked(); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java index ab814ee15df0..5fcd2aa35e05 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -38,6 +38,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import android.content.pm.ActivityInfo; import android.os.UserHandle; @@ -71,8 +72,8 @@ public class ActivityStackTests extends ActivityTestsBase { setupActivityTaskManagerService(); mDefaultDisplay = mSupervisor.getDefaultDisplay(); - mStack = mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, - true /* onTop */); + mStack = spy(mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, + true /* onTop */)); mTask = new TaskBuilder(mSupervisor).setStack(mStack).build(); } @@ -720,7 +721,7 @@ public class ActivityStackTests extends ActivityTestsBase { doReturn(display).when(mSupervisor).getActivityDisplay(anyInt()); doReturn(keyguardGoingAway).when(keyguardController).isKeyguardGoingAway(); doReturn(displaySleeping).when(display).isSleeping(); - doReturn(focusedStack ? mStack : null).when(mSupervisor).getTopDisplayFocusedStack(); + doReturn(focusedStack).when(mStack).isFocusedStackOnDisplay(); assertEquals(expected, mStack.shouldSleepActivities()); } 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 b3303049be39..96c5fde83926 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java @@ -32,6 +32,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; import static com.android.server.wm.WindowContainer.POSITION_TOP; +import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; @@ -303,7 +304,8 @@ public class DisplayContentTests extends WindowTestsBase { createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, false)); // Check focus is on primary display. - assertEquals(sWm.mCurrentFocus, dc0.findFocusedWindow()); + assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus, + dc0.findFocusedWindow()); // Tap on secondary display DisplayMetrics dm1 = dc1.getDisplayMetrics(); @@ -313,7 +315,8 @@ public class DisplayContentTests extends WindowTestsBase { createTapEvent(dm1.widthPixels / 2, dm1.heightPixels / 2, false)); // Check focus is on secondary. - assertEquals(sWm.mCurrentFocus, dc1.findFocusedWindow()); + assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus, + dc1.findFocusedWindow()); } @Test @@ -321,34 +324,29 @@ public class DisplayContentTests extends WindowTestsBase { // Create a focusable window and check that focus is calculated correctly final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1"); - assertEquals(window1, sWm.mRoot.computeFocusedWindow()); + updateFocusedWindow(); + assertTrue(window1.isFocused()); + assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus); // Check that a new display doesn't affect focus final DisplayContent dc = createNewDisplay(); - assertEquals(window1, sWm.mRoot.computeFocusedWindow()); + updateFocusedWindow(); + assertTrue(window1.isFocused()); + assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus); // Add a window to the second display, and it should be focused final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, dc, "window2"); - assertEquals(window2, sWm.mRoot.computeFocusedWindow()); + updateFocusedWindow(); + assertTrue(window1.isFocused()); + assertTrue(window2.isFocused()); + assertEquals(window2, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus); // Move the first window to the to including parents, and make sure focus is updated window1.getParent().positionChildAt(POSITION_TOP, window1, true); - assertEquals(window1, sWm.mRoot.computeFocusedWindow()); - } - - @Test - public void testKeyguard_preventsSecondaryDisplayFocus() throws Exception { - final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR, - sWm.getDefaultDisplayContentLocked(), "keyguard"); - assertEquals(keyguard, sWm.mRoot.computeFocusedWindow()); - - // Add a window to a second display, and it should be focused - final DisplayContent dc = createNewDisplay(); - final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win"); - assertEquals(win, sWm.mRoot.computeFocusedWindow()); - - mWmRule.getWindowManagerPolicy().keyguardShowingAndNotOccluded = true; - assertEquals(keyguard, sWm.mRoot.computeFocusedWindow()); + updateFocusedWindow(); + assertTrue(window1.isFocused()); + assertTrue(window2.isFocused()); + assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus); } /** @@ -590,6 +588,12 @@ public class DisplayContentTests extends WindowTestsBase { assertEquals(displayContent.mBaseDisplayDensity, expectedBaseDensity); } + private void updateFocusedWindow() { + synchronized (sWm.mWindowMap) { + sWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false); + } + } + /** * Create DisplayContent that does not update display base/initial values from device to keep * the values set by test. diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java index 9c4da1f72e38..14312cf84693 100644 --- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java @@ -82,16 +82,6 @@ public class WindowManagerPermissionTests extends TestCase { fail("Unexpected remote exception"); } - try { - mWm.setFocusedApp(null, false); - fail("IWindowManager.setFocusedApp did not throw SecurityException as" - + " expected"); - } catch (SecurityException e) { - // expected - } catch (RemoteException e) { - fail("Unexpected remote exception"); - } - try { mWm.prepareAppTransition(0, false); fail("IWindowManager.prepareAppTransition did not throw SecurityException as" -- cgit v1.2.3-59-g8ed1b