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
This commit is contained in:
Hiroki Sato
2021-01-14 14:12:31 +09:00
parent b4dcfabf07
commit b45af76b3d
4 changed files with 13 additions and 16 deletions

View File

@@ -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 {

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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);