Handle focused tasks on multiple displays
When the focused task changes displays, make sure to mark the whole
previous display as not part of a focused task.
This change also adds an adb am command to change the task focus.
Test: android.server.cts.ActivityManagerDisplayTests
Test: #testStackFocusSwitchOnTouchEvent
Bug: 35214007
Change-Id: I9cb7372c21a0b592abb6f6d910077ff5097dd6cf
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index a06fa1b..80df26b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2031,6 +2031,8 @@
return runTaskDragTaskTest(pw);
} else if (op.equals("size-task-test")) {
return runTaskSizeTaskTest(pw);
+ } else if (op.equals("focus")) {
+ return runTaskFocus(pw);
} else {
getErrPrintWriter().println("Error: unknown command '" + op + "'");
return -1;
@@ -2322,6 +2324,13 @@
return 0;
}
+ int runTaskFocus(PrintWriter pw) throws RemoteException {
+ final int taskId = Integer.parseInt(getNextArgRequired());
+ pw.println("Setting focus to task " + taskId);
+ mInterface.setFocusedTask(taskId);
+ return 0;
+ }
+
int runWrite(PrintWriter pw) {
mInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
"registerUidObserver()");
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c45136c..2c315445 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1072,19 +1072,25 @@
}
void setTouchExcludeRegion(Task focusedTask) {
- mTouchExcludeRegion.set(mBaseDisplayRect);
- final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
- mTmpRect2.setEmpty();
- for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
- final TaskStack stack = mTaskStackContainers.get(stackNdx);
- stack.setTouchExcludeRegion(
- focusedTask, delta, mTouchExcludeRegion, mContentRect, 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
- // any touch inside the focused task itself.
- if (!mTmpRect2.isEmpty()) {
- mTouchExcludeRegion.op(mTmpRect2, Region.Op.UNION);
+ // The provided task is the task on this display with focus, so if WindowManagerService's
+ // focused app is not on this display, focusedTask will be null.
+ if (focusedTask == null) {
+ mTouchExcludeRegion.setEmpty();
+ } else {
+ mTouchExcludeRegion.set(mBaseDisplayRect);
+ final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
+ mTmpRect2.setEmpty();
+ for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
+ final TaskStack stack = mTaskStackContainers.get(stackNdx);
+ stack.setTouchExcludeRegion(
+ focusedTask, delta, mTouchExcludeRegion, mContentRect, 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
+ // any touch inside the focused task itself.
+ if (!mTmpRect2.isEmpty()) {
+ mTouchExcludeRegion.op(mTmpRect2, Region.Op.UNION);
+ }
}
final WindowState inputMethod = mService.mInputMethodWindow;
if (inputMethod != null && inputMethod.isVisibleLw()) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 80e6655..126e080 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -784,7 +784,7 @@
if (updateInputWindowsNeeded) {
mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
}
- mService.setFocusTaskRegionLocked();
+ mService.setFocusTaskRegionLocked(null);
// Check to see if we are now in a state where the screen should
// be enabled, because the window obscured flags have changed.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 597e8b6..a2946db 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2574,13 +2574,18 @@
}
}
- void setFocusTaskRegionLocked() {
+ void setFocusTaskRegionLocked(AppWindowToken previousFocus) {
final Task focusedTask = mFocusedApp != null ? mFocusedApp.mTask : null;
- if (focusedTask != null) {
- final DisplayContent displayContent = focusedTask.getDisplayContent();
- if (displayContent != null) {
- displayContent.setTouchExcludeRegion(focusedTask);
- }
+ final Task previousTask = previousFocus != null ? previousFocus.mTask : 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);
}
}
@@ -2606,9 +2611,10 @@
final boolean changed = mFocusedApp != newFocus;
if (changed) {
+ AppWindowToken prev = mFocusedApp;
mFocusedApp = newFocus;
mInputMonitor.setFocusedAppLw(newFocus);
- setFocusTaskRegionLocked();
+ setFocusTaskRegionLocked(prev);
}
if (moveFocusNow && changed) {
@@ -7439,7 +7445,7 @@
synchronized (mWindowMap) {
getDefaultDisplayContentLocked().getDockedDividerController()
.setTouchRegion(touchRegion);
- setFocusTaskRegionLocked();
+ setFocusTaskRegionLocked(null);
}
}