Fix Instrumentation#setInTouchMode behavior.
Instrumentation#setInTouchMode should set the touch mode for all displays, regardless of the value of the perDisplayFocusEnabled flag and whether any display has own touch mode / own focus. The fix is WindowManagerService#setInTouchModeOnAllDisplays ignoring the "own focus" property of displays. Test: atest TouchModeTest Test: atest WindowManagerServiceTests Fix: 267331091 Change-Id: I5a9010e23e3d91ac65f2d7ee8790cf2288bed1a2
This commit is contained in:
@@ -3831,8 +3831,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
|
||||
@@ -3844,27 +3845,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;
|
||||
}
|
||||
@@ -3875,15 +3858,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);
|
||||
}
|
||||
@@ -3906,6 +3886,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.
|
||||
*/
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user