summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Daniel Norman <danielnorman@google.com> 2025-01-29 14:01:54 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-01-29 14:01:54 -0800
commit7143d096a8bedff00a89cc0f7ce80d180d957e89 (patch)
treecb2079c2755d3c43389e670b9c1c9209ea2a08b9
parent48a6892d7b618875caa0d8e874b69691b5667ddb (diff)
parent2945b46dd7e8346fa6228067683ac57a2a338e86 (diff)
Merge "Stop non-tool A11yServices from injecting gestures onto sensitive views." into main
-rw-r--r--core/java/android/view/MotionEvent.java38
-rw-r--r--core/java/android/view/View.java10
-rw-r--r--core/java/android/view/WindowManagerPolicyConstants.java2
-rw-r--r--core/java/android/view/accessibility/flags/accessibility_flags.aconfig154
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java5
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java3
-rw-r--r--services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java51
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java26
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java66
9 files changed, 250 insertions, 105 deletions
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index bd6ff4c2af02..ae0e9c623571 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -532,14 +532,30 @@ public final class MotionEvent extends InputEvent implements Parcelable {
public static final int FLAG_NO_FOCUS_CHANGE = MotionEventFlag.NO_FOCUS_CHANGE;
/**
- * This flag indicates that this event was modified by or generated from an accessibility
- * service. Value = 0x800
+ * This flag indicates that this event was injected from some
+ * {@link android.accessibilityservice.AccessibilityService}, which may be either an
+ * Accessibility Tool OR a service using that API for purposes other than assisting users with
+ * disabilities. Value = 0x800
+ * @see #FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL
* @hide
*/
@TestApi
public static final int FLAG_IS_ACCESSIBILITY_EVENT = MotionEventFlag.IS_ACCESSIBILITY_EVENT;
/**
+ * This flag indicates that this event was injected from an
+ * {@link android.accessibilityservice.AccessibilityService} with the
+ * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool()} property
+ * set to true. These services (known as "Accessibility Tools") are used to assist users with
+ * disabilities, so events from these services should be able to reach all Views including
+ * Views which set {@link View#isAccessibilityDataSensitive()} to true.
+ * Value = 0x1000
+ * @hide
+ */
+ public static final int FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL =
+ MotionEventFlag.INJECTED_FROM_ACCESSIBILITY_TOOL;
+
+ /**
* Private flag that indicates when the system has detected that this motion event
* may be inconsistent with respect to the sequence of previously delivered motion events,
* such as when a pointer move event is sent but the pointer is not down.
@@ -2534,6 +2550,24 @@ public final class MotionEvent extends InputEvent implements Parcelable {
: flags & ~FLAG_TARGET_ACCESSIBILITY_FOCUS);
}
+ /**
+ * @see #FLAG_IS_ACCESSIBILITY_EVENT
+ * @hide
+ */
+ public boolean isInjectedFromAccessibilityService() {
+ final int flags = getFlags();
+ return (flags & FLAG_IS_ACCESSIBILITY_EVENT) != 0;
+ }
+
+ /**
+ * @see #FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL
+ * @hide
+ */
+ public boolean isInjectedFromAccessibilityTool() {
+ final int flags = getFlags();
+ return (flags & FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL) != 0;
+ }
+
/** @hide */
public final boolean isHoverExitPending() {
final int flags = getFlags();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7206906658ff..0866e0d832b1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16654,6 +16654,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// Window is obscured, drop this touch.
return false;
}
+ if (android.view.accessibility.Flags.preventA11yNontoolFromInjectingIntoSensitiveViews()) {
+ if (event.isInjectedFromAccessibilityService()
+ // If the event came from an Accessibility Service that does *not* declare
+ // itself as AccessibilityServiceInfo#isAccessibilityTool and this View is
+ // declared sensitive then drop the event.
+ // Only Accessibility Tools are allowed to interact with sensitive Views.
+ && !event.isInjectedFromAccessibilityTool() && isAccessibilityDataSensitive()) {
+ return false;
+ }
+ }
return true;
}
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index 6d2c0d0061dd..bb8958bc9c70 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -17,6 +17,7 @@
package android.view;
import static android.os.IInputConstants.POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY;
+import static android.os.IInputConstants.POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL;
import static android.os.IInputConstants.POLICY_FLAG_KEY_GESTURE_TRIGGERED;
import android.annotation.IntDef;
@@ -37,6 +38,7 @@ public interface WindowManagerPolicyConstants {
int FLAG_VIRTUAL = 0x00000002;
int FLAG_INJECTED_FROM_ACCESSIBILITY = POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY;
+ int FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL = POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL;
int FLAG_KEY_GESTURE_TRIGGERED = POLICY_FLAG_KEY_GESTURE_TRIGGERED;
int FLAG_INJECTED = 0x01000000;
int FLAG_TRUSTED = 0x02000000;
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index 294e5da1edd1..37f393ec6511 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -4,6 +4,14 @@ container: "system"
# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
flag {
+ name: "a11y_character_in_window_api"
+ namespace: "accessibility"
+ description: "Enables new extra data key for an AccessibilityService to request character bounds in unmagnified window coordinates."
+ bug: "375429616"
+ is_exported: true
+}
+
+flag {
name: "a11y_expansion_state_api"
namespace: "accessibility"
description: "Enables new APIs for an app to convey if a node is expanded or collapsed."
@@ -42,23 +50,15 @@ flag {
}
flag {
- name: "a11y_character_in_window_api"
- namespace: "accessibility"
- description: "Enables new extra data key for an AccessibilityService to request character bounds in unmagnified window coordinates."
- bug: "375429616"
- is_exported: true
-}
-
-flag {
- namespace: "accessibility"
name: "allow_shortcut_chooser_on_lockscreen"
+ namespace: "accessibility"
description: "Allows the a11y shortcut disambig dialog to appear on the lockscreen"
bug: "303871725"
}
flag {
- namespace: "accessibility"
name: "braille_display_hid"
+ namespace: "accessibility"
is_exported: true
description: "Enables new APIs for an AccessibilityService to communicate with a HID Braille display"
bug: "303522222"
@@ -72,47 +72,62 @@ flag {
}
flag {
- namespace: "accessibility"
name: "collection_info_item_counts"
+ namespace: "accessibility"
is_exported: true
description: "Fields for total items and the number of important for accessibility items in a collection"
bug: "302376158"
}
flag {
- namespace: "accessibility"
name: "copy_events_for_gesture_detection"
+ namespace: "accessibility"
description: "Creates copies of MotionEvents and GestureEvents in GestureMatcher"
bug: "280130713"
}
flag {
- namespace: "accessibility"
name: "deprecate_accessibility_announcement_apis"
+ namespace: "accessibility"
description: "Controls the deprecation of platform APIs related to disruptive accessibility announcements"
bug: "376727542"
is_exported: true
}
flag {
- namespace: "accessibility"
name: "deprecate_ani_label_for_apis"
+ namespace: "accessibility"
description: "Controls the deprecation of AccessibilityNodeInfo labelFor apis"
bug: "333783827"
is_exported: true
}
flag {
+ name: "enable_system_pinch_zoom_gesture"
namespace: "accessibility"
+ description: "Feature flag for system pinch zoom gesture detector and related opt-out apis"
+ bug: "283323770"
+}
+
+flag {
+ name: "enable_type_window_control"
+ namespace: "accessibility"
+ is_exported: true
+ description: "adds new TYPE_WINDOW_CONTROL to AccessibilityWindowInfo for detecting Window Decorations"
+ bug: "320445550"
+}
+
+flag {
name: "flash_notification_system_api"
+ namespace: "accessibility"
is_exported: true
description: "Makes flash notification APIs as system APIs for calling from mainline module"
bug: "303131332"
}
flag {
- namespace: "accessibility"
name: "focus_rect_min_size"
+ namespace: "accessibility"
description: "Ensures the a11y focus rect is big enough to be drawn as visible"
bug: "368667566"
metadata {
@@ -121,102 +136,101 @@ flag {
}
flag {
- namespace: "accessibility"
name: "force_invert_color"
+ namespace: "accessibility"
description: "Enable force force-dark for smart inversion and dark theme everywhere"
bug: "282821643"
}
flag {
- name: "migrate_enable_shortcuts"
+ name: "global_action_media_play_pause"
namespace: "accessibility"
- description: "Refactors deprecated code to use AccessibilityManager#enableShortcutsForTargets."
- bug: "332006721"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- name: "motion_event_observing"
+ description: "Allow AccessibilityService to perform GLOBAL_ACTION_MEDIA_PLAY_PAUSE"
+ bug: "334954140"
is_exported: true
- namespace: "accessibility"
- description: "Allows accessibility services to intercept but not consume motion events from specified sources."
- bug: "297595990"
}
flag {
- namespace: "accessibility"
name: "global_action_menu"
+ namespace: "accessibility"
description: "Allow AccessibilityService to perform GLOBAL_ACTION_MENU"
bug: "334954140"
is_exported: true
}
flag {
+ name: "granular_scrolling"
namespace: "accessibility"
- name: "global_action_media_play_pause"
- description: "Allow AccessibilityService to perform GLOBAL_ACTION_MEDIA_PLAY_PAUSE"
- bug: "334954140"
is_exported: true
+ description: "Allow the use of granular scrolling. This allows scrollable nodes to scroll by increments other than a full screen"
+ bug: "302376158"
}
flag {
+ name: "indeterminate_range_info"
namespace: "accessibility"
- name: "granular_scrolling"
+ description: "Creates a way to create an INDETERMINATE RangeInfo"
+ bug: "376108874"
is_exported: true
- description: "Allow the use of granular scrolling. This allows scrollable nodes to scroll by increments other than a full screen"
- bug: "302376158"
}
flag {
+ name: "migrate_enable_shortcuts"
namespace: "accessibility"
- name: "reduce_window_content_changed_event_throttle"
- description: "Reduces the throttle of AccessibilityEvent of TYPE_WINDOW_CONTENT_CHANGED"
- bug: "277305460"
+ description: "Refactors deprecated code to use AccessibilityManager#enableShortcutsForTargets."
+ bug: "332006721"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
+ name: "motion_event_observing"
+ is_exported: true
namespace: "accessibility"
- name: "remove_child_hover_check_for_touch_exploration"
- description: "Remove a check for a hovered child that prevents touch events from being delegated to non-direct descendants"
- bug: "304770837"
+ description: "Allows accessibility services to intercept but not consume motion events from specified sources."
+ bug: "297595990"
}
flag {
- name: "skip_accessibility_warning_dialog_for_trusted_services"
+ name: "prevent_a11y_nontool_from_injecting_into_sensitive_views"
namespace: "accessibility"
- description: "Skips showing the accessibility warning dialog for trusted services."
- bug: "303511250"
+ description: "Prevents injected gestures from A11yServices without isAccessibilityTool=true from reaching AccessibilityDataSensitive UI elements"
+ bug: "284180538"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
+ name: "prevent_leaking_viewrootimpl"
namespace: "accessibility"
- name: "enable_type_window_control"
- is_exported: true
- description: "adds new TYPE_WINDOW_CONTROL to AccessibilityWindowInfo for detecting Window Decorations"
- bug: "320445550"
+ description: "Clear pending messages and callbacks of the handler in AccessibilityInteractionController when the ViewRootImpl is detached from Window to prevent leaking ViewRootImpl"
+ bug: "320701910"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
+ name: "reduce_window_content_changed_event_throttle"
namespace: "accessibility"
- name: "update_always_on_a11y_service"
- description: "Updates the Always-On A11yService state when the user changes the enablement of the shortcut."
- bug: "298869916"
+ description: "Reduces the throttle of AccessibilityEvent of TYPE_WINDOW_CONTENT_CHANGED"
+ bug: "277305460"
}
flag {
- name: "enable_system_pinch_zoom_gesture"
+ name: "remove_child_hover_check_for_touch_exploration"
namespace: "accessibility"
- description: "Feature flag for system pinch zoom gesture detector and related opt-out apis"
- bug: "283323770"
+ description: "Remove a check for a hovered child that prevents touch events from being delegated to non-direct descendants"
+ bug: "304770837"
}
flag {
- name: "prevent_leaking_viewrootimpl"
+ name: "restore_a11y_secure_settings_on_hsum_device"
namespace: "accessibility"
- description: "Clear pending messages and callbacks of the handler in AccessibilityInteractionController when the ViewRootImpl is detached from Window to prevent leaking ViewRootImpl"
- bug: "320701910"
+ description: "Grab the a11y settings and send the settings restored broadcast for current visible foreground user"
+ bug: "381294327"
metadata {
purpose: PURPOSE_BUGFIX
}
@@ -233,13 +247,10 @@ flag {
}
flag {
- name: "restore_a11y_secure_settings_on_hsum_device"
+ name: "skip_accessibility_warning_dialog_for_trusted_services"
namespace: "accessibility"
- description: "Grab the a11y settings and send the settings restored broadcast for current visible foreground user"
- bug: "381294327"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
+ description: "Skips showing the accessibility warning dialog for trusted services."
+ bug: "303511250"
}
flag {
@@ -274,6 +285,13 @@ flag {
}
flag {
+ namespace: "accessibility"
+ name: "update_always_on_a11y_service"
+ description: "Updates the Always-On A11yService state when the user changes the enablement of the shortcut."
+ bug: "298869916"
+}
+
+flag {
name: "warning_use_default_dialog_type"
namespace: "accessibility"
description: "Uses the default type for the A11yService warning dialog, instead of SYSTEM_ALERT_DIALOG"
@@ -282,11 +300,3 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
-
-flag {
- name: "indeterminate_range_info"
- namespace: "accessibility"
- description: "Creates a way to create an INDETERMINATE RangeInfo"
- bug: "376108874"
- is_exported: true
-}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index fda57d6bb986..e422fef6c22c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -31,6 +31,7 @@ import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemClock;
import android.provider.Settings;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -71,9 +72,9 @@ import java.util.StringJoiner;
*/
class AccessibilityInputFilter extends InputFilter implements EventStreamTransformation {
- private static final String TAG = AccessibilityInputFilter.class.getSimpleName();
+ private static final String TAG = "A11yInputFilter";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/**
* Flag for enabling the screen magnification feature.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index a3fe9ec5ea22..6cba3633b940 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -554,7 +554,8 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
if (motionEventInjector != null
&& mWindowManagerService.isTouchOrFaketouchDevice()) {
motionEventInjector.injectEvents(
- gestureSteps.getList(), mClient, sequence, displayId);
+ gestureSteps.getList(), mClient, sequence, displayId,
+ mAccessibilityServiceInfo.isAccessibilityTool());
} else {
try {
if (svcClientTracingEnabled()) {
diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
index 5cbd1a208ce1..b2169535d0de 100644
--- a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
+++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
@@ -105,12 +105,14 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement
* either complete or cancelled.
*/
public void injectEvents(List<GestureStep> gestureSteps,
- IAccessibilityServiceClient serviceInterface, int sequence, int displayId) {
+ IAccessibilityServiceClient serviceInterface, int sequence, int displayId,
+ boolean fromAccessibilityTool) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = gestureSteps;
args.arg2 = serviceInterface;
args.argi1 = sequence;
args.argi2 = displayId;
+ args.argi3 = fromAccessibilityTool ? 1 : 0;
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_INJECT_EVENTS, args));
}
@@ -132,9 +134,11 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement
return;
}
cancelAnyPendingInjectedEvents();
- // Indicate that the input event is injected from accessibility, to let applications
- // distinguish it from events injected by other means.
- policyFlags |= WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY;
+ if (!android.view.accessibility.Flags.preventA11yNontoolFromInjectingIntoSensitiveViews()) {
+ // Indicate that the input event is injected from accessibility, to let applications
+ // distinguish it from events injected by other means.
+ policyFlags |= WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY;
+ }
sendMotionEventToNext(event, rawEvent, policyFlags);
}
@@ -159,8 +163,12 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement
public boolean handleMessage(Message message) {
if (message.what == MESSAGE_INJECT_EVENTS) {
SomeArgs args = (SomeArgs) message.obj;
- injectEventsMainThread((List<GestureStep>) args.arg1,
- (IAccessibilityServiceClient) args.arg2, args.argi1, args.argi2);
+ injectEventsMainThread(
+ /*gestureSteps=*/(List<GestureStep>) args.arg1,
+ /*serviceInterface=*/(IAccessibilityServiceClient) args.arg2,
+ /*sequence=*/args.argi1,
+ /*displayId=*/args.argi2,
+ /*fromAccessibilityTool=*/args.argi3 == 1);
args.recycle();
return true;
}
@@ -169,9 +177,15 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement
return false;
}
MotionEvent motionEvent = (MotionEvent) message.obj;
- sendMotionEventToNext(motionEvent, motionEvent,
- WindowManagerPolicyConstants.FLAG_PASS_TO_USER
- | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY);
+ int policyFlags = WindowManagerPolicyConstants.FLAG_PASS_TO_USER
+ | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY;
+ if (android.view.accessibility.Flags.preventA11yNontoolFromInjectingIntoSensitiveViews()) {
+ boolean fromAccessibilityTool = message.arg2 == 1;
+ if (fromAccessibilityTool) {
+ policyFlags |= WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL;
+ }
+ }
+ sendMotionEventToNext(motionEvent, motionEvent, policyFlags);
boolean isEndOfSequence = message.arg1 != 0;
if (isEndOfSequence) {
notifyService(mServiceInterfaceForCurrentGesture, mSequencesInProgress.get(0), true);
@@ -181,7 +195,8 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement
}
private void injectEventsMainThread(List<GestureStep> gestureSteps,
- IAccessibilityServiceClient serviceInterface, int sequence, int displayId) {
+ IAccessibilityServiceClient serviceInterface, int sequence, int displayId,
+ boolean fromAccessibilityTool) {
if (mIsDestroyed) {
try {
serviceInterface.onPerformGestureResult(sequence, false);
@@ -228,7 +243,8 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement
event.setDisplayId(displayId);
int isEndOfSequence = (i == events.size() - 1) ? 1 : 0;
Message message = mHandler.obtainMessage(
- MESSAGE_SEND_MOTION_EVENT, isEndOfSequence, 0, event);
+ MESSAGE_SEND_MOTION_EVENT, isEndOfSequence,
+ fromAccessibilityTool ? 1 : 0, event);
mLastScheduledEventTime = event.getEventTime();
mHandler.sendMessageDelayed(message, Math.max(0, event.getEventTime() - currentTime));
}
@@ -322,9 +338,16 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement
long now = SystemClock.uptimeMillis();
MotionEvent cancelEvent =
obtainMotionEvent(now, now, MotionEvent.ACTION_CANCEL, getLastTouchPoints(), 1);
- sendMotionEventToNext(cancelEvent, cancelEvent,
- WindowManagerPolicyConstants.FLAG_PASS_TO_USER
- | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY);
+ int policyFlags = WindowManagerPolicyConstants.FLAG_PASS_TO_USER
+ | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY;
+ if (android.view.accessibility.Flags
+ .preventA11yNontoolFromInjectingIntoSensitiveViews()) {
+ // ACTION_CANCEL events are internal system details for event stream state
+ // management and not used for performing new actions, so always treat them as
+ // originating from an accessibility tool.
+ policyFlags |= WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL;
+ }
+ sendMotionEventToNext(cancelEvent, cancelEvent, policyFlags);
mOpenGesturesInProgress.put(source, false);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index d4f2dcc24af6..5d94e7274a1f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -250,9 +250,26 @@ public class AccessibilityServiceConnectionTest {
}
@Test
- public void sendGesture_touchableDevice_injectEvents()
- throws RemoteException {
+ public void sendGesture_touchableDevice_injectEvents_fromAccessibilityTool() {
+ when(mMockWindowManagerInternal.isTouchOrFaketouchDevice()).thenReturn(true);
+ when(mServiceInfo.isAccessibilityTool()).thenReturn(true);
+ setServiceBinding(COMPONENT_NAME);
+ mConnection.bindLocked();
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+
+ ParceledListSlice parceledListSlice = mock(ParceledListSlice.class);
+ List<GestureDescription.GestureStep> gestureSteps = mock(List.class);
+ when(parceledListSlice.getList()).thenReturn(gestureSteps);
+ mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY);
+
+ verify(mMockMotionEventInjector).injectEvents(gestureSteps, mMockServiceClient, 0,
+ Display.DEFAULT_DISPLAY, true);
+ }
+
+ @Test
+ public void sendGesture_touchableDevice_injectEvents_fromNonTool() {
when(mMockWindowManagerInternal.isTouchOrFaketouchDevice()).thenReturn(true);
+ when(mServiceInfo.isAccessibilityTool()).thenReturn(false);
setServiceBinding(COMPONENT_NAME);
mConnection.bindLocked();
mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
@@ -263,13 +280,14 @@ public class AccessibilityServiceConnectionTest {
mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY);
verify(mMockMotionEventInjector).injectEvents(gestureSteps, mMockServiceClient, 0,
- Display.DEFAULT_DISPLAY);
+ Display.DEFAULT_DISPLAY, false);
}
@Test
public void sendGesture_untouchableDevice_performGestureResultFailed()
throws RemoteException {
when(mMockWindowManagerInternal.isTouchOrFaketouchDevice()).thenReturn(false);
+ when(mServiceInfo.isAccessibilityTool()).thenReturn(true);
setServiceBinding(COMPONENT_NAME);
mConnection.bindLocked();
mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
@@ -280,7 +298,7 @@ public class AccessibilityServiceConnectionTest {
mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY);
verify(mMockMotionEventInjector, never()).injectEvents(gestureSteps, mMockServiceClient, 0,
- Display.DEFAULT_DISPLAY);
+ Display.DEFAULT_DISPLAY, true);
verify(mMockServiceClient).onPerformGestureResult(0, false);
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
index 233caf9c7761..d2d8c682ed90 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
@@ -20,8 +20,7 @@ import static android.view.KeyCharacterMap.VIRTUAL_KEYBOARD;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_HOVER_MOVE;
import static android.view.MotionEvent.ACTION_UP;
-import static android.view.WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY;
-import static android.view.WindowManagerPolicyConstants.FLAG_PASS_TO_USER;
+import static android.view.accessibility.Flags.FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.anyOf;
@@ -48,10 +47,14 @@ import android.graphics.Point;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.view.Display;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.WindowManagerPolicyConstants;
import android.view.accessibility.AccessibilityEvent;
import androidx.test.runner.AndroidJUnit4;
@@ -64,6 +67,7 @@ import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -77,7 +81,7 @@ import java.util.List;
*/
@RunWith(AndroidJUnit4.class)
public class MotionEventInjectorTest {
- private static final String LOG_TAG = "MotionEventInjectorTest";
+
private static final Matcher<MotionEvent> IS_ACTION_DOWN =
new MotionEventActionMatcher(ACTION_DOWN);
private static final Matcher<MotionEvent> IS_ACTION_POINTER_DOWN =
@@ -120,6 +124,9 @@ public class MotionEventInjectorTest {
private static final float POINTER_SIZE = 1;
private static final int METASTATE = 0;
+ @Rule
+ public SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
MotionEventInjector mMotionEventInjector;
IAccessibilityServiceClient mServiceInterface;
AccessibilityTraceManager mTrace;
@@ -201,7 +208,8 @@ public class MotionEventInjectorTest {
verifyNoMoreInteractions(next);
mMessageCapturingHandler.sendOneMessage(); // Send a motion event
- final int expectedFlags = FLAG_PASS_TO_USER | FLAG_INJECTED_FROM_ACCESSIBILITY;
+ final int expectedFlags = WindowManagerPolicyConstants.FLAG_PASS_TO_USER
+ | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY;
verify(next).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), eq(expectedFlags));
verify(next).onMotionEvent(argThat(mIsLineStart), argThat(mIsLineStart), eq(expectedFlags));
verifyNoMoreInteractions(next);
@@ -227,6 +235,21 @@ public class MotionEventInjectorTest {
}
@Test
+ @EnableFlags(FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS)
+ public void testInjectEvents_fromAccessibilityTool_providesToolPolicyFlag() {
+ EventStreamTransformation next = attachMockNext(mMotionEventInjector);
+ injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE,
+ /*fromAccessibilityTool=*/true);
+
+ mMessageCapturingHandler.sendOneMessage(); // Send a motion event
+ verify(next).onMotionEvent(
+ argThat(mIsLineStart), argThat(mIsLineStart),
+ eq(WindowManagerPolicyConstants.FLAG_PASS_TO_USER
+ | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY
+ | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL));
+ }
+
+ @Test
public void testInjectEvents_gestureWithTooManyPoints_shouldNotCrash() throws Exception {
int tooManyPointsCount = 20;
TouchPoint[] startTouchPoints = new TouchPoint[tooManyPointsCount];
@@ -251,14 +274,28 @@ public class MotionEventInjectorTest {
}
@Test
- public void testRegularEvent_afterGestureComplete_shouldPassToNext() {
+ @DisableFlags(FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS)
+ public void testRegularEvent_afterGestureComplete_shouldPassToNext_withFlagInjectedFromA11y() {
+ EventStreamTransformation next = attachMockNext(mMotionEventInjector);
+ injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
+ mMessageCapturingHandler.sendAllMessages(); // Send all motion events
+ reset(next);
+ mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0);
+ verify(next).onMotionEvent(argThat(mIsClickDown), argThat(mIsClickDown),
+ eq(WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY));
+ }
+
+ @Test
+ @EnableFlags(FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS)
+ public void testRegularEvent_afterGestureComplete_shouldPassToNext_withNoPolicyFlagChanges() {
EventStreamTransformation next = attachMockNext(mMotionEventInjector);
injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
mMessageCapturingHandler.sendAllMessages(); // Send all motion events
reset(next);
mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0);
verify(next).onMotionEvent(argThat(mIsClickDown), argThat(mIsClickDown),
- eq(FLAG_INJECTED_FROM_ACCESSIBILITY));
+ // The regular event passing through the filter should have no policy flag changes
+ eq(0));
}
@Test
@@ -275,7 +312,8 @@ public class MotionEventInjectorTest {
mMessageCapturingHandler.sendOneMessage(); // Send a motion event
verify(next).onMotionEvent(
argThat(mIsLineStart), argThat(mIsLineStart),
- eq(FLAG_PASS_TO_USER | FLAG_INJECTED_FROM_ACCESSIBILITY));
+ eq(WindowManagerPolicyConstants.FLAG_PASS_TO_USER
+ | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY));
}
@Test
@@ -307,10 +345,12 @@ public class MotionEventInjectorTest {
mMessageCapturingHandler.sendOneMessage(); // Send a motion event
verify(next).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(),
- eq(FLAG_PASS_TO_USER | FLAG_INJECTED_FROM_ACCESSIBILITY));
+ eq(WindowManagerPolicyConstants.FLAG_PASS_TO_USER
+ | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY));
verify(next).onMotionEvent(
argThat(mIsLineStart), argThat(mIsLineStart),
- eq(FLAG_PASS_TO_USER | FLAG_INJECTED_FROM_ACCESSIBILITY));
+ eq(WindowManagerPolicyConstants.FLAG_PASS_TO_USER
+ | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY));
}
@Test
@@ -731,8 +771,14 @@ public class MotionEventInjectorTest {
private void injectEventsSync(List<GestureStep> gestureSteps,
IAccessibilityServiceClient serviceInterface, int sequence) {
+ injectEventsSync(gestureSteps, serviceInterface, sequence, false);
+ }
+
+ private void injectEventsSync(List<GestureStep> gestureSteps,
+ IAccessibilityServiceClient serviceInterface, int sequence,
+ boolean fromAccessibilityTool) {
mMotionEventInjector.injectEvents(gestureSteps, serviceInterface, sequence,
- Display.DEFAULT_DISPLAY);
+ Display.DEFAULT_DISPLAY, fromAccessibilityTool);
// Dispatch the message sent by the injector. Our simple handler doesn't guarantee stuff
// happens in order.
mMessageCapturingHandler.sendLastMessage();