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

Commit b45af76b authored by Hiroki Sato's avatar Hiroki Sato
Browse files

Dispatch accessibility gesture if device supports touch

This change fixes the issue where AccessibilityService was not able to
dispatch a gesture if a device doesn't have a touchscreen hardware
feature, resulting the behavior gap between CTS and framework.

With this CL, AccessibilityService can dispatch a gesture if the device
declares touchscreen or faketouch hardware features.

Bug: 177021722
Test: AccessibilityManagerServiceTest AccessibilityServiceConnectionTest
Test: CtsAccessibilityServiceTestCases on crosshatch and kindred
Change-Id: I8a1e4884d1283705d409ed38e35047ec2dcd89f0
parent b4dcfabf
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -372,12 +372,11 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect

    @Override
    public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
        final boolean isTouchableDisplay = mWindowManagerService.isTouchableDisplay(displayId);
        synchronized (mLock) {
            if (mSecurityPolicy.canPerformGestures(this)) {
                MotionEventInjector motionEventInjector =
                        mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId);
                if (motionEventInjector != null && isTouchableDisplay) {
                if (mWindowManagerService.isTouchOrFaketouchDevice()) {
                    motionEventInjector.injectEvents(
                            gestureSteps.getList(), mServiceInterface, sequence, displayId);
                } else {
+2 −2
Original line number Diff line number Diff line
@@ -543,9 +543,9 @@ public abstract class WindowManagerInternal {
    public abstract void removeNonHighRefreshRatePackage(@NonNull String packageName);

    /**
     * Checks if this display is touchable.
     * Checks if the device supports touch or faketouch.
     */
    public abstract boolean isTouchableDisplay(int displayId);
    public abstract boolean isTouchOrFaketouchDevice();

    /**
     * Returns the info associated with the input token used to determine if a key should be
+6 −6
Original line number Diff line number Diff line
@@ -753,6 +753,7 @@ public class WindowManagerService extends IWindowManager.Stub
    final TaskSnapshotController mTaskSnapshotController;

    boolean mIsTouchDevice;
    boolean mIsFakeTouchDevice;

    final H mH = new H();

@@ -5030,6 +5031,8 @@ public class WindowManagerService extends IWindowManager.Stub
            mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);
            mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
                    PackageManager.FEATURE_TOUCHSCREEN);
            mIsFakeTouchDevice = mContext.getPackageManager().hasSystemFeature(
                    PackageManager.FEATURE_FAKETOUCH);
        }

        try {
@@ -8018,13 +8021,10 @@ public class WindowManagerService extends IWindowManager.Stub
        }

        @Override
        public boolean isTouchableDisplay(int displayId) {
        public boolean isTouchOrFaketouchDevice() {
            synchronized (mGlobalLock) {
                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                final Configuration configuration =
                        displayContent != null ? displayContent.getConfiguration() : null;
                return configuration != null
                        && configuration.touchscreen == Configuration.TOUCHSCREEN_FINGER;
                // All touchable devices are also faketouchable.
                return mIsFakeTouchDevice;
            }
        }

+4 −6
Original line number Diff line number Diff line
@@ -110,8 +110,6 @@ public class AccessibilityServiceConnectionTest {
        mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);

        when(mMockIBinder.queryLocalInterface(any())).thenReturn(mMockServiceClient);
        when(mMockWindowManagerInternal.isTouchableDisplay(Display.DEFAULT_DISPLAY)).thenReturn(
                true);

        mConnection = new AccessibilityServiceConnection(mMockUserState, mMockContext,
                COMPONENT_NAME, mMockServiceInfo, SERVICE_ID, mHandler, new Object(),
@@ -197,8 +195,9 @@ public class AccessibilityServiceConnectionTest {
    }

    @Test
    public void sendGesture_touchableDisplay_injectEvents()
    public void sendGesture_touchableDevice_injectEvents()
            throws RemoteException {
        when(mMockWindowManagerInternal.isTouchOrFaketouchDevice()).thenReturn(true);
        setServiceBinding(COMPONENT_NAME);
        mConnection.bindLocked();
        mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
@@ -213,10 +212,9 @@ public class AccessibilityServiceConnectionTest {
    }

    @Test
    public void sendGesture_untouchableDisplay_performGestureResultFailed()
    public void sendGesture_untouchableDevice_performGestureResultFailed()
            throws RemoteException {
        when(mMockWindowManagerInternal.isTouchableDisplay(Display.DEFAULT_DISPLAY)).thenReturn(
                false);
        when(mMockWindowManagerInternal.isTouchOrFaketouchDevice()).thenReturn(false);
        setServiceBinding(COMPONENT_NAME);
        mConnection.bindLocked();
        mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);