1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.accessibility;
18 
19 import static android.view.InputDevice.SOURCE_CLASS_POINTER;
20 import static android.view.MotionEvent.ACTION_SCROLL;
21 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
22 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
23 
24 import android.accessibilityservice.AccessibilityTrace;
25 import android.annotation.MainThread;
26 import android.annotation.NonNull;
27 import android.content.Context;
28 import android.graphics.Region;
29 import android.os.PowerManager;
30 import android.os.SystemClock;
31 import android.provider.Settings;
32 import android.util.Slog;
33 import android.util.SparseArray;
34 import android.util.SparseBooleanArray;
35 import android.view.Display;
36 import android.view.InputDevice;
37 import android.view.InputEvent;
38 import android.view.InputFilter;
39 import android.view.KeyEvent;
40 import android.view.MotionEvent;
41 import android.view.MotionEvent.PointerCoords;
42 import android.view.MotionEvent.PointerProperties;
43 import android.view.accessibility.AccessibilityEvent;
44 
45 import com.android.server.LocalServices;
46 import com.android.server.accessibility.gestures.TouchExplorer;
47 import com.android.server.accessibility.magnification.FullScreenMagnificationGestureHandler;
48 import com.android.server.accessibility.magnification.FullScreenMagnificationVibrationHelper;
49 import com.android.server.accessibility.magnification.MagnificationGestureHandler;
50 import com.android.server.accessibility.magnification.WindowMagnificationGestureHandler;
51 import com.android.server.accessibility.magnification.WindowMagnificationPromptController;
52 import com.android.server.policy.WindowManagerPolicy;
53 
54 import java.io.FileDescriptor;
55 import java.io.PrintWriter;
56 import java.util.ArrayList;
57 import java.util.StringJoiner;
58 
59 /**
60  * This class is an input filter for implementing accessibility features such
61  * as display magnification and explore by touch.
62  *
63  * NOTE: This class has to be created and poked only from the main thread.
64  */
65 @SuppressWarnings("MissingPermissionAnnotation")
66 class AccessibilityInputFilter extends InputFilter implements EventStreamTransformation {
67 
68     private static final String TAG = AccessibilityInputFilter.class.getSimpleName();
69 
70     private static final boolean DEBUG = false;
71 
72     /**
73      * Flag for enabling the screen magnification feature.
74      *
75      * @see #setUserAndEnabledFeatures(int, int)
76      */
77     static final int FLAG_FEATURE_MAGNIFICATION_SINGLE_FINGER_TRIPLE_TAP = 0x00000001;
78 
79     /**
80      * Flag for enabling the touch exploration feature.
81      *
82      * @see #setUserAndEnabledFeatures(int, int)
83      */
84     static final int FLAG_FEATURE_TOUCH_EXPLORATION = 0x00000002;
85 
86     /**
87      * Flag for enabling the filtering key events feature.
88      *
89      * @see #setUserAndEnabledFeatures(int, int)
90      */
91     static final int FLAG_FEATURE_FILTER_KEY_EVENTS = 0x00000004;
92 
93     /**
94      * Flag for enabling "Automatically click on mouse stop" feature.
95      *
96      * @see #setUserAndEnabledFeatures(int, int)
97      */
98     static final int FLAG_FEATURE_AUTOCLICK = 0x00000008;
99 
100     /**
101      * Flag for enabling motion event injection.
102      *
103      * @see #setUserAndEnabledFeatures(int, int)
104      */
105     static final int FLAG_FEATURE_INJECT_MOTION_EVENTS = 0x00000010;
106 
107     /**
108      * Flag for enabling the feature to control the screen magnifier. If
109      * {@link #FLAG_FEATURE_MAGNIFICATION_SINGLE_FINGER_TRIPLE_TAP} is set this flag is ignored
110      * as the screen magnifier feature performs a super set of the work
111      * performed by this feature.
112      *
113      * @see #setUserAndEnabledFeatures(int, int)
114      */
115     static final int FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER = 0x00000020;
116 
117     /**
118      * Flag for enabling the feature to trigger the screen magnifier
119      * from another on-device interaction.
120      */
121     static final int FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER = 0x00000040;
122 
123     /**
124      * Flag for dispatching double tap and double tap and hold to the service.
125      *
126      * @see #setUserAndEnabledFeatures(int, int)
127      */
128     static final int FLAG_SERVICE_HANDLES_DOUBLE_TAP = 0x00000080;
129 
130 /**
131      * Flag for enabling multi-finger gestures.
132      *
133      * @see #setUserAndEnabledFeatures(int, int)
134      */
135     static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x00000100;
136 
137     /**
138      * Flag for enabling two-finger passthrough when multi-finger gestures are enabled.
139      *
140      * @see #setUserAndEnabledFeatures(int, int)
141      */
142     static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 0x00000200;
143 
144     /**
145      * Flag for including motion events when dispatching a gesture.
146      *
147      * @see #setUserAndEnabledFeatures(int, int)
148      */
149     static final int FLAG_SEND_MOTION_EVENTS = 0x00000400;
150 
151     /** Flag for intercepting generic motion events. */
152     static final int FLAG_FEATURE_INTERCEPT_GENERIC_MOTION_EVENTS = 0x00000800;
153 
154     /**
155      * Flag for enabling the two-finger triple-tap magnification feature.
156      *
157      * @see #setUserAndEnabledFeatures(int, int)
158      */
159     static final int FLAG_FEATURE_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP = 0x00001000;
160 
161     static final int FEATURES_AFFECTING_MOTION_EVENTS =
162             FLAG_FEATURE_INJECT_MOTION_EVENTS
163                     | FLAG_FEATURE_AUTOCLICK
164                     | FLAG_FEATURE_TOUCH_EXPLORATION
165                     | FLAG_FEATURE_MAGNIFICATION_SINGLE_FINGER_TRIPLE_TAP
166                     | FLAG_FEATURE_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP
167                     | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER
168                     | FLAG_SERVICE_HANDLES_DOUBLE_TAP
169                     | FLAG_REQUEST_MULTI_FINGER_GESTURES
170                     | FLAG_REQUEST_2_FINGER_PASSTHROUGH
171                     | FLAG_FEATURE_INTERCEPT_GENERIC_MOTION_EVENTS;
172 
173     private final Context mContext;
174 
175     private final PowerManager mPm;
176 
177     private final AccessibilityManagerService mAms;
178 
179     private final SparseArray<EventStreamTransformation> mEventHandler;
180 
181     private final SparseArray<TouchExplorer> mTouchExplorer = new SparseArray<>(0);
182 
183     private final SparseArray<MagnificationGestureHandler> mMagnificationGestureHandler =
184             new SparseArray<>(0);
185 
186     private final SparseArray<MotionEventInjector> mMotionEventInjectors = new SparseArray<>(0);
187 
188     private AutoclickController mAutoclickController;
189 
190     private KeyboardInterceptor mKeyboardInterceptor;
191 
192     private boolean mInstalled;
193 
194     private int mUserId;
195 
196     private int mEnabledFeatures;
197 
198     // Display-specific features
199     private SparseArray<Boolean> mServiceDetectsGestures = new SparseArray<>();
200     private final SparseArray<EventStreamState> mMouseStreamStates = new SparseArray<>(0);
201 
202     private final SparseArray<EventStreamState> mTouchScreenStreamStates = new SparseArray<>(0);
203 
204     // State tracking for generic MotionEvents is display-agnostic so we only need one.
205     private GenericMotionEventStreamState mGenericMotionEventStreamState;
206     private int mCombinedGenericMotionEventSources = 0;
207     private int mCombinedMotionEventObservedSources = 0;
208 
209     private EventStreamState mKeyboardStreamState;
210 
211     /**
212      * The last MotionEvent emitted from the input device that's currently active. This is used to
213      * keep track of which input device is currently active, and also to generate the cancel event
214      * if a new device becomes active.
215      */
216     private MotionEvent mLastActiveDeviceMotionEvent = null;
217 
cancelMotion(MotionEvent event)218     private static MotionEvent cancelMotion(MotionEvent event) {
219         if (event.getActionMasked() == MotionEvent.ACTION_CANCEL
220                 || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT
221                 || event.getActionMasked() == MotionEvent.ACTION_UP) {
222             throw new IllegalArgumentException("Can't cancel " + event);
223         }
224         final int action;
225         if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
226                 || event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
227             action = MotionEvent.ACTION_HOVER_EXIT;
228         } else {
229             action = MotionEvent.ACTION_CANCEL;
230         }
231 
232         final int pointerCount;
233         if (event.getActionMasked() == MotionEvent.ACTION_POINTER_UP) {
234             pointerCount = event.getPointerCount() - 1;
235         } else {
236             pointerCount = event.getPointerCount();
237         }
238         final PointerProperties[] properties = new PointerProperties[pointerCount];
239         final PointerCoords[] coords = new PointerCoords[pointerCount];
240         int newPointerIndex = 0;
241         for (int i = 0; i < event.getPointerCount(); i++) {
242             if (event.getActionMasked() == MotionEvent.ACTION_POINTER_UP) {
243                 if (event.getActionIndex() == i) {
244                     // Skip the pointer that's going away
245                     continue;
246                 }
247             }
248             final PointerCoords c = new PointerCoords();
249             c.x = event.getX(i);
250             c.y = event.getY(i);
251             coords[newPointerIndex] = c;
252             final PointerProperties p = new PointerProperties();
253             p.id = event.getPointerId(i);
254             p.toolType = event.getToolType(i);
255             properties[newPointerIndex] = p;
256             newPointerIndex++;
257         }
258 
259         return MotionEvent.obtain(event.getDownTime(), SystemClock.uptimeMillis(), action,
260                 pointerCount, properties, coords,
261                 event.getMetaState(), event.getButtonState(),
262                 event.getXPrecision(), event.getYPrecision(), event.getDeviceId(),
263                 event.getEdgeFlags(), event.getSource(), event.getDisplayId(), event.getFlags(),
264                 event.getClassification());
265     }
266 
AccessibilityInputFilter(Context context, AccessibilityManagerService service)267     AccessibilityInputFilter(Context context, AccessibilityManagerService service) {
268         this(context, service, new SparseArray<>(0));
269     }
270 
AccessibilityInputFilter(Context context, AccessibilityManagerService service, SparseArray<EventStreamTransformation> eventHandler)271     AccessibilityInputFilter(Context context, AccessibilityManagerService service,
272             SparseArray<EventStreamTransformation> eventHandler) {
273         super(context.getMainLooper());
274         mContext = context;
275         mAms = service;
276         mPm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
277         mEventHandler = eventHandler;
278     }
279 
280     @Override
onInstalled()281     public void onInstalled() {
282         if (DEBUG) {
283             Slog.d(TAG, "Accessibility input filter installed.");
284         }
285         mInstalled = true;
286         disableFeatures();
287         enableFeatures();
288         mAms.onInputFilterInstalled(true);
289         super.onInstalled();
290     }
291 
292     @Override
onUninstalled()293     public void onUninstalled() {
294         if (DEBUG) {
295             Slog.d(TAG, "Accessibility input filter uninstalled.");
296         }
297         mInstalled = false;
298         disableFeatures();
299         mAms.onInputFilterInstalled(false);
300         super.onUninstalled();
301     }
302 
onDisplayAdded(@onNull Display display)303     void onDisplayAdded(@NonNull Display display) {
304         enableFeaturesForDisplayIfInstalled(display);
305 
306     }
307 
onDisplayRemoved(int displayId)308     void onDisplayRemoved(int displayId) {
309         disableFeaturesForDisplayIfInstalled(displayId);
310     }
311 
312     @Override
onInputEvent(InputEvent event, int policyFlags)313     public void onInputEvent(InputEvent event, int policyFlags) {
314         if (DEBUG) {
315             Slog.d(TAG, "Received event: " + event + ", policyFlags=0x"
316                     + Integer.toHexString(policyFlags));
317         }
318         if (mAms.getTraceManager().isA11yTracingEnabledForTypes(
319                 AccessibilityTrace.FLAGS_INPUT_FILTER)) {
320             mAms.getTraceManager().logTrace(TAG + ".onInputEvent",
321                     AccessibilityTrace.FLAGS_INPUT_FILTER,
322                     "event=" + event + ";policyFlags=" + policyFlags);
323         }
324         if (Flags.handleMultiDeviceInput()) {
325             if (!shouldProcessMultiDeviceEvent(event, policyFlags)) {
326                 // We are only allowing a single device to be active at a time.
327                 return;
328             }
329         }
330 
331         onInputEventInternal(event, policyFlags);
332     }
333 
onInputEventInternal(InputEvent event, int policyFlags)334     private void onInputEventInternal(InputEvent event, int policyFlags) {
335         if (mEventHandler.size() == 0) {
336             if (DEBUG) Slog.d(TAG, "No mEventHandler for event " + event);
337             super.onInputEvent(event, policyFlags);
338             return;
339         }
340 
341         EventStreamState state = getEventStreamState(event);
342         if (state == null) {
343             super.onInputEvent(event, policyFlags);
344             return;
345         }
346 
347         final int eventSource = event.getSource();
348         final int displayId = event.getDisplayId();
349         if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) == 0) {
350             if (!Flags.doNotResetKeyEventState()) {
351                 state.reset();
352                 clearEventStreamHandler(displayId, eventSource);
353             }
354             if (DEBUG) {
355                 Slog.d(TAG, "Not processing event " + event);
356             }
357             super.onInputEvent(event, policyFlags);
358             return;
359         }
360 
361         if (state.updateInputSource(event.getSource())) {
362             clearEventStreamHandler(displayId, eventSource);
363         }
364 
365         if (!state.inputSourceValid()) {
366             super.onInputEvent(event, policyFlags);
367             return;
368         }
369 
370         if (event instanceof MotionEvent) {
371             if ((mEnabledFeatures & FEATURES_AFFECTING_MOTION_EVENTS) != 0) {
372                 MotionEvent motionEvent = (MotionEvent) event;
373                 processMotionEvent(state, motionEvent, policyFlags);
374                 return;
375             } else {
376                 super.onInputEvent(event, policyFlags);
377             }
378         } else if (event instanceof KeyEvent) {
379             KeyEvent keyEvent = (KeyEvent) event;
380             processKeyEvent(state, keyEvent, policyFlags);
381         }
382     }
383 
384     /**
385      * Gets current event stream state associated with an input event.
386      * @return The event stream state that should be used for the event. Null if the event should
387      *     not be handled by #AccessibilityInputFilter.
388      */
getEventStreamState(InputEvent event)389     private EventStreamState getEventStreamState(InputEvent event) {
390         if (event instanceof MotionEvent) {
391             final int displayId = event.getDisplayId();
392             if (mGenericMotionEventStreamState == null) {
393                 mGenericMotionEventStreamState = new GenericMotionEventStreamState();
394             }
395 
396             if (mGenericMotionEventStreamState.shouldProcessMotionEvent((MotionEvent) event)) {
397                 return mGenericMotionEventStreamState;
398             }
399             if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) {
400                 EventStreamState touchScreenStreamState = mTouchScreenStreamStates.get(displayId);
401                 if (touchScreenStreamState == null) {
402                     touchScreenStreamState = new TouchScreenEventStreamState();
403                     mTouchScreenStreamStates.put(displayId, touchScreenStreamState);
404                 }
405                 return touchScreenStreamState;
406             }
407             if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
408                 EventStreamState mouseStreamState = mMouseStreamStates.get(displayId);
409                 if (mouseStreamState == null) {
410                     mouseStreamState = new MouseEventStreamState();
411                     mMouseStreamStates.put(displayId, mouseStreamState);
412                 }
413                 return mouseStreamState;
414             }
415         } else if (event instanceof KeyEvent) {
416             if (event.isFromSource(InputDevice.SOURCE_KEYBOARD)) {
417                 if (mKeyboardStreamState == null) {
418                     mKeyboardStreamState = new KeyboardEventStreamState();
419                 }
420                 return mKeyboardStreamState;
421             }
422         }
423         return null;
424     }
425 
clearEventStreamHandler(int displayId, int eventSource)426     private void clearEventStreamHandler(int displayId, int eventSource) {
427         final EventStreamTransformation eventHandler = mEventHandler.get(displayId);
428         if (eventHandler != null) {
429             eventHandler.clearEvents(eventSource);
430         }
431     }
432 
shouldProcessMultiDeviceEvent(InputEvent event, int policyFlags)433     boolean shouldProcessMultiDeviceEvent(InputEvent event, int policyFlags) {
434         if (event instanceof MotionEvent motion) {
435             if (!motion.isFromSource(SOURCE_CLASS_POINTER) || motion.getAction() == ACTION_SCROLL) {
436                 // Non-pointer events are focus-dispatched and don't require special logic.
437                 // Scroll events are stand-alone and therefore can be considered to not be part of
438                 // a stream.
439                 return true;
440             }
441             // Only allow 1 device to be sending motion events at a time
442             // If the event is from an active device, let it through.
443             // If the event is not from an active device, only let it through if it starts a new
444             // gesture like ACTION_DOWN or ACTION_HOVER_ENTER
445             final boolean eventIsFromCurrentDevice = mLastActiveDeviceMotionEvent != null
446                     && mLastActiveDeviceMotionEvent.getDeviceId() == motion.getDeviceId();
447             final int actionMasked = motion.getActionMasked();
448             switch (actionMasked) {
449                 case MotionEvent.ACTION_DOWN:
450                 case MotionEvent.ACTION_HOVER_ENTER:
451                 case MotionEvent.ACTION_HOVER_MOVE: {
452                     if (mLastActiveDeviceMotionEvent != null
453                             && mLastActiveDeviceMotionEvent.getDeviceId() != motion.getDeviceId()) {
454                         // This is a new gesture from a new device. Cancel the existing state
455                         // and let this through
456                         MotionEvent canceled = cancelMotion(mLastActiveDeviceMotionEvent);
457                         onInputEventInternal(canceled, policyFlags);
458                     }
459                     mLastActiveDeviceMotionEvent = MotionEvent.obtain(motion);
460                     return true;
461                 }
462                 case MotionEvent.ACTION_MOVE:
463                 case MotionEvent.ACTION_POINTER_DOWN:
464                 case MotionEvent.ACTION_POINTER_UP: {
465                     if (eventIsFromCurrentDevice) {
466                         mLastActiveDeviceMotionEvent = MotionEvent.obtain(motion);
467                         return true;
468                     } else {
469                         return false;
470                     }
471                 }
472                 case MotionEvent.ACTION_UP:
473                 case MotionEvent.ACTION_CANCEL:
474                 case MotionEvent.ACTION_HOVER_EXIT: {
475                     if (eventIsFromCurrentDevice) {
476                         // This is the last event of the gesture from this device.
477                         mLastActiveDeviceMotionEvent = null;
478                         return true;
479                     } else {
480                         // Event is from another device
481                         return false;
482                     }
483                 }
484                 default: {
485                     if (mLastActiveDeviceMotionEvent != null
486                             && event.getDeviceId() != mLastActiveDeviceMotionEvent.getDeviceId()) {
487                         // This is an event from another device, ignore it.
488                         return false;
489                     }
490                 }
491             }
492         }
493         return true;
494     }
495 
processMotionEvent(EventStreamState state, MotionEvent event, int policyFlags)496     private void processMotionEvent(EventStreamState state, MotionEvent event, int policyFlags) {
497         if (!state.shouldProcessScroll() && event.getActionMasked() == ACTION_SCROLL) {
498             super.onInputEvent(event, policyFlags);
499             return;
500         }
501 
502         if (!state.shouldProcessMotionEvent(event)) {
503             return;
504         }
505 
506         handleMotionEvent(event, policyFlags);
507     }
508 
processKeyEvent(EventStreamState state, KeyEvent event, int policyFlags)509     private void processKeyEvent(EventStreamState state, KeyEvent event, int policyFlags) {
510         if (!state.shouldProcessKeyEvent(event)) {
511             if (DEBUG) {
512                 Slog.d(TAG, "processKeyEvent: not processing: " + event);
513             }
514             super.onInputEvent(event, policyFlags);
515             return;
516         }
517         if (DEBUG) {
518             Slog.d(TAG, "processKeyEvent: " + event);
519         }
520         // Since the display id of KeyEvent always would be -1 and there is only one
521         // KeyboardInterceptor for all display, pass KeyEvent to the mEventHandler of
522         // DEFAULT_DISPLAY to handle.
523         mEventHandler.get(Display.DEFAULT_DISPLAY).onKeyEvent(event, policyFlags);
524     }
525 
handleMotionEvent(MotionEvent event, int policyFlags)526     private void handleMotionEvent(MotionEvent event, int policyFlags) {
527         if (DEBUG) {
528             Slog.i(TAG, "Handling motion event: " + event + ", policyFlags: " + policyFlags);
529         }
530         mPm.userActivity(event.getEventTime(), false);
531         MotionEvent transformedEvent = MotionEvent.obtain(event);
532         final int displayId = event.getDisplayId();
533         EventStreamTransformation eventStreamTransformation = mEventHandler.get(
534                 isDisplayIdValid(displayId) ? displayId : Display.DEFAULT_DISPLAY);
535         if (eventStreamTransformation != null) {
536             eventStreamTransformation.onMotionEvent(transformedEvent, event, policyFlags);
537         }
538         transformedEvent.recycle();
539     }
540 
isDisplayIdValid(int displayId)541     private boolean isDisplayIdValid(int displayId) {
542         return mEventHandler.get(displayId) != null;
543     }
544 
545     @Override
onMotionEvent(MotionEvent transformedEvent, MotionEvent rawEvent, int policyFlags)546     public void onMotionEvent(MotionEvent transformedEvent, MotionEvent rawEvent,
547             int policyFlags) {
548         if (!mInstalled) {
549             Slog.w(TAG, "onMotionEvent called before input filter installed!");
550             return;
551         }
552         sendInputEvent(transformedEvent, policyFlags);
553     }
554 
555     @Override
onKeyEvent(KeyEvent event, int policyFlags)556     public void onKeyEvent(KeyEvent event, int policyFlags) {
557         if (!mInstalled) {
558             Slog.w(TAG, "onKeyEvent called before input filter installed!");
559             return;
560         }
561         sendInputEvent(event, policyFlags);
562     }
563 
564     @Override
onAccessibilityEvent(AccessibilityEvent event)565     public void onAccessibilityEvent(AccessibilityEvent event) {
566         // TODO Implement this to inject the accessibility event
567         //      into the accessibility manager service similarly
568         //      to how this is done for input events.
569     }
570 
571     @Override
setNext(EventStreamTransformation sink)572     public void setNext(EventStreamTransformation sink) {
573         /* do nothing */
574     }
575 
576     @Override
getNext()577     public EventStreamTransformation getNext() {
578         return null;
579     }
580 
581     @Override
clearEvents(int inputSource)582     public void clearEvents(int inputSource) {
583         /* do nothing */
584     }
585 
setUserAndEnabledFeatures(int userId, int enabledFeatures)586     void setUserAndEnabledFeatures(int userId, int enabledFeatures) {
587         if (DEBUG) {
588             Slog.i(TAG, "setUserAndEnabledFeatures(userId = " + userId + ", enabledFeatures = 0x"
589                     + Integer.toHexString(enabledFeatures) + ")");
590         }
591         if (mEnabledFeatures == enabledFeatures && mUserId == userId) {
592             return;
593         }
594         if (mInstalled) {
595             disableFeatures();
596         }
597         mUserId = userId;
598         mEnabledFeatures = enabledFeatures;
599         if (mInstalled) {
600             enableFeatures();
601         }
602     }
603 
notifyAccessibilityEvent(AccessibilityEvent event)604     void notifyAccessibilityEvent(AccessibilityEvent event) {
605         for (int i = 0; i < mEventHandler.size(); i++) {
606             final EventStreamTransformation eventHandler = mEventHandler.valueAt(i);
607             if (eventHandler != null) {
608                 eventHandler.onAccessibilityEvent(event);
609             }
610         }
611     }
612 
notifyAccessibilityButtonClicked(int displayId)613     void notifyAccessibilityButtonClicked(int displayId) {
614         if (mMagnificationGestureHandler.size() != 0) {
615             final MagnificationGestureHandler handler = mMagnificationGestureHandler.get(displayId);
616             if (handler != null) {
617                 handler.notifyShortcutTriggered();
618             }
619         }
620     }
621 
enableFeatures()622     private void enableFeatures() {
623         if (DEBUG) Slog.i(TAG, "enableFeatures()");
624 
625         resetAllStreamState();
626 
627         final ArrayList<Display> displaysList = mAms.getValidDisplayList();
628 
629         for (int i = displaysList.size() - 1; i >= 0; i--) {
630             enableFeaturesForDisplay(displaysList.get(i));
631         }
632         enableDisplayIndependentFeatures();
633     }
634 
enableFeaturesForDisplay(Display display)635     private void enableFeaturesForDisplay(Display display) {
636         if (DEBUG) {
637             Slog.i(TAG, "enableFeaturesForDisplay() : display Id = " + display.getDisplayId());
638         }
639 
640         final Context displayContext = mContext.createDisplayContext(display);
641         final int displayId = display.getDisplayId();
642         if (mAms.isDisplayProxyed(displayId)) {
643             return;
644         }
645         if (!mServiceDetectsGestures.contains(displayId)) {
646             mServiceDetectsGestures.put(displayId, false);
647         }
648         if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) {
649             if (mAutoclickController == null) {
650                 mAutoclickController = new AutoclickController(
651                         mContext, mUserId, mAms.getTraceManager());
652             }
653             addFirstEventHandler(displayId, mAutoclickController);
654         }
655 
656         if ((mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
657             TouchExplorer explorer = new TouchExplorer(displayContext, mAms);
658             if ((mEnabledFeatures & FLAG_SERVICE_HANDLES_DOUBLE_TAP) != 0) {
659                 explorer.setServiceHandlesDoubleTap(true);
660             }
661             if ((mEnabledFeatures & FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0) {
662                 explorer.setMultiFingerGesturesEnabled(true);
663             }
664             if ((mEnabledFeatures & FLAG_REQUEST_2_FINGER_PASSTHROUGH) != 0) {
665                 explorer.setTwoFingerPassthroughEnabled(true);
666             }
667             if ((mEnabledFeatures & FLAG_SEND_MOTION_EVENTS) != 0) {
668                 explorer.setSendMotionEventsEnabled(true);
669             }
670             explorer.setServiceDetectsGestures(mServiceDetectsGestures.get(displayId));
671             addFirstEventHandler(displayId, explorer);
672             mTouchExplorer.put(displayId, explorer);
673         }
674 
675         if ((mEnabledFeatures & FLAG_FEATURE_INTERCEPT_GENERIC_MOTION_EVENTS) != 0) {
676             addFirstEventHandler(
677                     displayId,
678                     new BaseEventStreamTransformation() {
679                         @Override
680                         public void onMotionEvent(
681                                 MotionEvent event, MotionEvent rawEvent, int policyFlags) {
682                             boolean passAlongEvent = true;
683                             if (anyServiceWantsGenericMotionEvent(event)) {
684                                 // Some service wants this event, so try to deliver it to at least
685                                 // one service.
686                                 if (mAms.sendMotionEventToListeningServices(event)) {
687                                     // A service accepted this event, so prevent it from passing
688                                     // down the stream by default.
689                                     passAlongEvent = false;
690                                 }
691                                 // However, if a service is observing these events instead of
692                                 // consuming them then ensure
693                                 // it is always passed along to the next stage of the event stream.
694                                 if (anyServiceWantsToObserveMotionEvent(event)) {
695                                     passAlongEvent = true;
696                                 }
697                             }
698                             if (passAlongEvent) {
699                                 super.onMotionEvent(event, rawEvent, policyFlags);
700                             }
701                         }
702                     });
703         }
704 
705         if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0
706                 || ((mEnabledFeatures & FLAG_FEATURE_MAGNIFICATION_SINGLE_FINGER_TRIPLE_TAP) != 0)
707                 || ((mEnabledFeatures & FLAG_FEATURE_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP) != 0)
708                 || ((mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0)) {
709             final MagnificationGestureHandler magnificationGestureHandler =
710                     createMagnificationGestureHandler(displayId, displayContext);
711             addFirstEventHandler(displayId, magnificationGestureHandler);
712             mMagnificationGestureHandler.put(displayId, magnificationGestureHandler);
713         }
714 
715         if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
716             MotionEventInjector injector =
717                     new MotionEventInjector(mContext.getMainLooper(), mAms.getTraceManager());
718             addFirstEventHandler(displayId, injector);
719             mMotionEventInjectors.put(displayId, injector);
720         }
721     }
722 
enableDisplayIndependentFeatures()723     private void enableDisplayIndependentFeatures() {
724         if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
725             mAms.setMotionEventInjectors(mMotionEventInjectors);
726         }
727 
728         if ((mEnabledFeatures & FLAG_FEATURE_FILTER_KEY_EVENTS) != 0) {
729             mKeyboardInterceptor = new KeyboardInterceptor(mAms,
730                     LocalServices.getService(WindowManagerPolicy.class));
731             // Since the display id of KeyEvent always would be -1 and it would be dispatched to
732             // the display with input focus directly, we only need one KeyboardInterceptor for
733             // default display.
734             addFirstEventHandler(Display.DEFAULT_DISPLAY, mKeyboardInterceptor);
735         }
736     }
737 
738     /**
739      * Adds an event handler to the event handler chain for giving display. The handler is added at
740      * the beginning of the chain.
741      *
742      * @param displayId The logical display id.
743      * @param handler The handler to be added to the event handlers list.
744      */
addFirstEventHandler(int displayId, EventStreamTransformation handler)745     private void addFirstEventHandler(int displayId, EventStreamTransformation handler) {
746         EventStreamTransformation eventHandler = mEventHandler.get(displayId);
747         if (eventHandler != null) {
748             handler.setNext(eventHandler);
749         } else {
750             handler.setNext(this);
751         }
752         eventHandler = handler;
753         mEventHandler.put(displayId, eventHandler);
754     }
755 
disableFeatures()756     private void disableFeatures() {
757         final ArrayList<Display> displaysList = mAms.getValidDisplayList();
758 
759         for (int i = displaysList.size() - 1; i >= 0; i--) {
760             disableFeaturesForDisplay(displaysList.get(i).getDisplayId());
761         }
762         mAms.setMotionEventInjectors(null);
763         disableDisplayIndependentFeatures();
764 
765         resetAllStreamState();
766     }
767 
disableFeaturesForDisplay(int displayId)768     private void disableFeaturesForDisplay(int displayId) {
769         if (DEBUG) {
770             Slog.i(TAG, "disableFeaturesForDisplay() : display Id = " + displayId);
771         }
772 
773         final MotionEventInjector injector = mMotionEventInjectors.get(displayId);
774         if (injector != null) {
775             injector.onDestroy();
776             mMotionEventInjectors.remove(displayId);
777         }
778 
779         final TouchExplorer explorer = mTouchExplorer.get(displayId);
780         if (explorer != null) {
781             explorer.onDestroy();
782             mTouchExplorer.remove(displayId);
783         }
784 
785         final MagnificationGestureHandler handler = mMagnificationGestureHandler.get(displayId);
786         if (handler != null) {
787             handler.onDestroy();
788             mMagnificationGestureHandler.remove(displayId);
789         }
790 
791         final EventStreamTransformation eventStreamTransformation = mEventHandler.get(displayId);
792         if (eventStreamTransformation != null) {
793             mEventHandler.remove(displayId);
794         }
795     }
enableFeaturesForDisplayIfInstalled(Display display)796     void enableFeaturesForDisplayIfInstalled(Display display) {
797         if (mInstalled) {
798             resetStreamStateForDisplay(display.getDisplayId());
799             enableFeaturesForDisplay(display);
800         }
801     }
disableFeaturesForDisplayIfInstalled(int displayId)802     void disableFeaturesForDisplayIfInstalled(int displayId) {
803         if (mInstalled) {
804             disableFeaturesForDisplay(displayId);
805             resetStreamStateForDisplay(displayId);
806         }
807     }
808 
disableDisplayIndependentFeatures()809     private void disableDisplayIndependentFeatures() {
810         if (mAutoclickController != null) {
811             mAutoclickController.onDestroy();
812             mAutoclickController = null;
813         }
814 
815         if (mKeyboardInterceptor != null) {
816             mKeyboardInterceptor.onDestroy();
817             mKeyboardInterceptor = null;
818         }
819     }
820 
createMagnificationGestureHandler( int displayId, Context displayContext)821     private MagnificationGestureHandler createMagnificationGestureHandler(
822             int displayId, Context displayContext) {
823         final boolean detectControlGestures = (mEnabledFeatures
824                 & FLAG_FEATURE_MAGNIFICATION_SINGLE_FINGER_TRIPLE_TAP) != 0;
825         final boolean detectTwoFingerTripleTap = (mEnabledFeatures
826                 & FLAG_FEATURE_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP) != 0;
827         final boolean triggerable = (mEnabledFeatures
828                 & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0;
829         MagnificationGestureHandler magnificationGestureHandler;
830         if (mAms.getMagnificationMode(displayId)
831                 == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
832             final Context uiContext = displayContext.createWindowContext(
833                     TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, null /* options */);
834             magnificationGestureHandler = new WindowMagnificationGestureHandler(uiContext,
835                     mAms.getMagnificationConnectionManager(), mAms.getTraceManager(),
836                     mAms.getMagnificationController(),
837                     detectControlGestures,
838                     detectTwoFingerTripleTap,
839                     triggerable, displayId);
840         } else {
841             final Context uiContext = displayContext.createWindowContext(
842                     TYPE_MAGNIFICATION_OVERLAY, null /* options */);
843             FullScreenMagnificationVibrationHelper fullScreenMagnificationVibrationHelper =
844                     new FullScreenMagnificationVibrationHelper(uiContext);
845             magnificationGestureHandler = new FullScreenMagnificationGestureHandler(uiContext,
846                     mAms.getMagnificationController().getFullScreenMagnificationController(),
847                     mAms.getTraceManager(),
848                     mAms.getMagnificationController(),
849                     detectControlGestures,
850                     detectTwoFingerTripleTap,
851                     triggerable,
852                     new WindowMagnificationPromptController(displayContext, mUserId), displayId,
853                     fullScreenMagnificationVibrationHelper);
854         }
855         return magnificationGestureHandler;
856     }
857 
resetAllStreamState()858     void resetAllStreamState() {
859         final ArrayList<Display> displaysList = mAms.getValidDisplayList();
860 
861         for (int i = displaysList.size() - 1; i >= 0; i--) {
862             resetStreamStateForDisplay(displaysList.get(i).getDisplayId());
863         }
864 
865         if (mKeyboardStreamState != null) {
866             mKeyboardStreamState.reset();
867         }
868     }
869 
resetStreamStateForDisplay(int displayId)870     void resetStreamStateForDisplay(int displayId) {
871         final EventStreamState touchScreenStreamState = mTouchScreenStreamStates.get(displayId);
872         if (touchScreenStreamState != null) {
873             touchScreenStreamState.reset();
874             mTouchScreenStreamStates.remove(displayId);
875         }
876 
877         final EventStreamState mouseStreamState = mMouseStreamStates.get(displayId);
878         if (mouseStreamState != null) {
879             mouseStreamState.reset();
880             mMouseStreamStates.remove(displayId);
881         }
882     }
883 
884     @Override
onDestroy()885     public void onDestroy() {
886         /* ignore */
887     }
888 
889     /**
890      * Called to refresh the magnification mode on the given display.
891      * It's responsible for changing {@link MagnificationGestureHandler} based on the current mode.
892      *
893      * @param display The logical display
894      */
895     @MainThread
refreshMagnificationMode(Display display)896     public void refreshMagnificationMode(Display display) {
897         final int displayId = display.getDisplayId();
898         final MagnificationGestureHandler magnificationGestureHandler =
899                 mMagnificationGestureHandler.get(displayId);
900         if (magnificationGestureHandler == null) {
901             return;
902         }
903         if (magnificationGestureHandler.getMode() == mAms.getMagnificationMode(displayId)) {
904             return;
905         }
906         magnificationGestureHandler.onDestroy();
907         final MagnificationGestureHandler currentMagnificationGestureHandler =
908                 createMagnificationGestureHandler(displayId,
909                         mContext.createDisplayContext(display));
910         switchEventStreamTransformation(displayId, magnificationGestureHandler,
911                 currentMagnificationGestureHandler);
912         mMagnificationGestureHandler.put(displayId, currentMagnificationGestureHandler);
913     }
914 
915     @MainThread
switchEventStreamTransformation(int displayId, EventStreamTransformation oldStreamTransformation, EventStreamTransformation currentStreamTransformation)916     private void switchEventStreamTransformation(int displayId,
917             EventStreamTransformation oldStreamTransformation,
918             EventStreamTransformation currentStreamTransformation) {
919         EventStreamTransformation eventStreamTransformation = mEventHandler.get(displayId);
920         if (eventStreamTransformation == null) {
921             return;
922         }
923         if (eventStreamTransformation == oldStreamTransformation) {
924             currentStreamTransformation.setNext(oldStreamTransformation.getNext());
925             mEventHandler.put(displayId, currentStreamTransformation);
926         } else {
927             while (eventStreamTransformation != null) {
928                 if (eventStreamTransformation.getNext() == oldStreamTransformation) {
929                     eventStreamTransformation.setNext(currentStreamTransformation);
930                     currentStreamTransformation.setNext(oldStreamTransformation.getNext());
931                     return;
932                 } else {
933                     eventStreamTransformation = eventStreamTransformation.getNext();
934                 }
935             }
936         }
937     }
938 
939     /**
940      * Keeps state of event streams observed for an input device with a certain source.
941      * Provides information about whether motion and key events should be processed by accessibility
942      * #EventStreamTransformations. Base implementation describes behaviour for event sources that
943      * whose events should not be handled by a11y event stream transformations.
944      */
945     private static class EventStreamState {
946         private int mSource;
947 
EventStreamState()948         EventStreamState() {
949             mSource = -1;
950         }
951 
952         /**
953          * Updates the input source of the device associated with the state. If the source changes,
954          * resets internal state.
955          *
956          * @param source Updated input source.
957          * @return Whether the input source has changed.
958          */
updateInputSource(int source)959         public boolean updateInputSource(int source) {
960             if (mSource == source) {
961                 return false;
962             }
963             // Reset clears internal state, so make sure it's called before |mSource| is updated.
964             reset();
965             mSource = source;
966             return true;
967         }
968 
969         /**
970          * @return Whether input source is valid.
971          */
inputSourceValid()972         public boolean inputSourceValid() {
973             return mSource >= 0;
974         }
975 
976         /**
977          * Resets the event stream state.
978          */
reset()979         public void reset() {
980             mSource = -1;
981         }
982 
983         /**
984          * @return Whether scroll events for device should be handled by event transformations.
985          */
shouldProcessScroll()986         public boolean shouldProcessScroll() {
987             return false;
988         }
989 
990         /**
991          * @param event An observed motion event.
992          * @return Whether the event should be handled by event transformations.
993          */
shouldProcessMotionEvent(MotionEvent event)994         public boolean shouldProcessMotionEvent(MotionEvent event) {
995             return false;
996         }
997 
998         /**
999          * @param event An observed key event.
1000          * @return Whether the event should be handled by event transformations.
1001          */
shouldProcessKeyEvent(KeyEvent event)1002         public boolean shouldProcessKeyEvent(KeyEvent event) {
1003             return false;
1004         }
1005     }
1006 
1007     /**
1008      * Keeps state of stream of events from a mouse device.
1009      */
1010     private static class MouseEventStreamState extends EventStreamState {
1011         private boolean mMotionSequenceStarted;
1012 
MouseEventStreamState()1013         public MouseEventStreamState() {
1014             reset();
1015         }
1016 
1017         @Override
reset()1018         final public void reset() {
1019             super.reset();
1020             mMotionSequenceStarted = false;
1021         }
1022 
1023         @Override
shouldProcessScroll()1024         final public boolean shouldProcessScroll() {
1025             return true;
1026         }
1027 
1028         @Override
shouldProcessMotionEvent(MotionEvent event)1029         final public boolean shouldProcessMotionEvent(MotionEvent event) {
1030             if (mMotionSequenceStarted) {
1031                 return true;
1032             }
1033             // Wait for down or move event to start processing mouse events.
1034             int action = event.getActionMasked();
1035             mMotionSequenceStarted =
1036                     action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_HOVER_MOVE;
1037             return mMotionSequenceStarted;
1038         }
1039     }
1040 
1041     /**
1042      * Keeps state of stream of events from a touch screen device.
1043      */
1044     private static class TouchScreenEventStreamState extends EventStreamState {
1045         private boolean mTouchSequenceStarted;
1046         private boolean mHoverSequenceStarted;
1047 
TouchScreenEventStreamState()1048         public TouchScreenEventStreamState() {
1049             reset();
1050         }
1051 
1052         @Override
reset()1053         final public void reset() {
1054             super.reset();
1055             mTouchSequenceStarted = false;
1056             mHoverSequenceStarted = false;
1057         }
1058 
1059         @Override
shouldProcessMotionEvent(MotionEvent event)1060         final public boolean shouldProcessMotionEvent(MotionEvent event) {
1061             // Wait for a down touch event to start processing.
1062             if (event.isTouchEvent()) {
1063                 if (mTouchSequenceStarted) {
1064                     return true;
1065                 }
1066                 mTouchSequenceStarted = event.getActionMasked() == MotionEvent.ACTION_DOWN;
1067                 return mTouchSequenceStarted;
1068             }
1069 
1070             // Wait for an enter hover event to start processing.
1071             if (mHoverSequenceStarted) {
1072                 return true;
1073             }
1074             mHoverSequenceStarted = event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER;
1075             return mHoverSequenceStarted;
1076         }
1077     }
1078 
1079     private class GenericMotionEventStreamState extends EventStreamState {
1080         @Override
shouldProcessMotionEvent(MotionEvent event)1081         public boolean shouldProcessMotionEvent(MotionEvent event) {
1082             return anyServiceWantsGenericMotionEvent(event);
1083         }
1084         @Override
shouldProcessScroll()1085         public boolean shouldProcessScroll() {
1086             return true;
1087         }
1088     }
1089 
anyServiceWantsToObserveMotionEvent(MotionEvent event)1090     private boolean anyServiceWantsToObserveMotionEvent(MotionEvent event) {
1091         // Disable SOURCE_TOUCHSCREEN generic event interception if any service is performing
1092         // touch exploration.
1093         if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)
1094                 && (mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
1095             return false;
1096         }
1097         final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
1098         return (mCombinedGenericMotionEventSources
1099                         & mCombinedMotionEventObservedSources
1100                         & eventSourceWithoutClass)
1101                 != 0;
1102     }
1103 
anyServiceWantsGenericMotionEvent(MotionEvent event)1104     private boolean anyServiceWantsGenericMotionEvent(MotionEvent event) {
1105         // Disable SOURCE_TOUCHSCREEN generic event interception if any service is performing
1106         // touch exploration.
1107         if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)
1108                 && (mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
1109             return false;
1110         }
1111         final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
1112         return (mCombinedGenericMotionEventSources & eventSourceWithoutClass) != 0;
1113     }
1114 
setCombinedGenericMotionEventSources(int sources)1115     public void setCombinedGenericMotionEventSources(int sources) {
1116         mCombinedGenericMotionEventSources = sources;
1117     }
1118 
setCombinedMotionEventObservedSources(int sources)1119     public void setCombinedMotionEventObservedSources(int sources) {
1120         mCombinedMotionEventObservedSources = sources;
1121     }
1122 
1123     /**
1124      * Keeps state of streams of events from all keyboard devices.
1125      */
1126     private static class KeyboardEventStreamState extends EventStreamState {
1127         private SparseBooleanArray mEventSequenceStartedMap = new SparseBooleanArray();
1128 
KeyboardEventStreamState()1129         public KeyboardEventStreamState() {
1130             reset();
1131         }
1132 
1133         @Override
reset()1134         final public void reset() {
1135             super.reset();
1136             mEventSequenceStartedMap.clear();
1137         }
1138 
1139         /*
1140          * Key events from different devices may be interleaved. For example, the volume up and
1141          * down keys can come from different input sources.
1142          */
1143         @Override
updateInputSource(int deviceId)1144         public boolean updateInputSource(int deviceId) {
1145             return false;
1146         }
1147 
1148         // We manage all input source simultaneously; there is no concept of validity.
1149         @Override
inputSourceValid()1150         public boolean inputSourceValid() {
1151             return true;
1152         }
1153 
1154         @Override
shouldProcessKeyEvent(KeyEvent event)1155         final public boolean shouldProcessKeyEvent(KeyEvent event) {
1156             // For each keyboard device, wait for a down event from a device to start processing
1157             int deviceId = event.getDeviceId();
1158             if (mEventSequenceStartedMap.get(deviceId, false)) {
1159                 return true;
1160             }
1161             boolean shouldProcess = event.getAction() == KeyEvent.ACTION_DOWN;
1162             mEventSequenceStartedMap.put(deviceId, shouldProcess);
1163             return shouldProcess;
1164         }
1165     }
1166 
setGestureDetectionPassthroughRegion(int displayId, Region region)1167     public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
1168         if (region != null && mTouchExplorer.contains(displayId)) {
1169             mTouchExplorer.get(displayId).setGestureDetectionPassthroughRegion(region);
1170         }
1171     }
1172 
setTouchExplorationPassthroughRegion(int displayId, Region region)1173     public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
1174         if (region != null && mTouchExplorer.contains(displayId)) {
1175             mTouchExplorer.get(displayId).setTouchExplorationPassthroughRegion(region);
1176         }
1177     }
1178 
setServiceDetectsGesturesEnabled(int displayId, boolean mode)1179     public void setServiceDetectsGesturesEnabled(int displayId, boolean mode) {
1180         if (mTouchExplorer.contains(displayId)) {
1181             mTouchExplorer.get(displayId).setServiceDetectsGestures(mode);
1182         }
1183         mServiceDetectsGestures.put(displayId, mode);
1184     }
1185 
resetServiceDetectsGestures()1186     public void resetServiceDetectsGestures() {
1187         mServiceDetectsGestures.clear();
1188     }
1189 
requestTouchExploration(int displayId)1190     public void requestTouchExploration(int displayId) {
1191         if (mTouchExplorer.contains(displayId)) {
1192             mTouchExplorer.get(displayId).requestTouchExploration();
1193         }
1194     }
1195 
requestDragging(int displayId, int pointerId)1196     public void requestDragging(int displayId, int pointerId) {
1197         if (mTouchExplorer.contains(displayId)) {
1198             mTouchExplorer.get(displayId).requestDragging(pointerId);
1199         }
1200     }
1201 
requestDelegating(int displayId)1202     public void requestDelegating(int displayId) {
1203         if (mTouchExplorer.contains(displayId)) {
1204             mTouchExplorer.get(displayId).requestDelegating();
1205         }
1206     }
1207 
onDoubleTap(int displayId)1208     public void onDoubleTap(int displayId) {
1209         if (mTouchExplorer.contains(displayId)) {
1210             mTouchExplorer.get(displayId).onDoubleTap();
1211         }
1212     }
1213 
onDoubleTapAndHold(int displayId)1214     public void onDoubleTapAndHold(int displayId) {
1215         if (mTouchExplorer.contains(displayId)) {
1216             mTouchExplorer.get(displayId).onDoubleTapAndHold();
1217         }
1218     }
1219 
1220     /**
1221      * Dumps all {@link AccessibilityInputFilter}s here.
1222      */
dump(FileDescriptor fd, final PrintWriter pw, String[] args)1223     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
1224         if (mEventHandler == null) {
1225             return;
1226         }
1227         pw.append("A11yInputFilter Info : ");
1228         pw.println();
1229 
1230         final ArrayList<Display> displaysList = mAms.getValidDisplayList();
1231         for (int i = 0; i < displaysList.size(); i++) {
1232             final int displayId = displaysList.get(i).getDisplayId();
1233             EventStreamTransformation next = mEventHandler.get(displayId);
1234             if (next != null) {
1235                 pw.append("Enabled features of Display [");
1236                 pw.append(Integer.toString(displayId));
1237                 pw.append("] = ");
1238 
1239                 final StringJoiner joiner = new StringJoiner(",", "[", "]");
1240 
1241                 while (next != null) {
1242                     if (next instanceof MagnificationGestureHandler) {
1243                         joiner.add("MagnificationGesture");
1244                     } else if (next instanceof KeyboardInterceptor) {
1245                         joiner.add("KeyboardInterceptor");
1246                     } else if (next instanceof TouchExplorer) {
1247                         joiner.add("TouchExplorer");
1248                     } else if (next instanceof AutoclickController) {
1249                         joiner.add("AutoclickController");
1250                     } else if (next instanceof MotionEventInjector) {
1251                         joiner.add("MotionEventInjector");
1252                     }
1253                     next = next.getNext();
1254                 }
1255                 pw.append(joiner.toString());
1256             }
1257             pw.println();
1258         }
1259     }
1260 }
1261