Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aef03412 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix Instrumentation#setInTouchMode behavior."

parents 0c6346a0 dd448e58
Loading
Loading
Loading
Loading
+42 −27
Original line number Diff line number Diff line
@@ -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.
     */
+45 −0
Original line number Diff line number Diff line
@@ -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(