diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 5f49aebda7ed3..ad819820ceece 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -3844,8 +3844,9 @@ public class WindowManagerService extends IWindowManager.Stub * * If {@code com.android.internal.R.bool.config_perDisplayFocusEnabled} is set to true, then * only the display represented by the {@code displayId} parameter will be requested to switch - * the touch mode state. Otherwise all all displays will be requested to switch their touch mode - * state (disregarding {@code displayId} parameter). + * the touch mode state. Otherwise all displays that do not maintain their own focus and touch + * mode will be requested to switch their touch mode state (disregarding {@code displayId} + * parameter). * * To be able to change touch mode state, the caller must either own the focused window, or must * have the {@link android.Manifest.permission#MODIFY_TOUCH_MODE_STATE} permission. Instrumented @@ -3857,27 +3858,9 @@ public class WindowManagerService extends IWindowManager.Stub */ @Override // Binder call public void setInTouchMode(boolean inTouch, int displayId) { - boolean perDisplayFocusEnabled = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_perDisplayFocusEnabled); - setInTouchMode(inTouch, displayId, perDisplayFocusEnabled); - } - - /** - * Sets the touch mode state on all displays (disregarding the value of - * {@code com.android.internal.R.bool.config_perDisplayFocusEnabled}). - * - * @param inTouch the touch mode to set - */ - @Override // Binder call - public void setInTouchModeOnAllDisplays(boolean inTouch) { - setInTouchMode(inTouch, /* any display id */ DEFAULT_DISPLAY, - /* perDisplayFocusEnabled= */ false); - } - - private void setInTouchMode(boolean inTouch, int displayId, boolean perDisplayFocusEnabled) { synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); - if (perDisplayFocusEnabled && (displayContent == null + if (mPerDisplayFocusEnabled && (displayContent == null || displayContent.isInTouchMode() == inTouch)) { return; } @@ -3888,15 +3871,12 @@ public class WindowManagerService extends IWindowManager.Stub } final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); - final boolean hasPermission = - mAtmService.instrumentationSourceHasPermission(pid, MODIFY_TOUCH_MODE_STATE) - || checkCallingPermission(MODIFY_TOUCH_MODE_STATE, "setInTouchMode()", - /* printlog= */ false); + final boolean hasPermission = hasTouchModePermission(pid); final long token = Binder.clearCallingIdentity(); try { - // If perDisplayFocusEnabled is set or the display maintains its own touch mode, + // If mPerDisplayFocusEnabled is set or the display maintains its own touch mode, // then just update the display pointed by displayId - if (perDisplayFocusEnabled || displayHasOwnTouchMode) { + if (mPerDisplayFocusEnabled || displayHasOwnTouchMode) { if (mInputManager.setInTouchMode(inTouch, pid, uid, hasPermission, displayId)) { displayContent.setInTouchMode(inTouch); } @@ -3919,6 +3899,41 @@ public class WindowManagerService extends IWindowManager.Stub } } + /** + * Sets the touch mode state forcibly on all displays (disregarding both the value of + * {@code com.android.internal.R.bool.config_perDisplayFocusEnabled} and whether the display + * maintains its own focus and touch mode). + * + * @param inTouch the touch mode to set + */ + @Override // Binder call + public void setInTouchModeOnAllDisplays(boolean inTouch) { + final int pid = Binder.getCallingPid(); + final int uid = Binder.getCallingUid(); + final boolean hasPermission = hasTouchModePermission(pid); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + for (int i = 0; i < mRoot.mChildren.size(); ++i) { + DisplayContent dc = mRoot.mChildren.get(i); + if (dc.isInTouchMode() != inTouch + && mInputManager.setInTouchMode(inTouch, pid, uid, hasPermission, + dc.mDisplayId)) { + dc.setInTouchMode(inTouch); + } + } + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + private boolean hasTouchModePermission(int pid) { + return mAtmService.instrumentationSourceHasPermission(pid, MODIFY_TOUCH_MODE_STATE) + || checkCallingPermission(MODIFY_TOUCH_MODE_STATE, "setInTouchMode()", + /* printlog= */ false); + } + /** * Returns the touch mode state for the display id passed as argument. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java index 2984de9f9cf5b..4dd5de3b999c1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java @@ -500,6 +500,51 @@ public class WindowManagerServiceTests extends WindowTestsBase { virtualDisplay.getDisplay().getDisplayId()); } + @Test + public void testSetInTouchModeOnAllDisplays_perDisplayFocusDisabled() { + testSetInTouchModeOnAllDisplays(/* perDisplayFocusEnabled= */ false); + } + + @Test + public void testSetInTouchModeOnAllDisplays_perDisplayFocusEnabled() { + testSetInTouchModeOnAllDisplays(/* perDisplayFocusEnabled= */ true); + } + + private void testSetInTouchModeOnAllDisplays(boolean perDisplayFocusEnabled) { + // Create a couple of extra displays. + // setInTouchModeOnAllDisplays should ignore the ownFocus setting. + final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false); + final VirtualDisplay virtualDisplayOwnFocus = createVirtualDisplay(/* ownFocus= */ true); + + // Enable or disable global touch mode (config_perDisplayFocusEnabled setting). + // setInTouchModeOnAllDisplays should ignore this value. + Resources mockResources = mock(Resources.class); + spyOn(mContext); + when(mContext.getResources()).thenReturn(mockResources); + doReturn(perDisplayFocusEnabled).when(mockResources).getBoolean( + com.android.internal.R.bool.config_perDisplayFocusEnabled); + + int callingPid = Binder.getCallingPid(); + int callingUid = Binder.getCallingUid(); + doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean()); + when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid, + android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(true); + + for (boolean inTouchMode : new boolean[]{true, false}) { + mWm.setInTouchModeOnAllDisplays(inTouchMode); + for (int i = 0; i < mWm.mRoot.mChildren.size(); ++i) { + DisplayContent dc = mWm.mRoot.mChildren.get(i); + // All displays that are not already in the desired touch mode are requested to + // change their touch mode. + if (dc.isInTouchMode() != inTouchMode) { + verify(mWm.mInputManager).setInTouchMode( + true, callingPid, callingUid, /* hasPermission= */ true, + dc.getDisplay().getDisplayId()); + } + } + } + } + private VirtualDisplay createVirtualDisplay(boolean ownFocus) { // Create virtual display Point surfaceSize = new Point(