1 /*
2  * Copyright (C) 2019 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 android.accessibilityservice;
18 
19 
20 import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP;
21 import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD;
22 import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP;
23 import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_DOWN;
24 import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_LEFT;
25 import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_RIGHT;
26 import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_UP;
27 import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_TRIPLE_TAP;
28 import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_TRIPLE_TAP_AND_HOLD;
29 import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP;
30 import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD;
31 import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP;
32 import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD;
33 import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN;
34 import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_LEFT;
35 import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_RIGHT;
36 import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_UP;
37 import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP;
38 import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD;
39 import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP;
40 import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD;
41 import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SINGLE_TAP;
42 import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_DOWN;
43 import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_LEFT;
44 import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_RIGHT;
45 import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_UP;
46 import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_TRIPLE_TAP;
47 import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP;
48 import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP_AND_HOLD;
49 import static android.accessibilityservice.AccessibilityService.GESTURE_PASSTHROUGH;
50 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN;
51 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN_AND_LEFT;
52 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN_AND_RIGHT;
53 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN_AND_UP;
54 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_LEFT;
55 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_LEFT_AND_DOWN;
56 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_LEFT_AND_RIGHT;
57 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_LEFT_AND_UP;
58 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_RIGHT;
59 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_RIGHT_AND_DOWN;
60 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_RIGHT_AND_LEFT;
61 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_RIGHT_AND_UP;
62 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP;
63 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP_AND_DOWN;
64 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP_AND_LEFT;
65 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP_AND_RIGHT;
66 import static android.accessibilityservice.AccessibilityService.GESTURE_TOUCH_EXPLORATION;
67 import static android.accessibilityservice.AccessibilityService.GESTURE_UNKNOWN;
68 
69 import android.annotation.IntDef;
70 import android.annotation.NonNull;
71 import android.annotation.TestApi;
72 import android.content.pm.ParceledListSlice;
73 import android.os.Parcel;
74 import android.os.Parcelable;
75 import android.view.MotionEvent;
76 
77 import java.lang.annotation.Retention;
78 import java.lang.annotation.RetentionPolicy;
79 import java.util.ArrayList;
80 import java.util.List;
81 
82 /**
83  * This class describes the gesture event including gesture id and which display it happens
84  * on.
85  * <p>
86  * <strong>Note:</strong> Accessibility services setting the
87  * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}
88  * flag can receive gestures.
89  *
90  * @see AccessibilityService#onGesture(AccessibilityGestureEvent)
91  */
92 
93 public final class AccessibilityGestureEvent implements Parcelable {
94 
95     /** @hide */
96     @IntDef(prefix = { "GESTURE_" }, value = {
97           GESTURE_UNKNOWN,
98           GESTURE_TOUCH_EXPLORATION,
99             GESTURE_2_FINGER_SINGLE_TAP,
100             GESTURE_2_FINGER_DOUBLE_TAP,
101             GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD,
102             GESTURE_2_FINGER_TRIPLE_TAP,
103             GESTURE_2_FINGER_TRIPLE_TAP_AND_HOLD,
104             GESTURE_3_FINGER_SINGLE_TAP,
105             GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD,
106             GESTURE_3_FINGER_DOUBLE_TAP,
107             GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD,
108             GESTURE_3_FINGER_TRIPLE_TAP,
109             GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD,
110             GESTURE_DOUBLE_TAP,
111             GESTURE_DOUBLE_TAP_AND_HOLD,
112             GESTURE_SWIPE_UP,
113             GESTURE_SWIPE_UP_AND_LEFT,
114             GESTURE_SWIPE_UP_AND_DOWN,
115             GESTURE_SWIPE_UP_AND_RIGHT,
116             GESTURE_SWIPE_DOWN,
117             GESTURE_SWIPE_DOWN_AND_LEFT,
118             GESTURE_SWIPE_DOWN_AND_UP,
119             GESTURE_SWIPE_DOWN_AND_RIGHT,
120             GESTURE_SWIPE_LEFT,
121             GESTURE_SWIPE_LEFT_AND_UP,
122             GESTURE_SWIPE_LEFT_AND_RIGHT,
123             GESTURE_SWIPE_LEFT_AND_DOWN,
124             GESTURE_SWIPE_RIGHT,
125             GESTURE_SWIPE_RIGHT_AND_UP,
126             GESTURE_SWIPE_RIGHT_AND_LEFT,
127             GESTURE_SWIPE_RIGHT_AND_DOWN,
128             GESTURE_2_FINGER_SWIPE_DOWN,
129             GESTURE_2_FINGER_SWIPE_LEFT,
130             GESTURE_2_FINGER_SWIPE_RIGHT,
131             GESTURE_2_FINGER_SWIPE_UP,
132             GESTURE_3_FINGER_SWIPE_DOWN,
133             GESTURE_3_FINGER_SWIPE_LEFT,
134             GESTURE_3_FINGER_SWIPE_RIGHT,
135             GESTURE_3_FINGER_SWIPE_UP,
136             GESTURE_4_FINGER_DOUBLE_TAP,
137             GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD,
138             GESTURE_4_FINGER_SINGLE_TAP,
139             GESTURE_4_FINGER_SWIPE_DOWN,
140             GESTURE_4_FINGER_SWIPE_LEFT,
141             GESTURE_4_FINGER_SWIPE_RIGHT,
142             GESTURE_4_FINGER_SWIPE_UP,
143             GESTURE_4_FINGER_TRIPLE_TAP
144     })
145     @Retention(RetentionPolicy.SOURCE)
146     public @interface GestureId {}
147 
148     @GestureId
149     private final int mGestureId;
150     private final int mDisplayId;
151     private List<MotionEvent> mMotionEvents = new ArrayList<>();
152 
153     /**
154      * Constructs an AccessibilityGestureEvent to be dispatched to an accessibility service.
155      *
156      * @param gestureId    the id number of the gesture.
157      * @param displayId    the display on which this gesture was performed.
158      * @param motionEvents the motion events that lead to this gesture.
159      */
AccessibilityGestureEvent( int gestureId, int displayId, @NonNull List<MotionEvent> motionEvents)160     public AccessibilityGestureEvent(
161             int gestureId, int displayId, @NonNull List<MotionEvent> motionEvents) {
162         mGestureId = gestureId;
163         mDisplayId = displayId;
164         mMotionEvents.addAll(motionEvents);
165     }
166 
167     /** @hide */
168     @TestApi
AccessibilityGestureEvent(int gestureId, int displayId)169     public AccessibilityGestureEvent(int gestureId, int displayId) {
170         this(gestureId, displayId, new ArrayList<MotionEvent>());
171     }
172 
AccessibilityGestureEvent(@onNull Parcel parcel)173     private AccessibilityGestureEvent(@NonNull Parcel parcel) {
174         mGestureId = parcel.readInt();
175         mDisplayId = parcel.readInt();
176         ParceledListSlice<MotionEvent> slice = parcel.readParcelable(getClass().getClassLoader(), android.content.pm.ParceledListSlice.class);
177         mMotionEvents = slice.getList();
178     }
179 
180     /**
181      * Returns the display id of the received-gesture display, for use with
182      * {@link android.hardware.display.DisplayManager#getDisplay(int)}.
183      *
184      * @return the display id.
185      */
getDisplayId()186     public int getDisplayId() {
187         return mDisplayId;
188     }
189 
190     /**
191      * Returns performed gesture id.
192      *
193      * @return the performed gesture id.
194      *
195      */
getGestureId()196     @GestureId public int getGestureId() {
197         return mGestureId;
198     }
199 
200     /**
201      * Returns the motion events that lead to this gesture.
202      *
203      */
204     @NonNull
getMotionEvents()205     public List<MotionEvent> getMotionEvents() {
206         return mMotionEvents;
207     }
208 
209     /**
210      * When we asynchronously use {@link AccessibilityGestureEvent}, we should make a copy,
211      * because motionEvent may be recycled before we use async.
212      *
213      * @hide
214      */
215     @NonNull
copyForAsync()216     public AccessibilityGestureEvent copyForAsync() {
217         return new AccessibilityGestureEvent(mGestureId, mDisplayId,
218                 mMotionEvents.stream().map(MotionEvent::copy).toList());
219     }
220 
221     /**
222      * After we use {@link AccessibilityGestureEvent} asynchronously, we should recycle the
223      * MotionEvent, avoid memory leaks.
224      *
225      * @hide
226      */
recycle()227     public void recycle() {
228         mMotionEvents.forEach(MotionEvent::recycle);
229         mMotionEvents.clear();
230     }
231 
232     @NonNull
233     @Override
toString()234     public String toString() {
235         StringBuilder stringBuilder = new StringBuilder("AccessibilityGestureEvent[");
236         stringBuilder.append("gestureId: ").append(gestureIdToString(mGestureId));
237         stringBuilder.append(", ");
238         stringBuilder.append("displayId: ").append(mDisplayId);
239         stringBuilder.append(", ");
240         stringBuilder.append("Motion Events: [");
241         for (int i = 0; i < mMotionEvents.size(); ++i) {
242             String action = MotionEvent.actionToString(mMotionEvents.get(i).getActionMasked());
243             stringBuilder.append(action);
244             if (i < (mMotionEvents.size() - 1)) {
245                 stringBuilder.append(", ");
246             } else {
247                 stringBuilder.append("]");
248             }
249         }
250         stringBuilder.append(']');
251         return stringBuilder.toString();
252     }
253 
254     /**
255      * Returns a string representation of the specified gesture id.
256      */
257     @NonNull
gestureIdToString(int id)258     public static String gestureIdToString(int id) {
259         switch (id) {
260             case GESTURE_UNKNOWN: return "GESTURE_UNKNOWN";
261             case GESTURE_PASSTHROUGH: return "GESTURE_PASSTHROUGH";
262             case GESTURE_TOUCH_EXPLORATION: return "GESTURE_TOUCH_EXPLORATION";
263             case GESTURE_2_FINGER_SINGLE_TAP: return "GESTURE_2_FINGER_SINGLE_TAP";
264             case GESTURE_2_FINGER_TRIPLE_TAP_AND_HOLD:
265                 return "GESTURE_2_FINGER_TRIPLE_TAP_AND_HOLD";
266             case GESTURE_2_FINGER_DOUBLE_TAP: return "GESTURE_2_FINGER_DOUBLE_TAP";
267             case GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD:
268                 return "GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD";
269             case GESTURE_2_FINGER_TRIPLE_TAP: return "GESTURE_2_FINGER_TRIPLE_TAP";
270             case GESTURE_3_FINGER_SINGLE_TAP: return "GESTURE_3_FINGER_SINGLE_TAP";
271             case GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD:
272                 return "GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD";
273             case GESTURE_3_FINGER_DOUBLE_TAP: return "GESTURE_3_FINGER_DOUBLE_TAP";
274             case GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD:
275                 return "GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD";
276             case GESTURE_3_FINGER_TRIPLE_TAP: return "GESTURE_3_FINGER_TRIPLE_TAP";
277             case GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD:
278                 return "GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD";
279             case GESTURE_4_FINGER_SINGLE_TAP: return "GESTURE_4_FINGER_SINGLE_TAP";
280             case GESTURE_4_FINGER_DOUBLE_TAP: return "GESTURE_4_FINGER_DOUBLE_TAP";
281             case GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD:
282                 return "GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD";
283             case GESTURE_4_FINGER_TRIPLE_TAP: return "GESTURE_4_FINGER_TRIPLE_TAP";
284             case GESTURE_DOUBLE_TAP: return "GESTURE_DOUBLE_TAP";
285             case GESTURE_DOUBLE_TAP_AND_HOLD: return "GESTURE_DOUBLE_TAP_AND_HOLD";
286             case GESTURE_SWIPE_DOWN: return "GESTURE_SWIPE_DOWN";
287             case GESTURE_SWIPE_DOWN_AND_LEFT: return "GESTURE_SWIPE_DOWN_AND_LEFT";
288             case GESTURE_SWIPE_DOWN_AND_UP: return "GESTURE_SWIPE_DOWN_AND_UP";
289             case GESTURE_SWIPE_DOWN_AND_RIGHT: return "GESTURE_SWIPE_DOWN_AND_RIGHT";
290             case GESTURE_SWIPE_LEFT: return "GESTURE_SWIPE_LEFT";
291             case GESTURE_SWIPE_LEFT_AND_UP: return "GESTURE_SWIPE_LEFT_AND_UP";
292             case GESTURE_SWIPE_LEFT_AND_RIGHT: return "GESTURE_SWIPE_LEFT_AND_RIGHT";
293             case GESTURE_SWIPE_LEFT_AND_DOWN: return "GESTURE_SWIPE_LEFT_AND_DOWN";
294             case GESTURE_SWIPE_RIGHT: return "GESTURE_SWIPE_RIGHT";
295             case GESTURE_SWIPE_RIGHT_AND_UP: return "GESTURE_SWIPE_RIGHT_AND_UP";
296             case GESTURE_SWIPE_RIGHT_AND_LEFT: return "GESTURE_SWIPE_RIGHT_AND_LEFT";
297             case GESTURE_SWIPE_RIGHT_AND_DOWN: return "GESTURE_SWIPE_RIGHT_AND_DOWN";
298             case GESTURE_SWIPE_UP: return "GESTURE_SWIPE_UP";
299             case GESTURE_SWIPE_UP_AND_LEFT: return "GESTURE_SWIPE_UP_AND_LEFT";
300             case GESTURE_SWIPE_UP_AND_DOWN: return "GESTURE_SWIPE_UP_AND_DOWN";
301             case GESTURE_SWIPE_UP_AND_RIGHT: return "GESTURE_SWIPE_UP_AND_RIGHT";
302             case GESTURE_2_FINGER_SWIPE_DOWN: return "GESTURE_2_FINGER_SWIPE_DOWN";
303             case GESTURE_2_FINGER_SWIPE_LEFT: return "GESTURE_2_FINGER_SWIPE_LEFT";
304             case GESTURE_2_FINGER_SWIPE_RIGHT: return "GESTURE_2_FINGER_SWIPE_RIGHT";
305             case GESTURE_2_FINGER_SWIPE_UP: return "GESTURE_2_FINGER_SWIPE_UP";
306             case GESTURE_3_FINGER_SWIPE_DOWN: return "GESTURE_3_FINGER_SWIPE_DOWN";
307             case GESTURE_3_FINGER_SWIPE_LEFT: return "GESTURE_3_FINGER_SWIPE_LEFT";
308             case GESTURE_3_FINGER_SWIPE_RIGHT: return "GESTURE_3_FINGER_SWIPE_RIGHT";
309             case GESTURE_3_FINGER_SWIPE_UP: return "GESTURE_3_FINGER_SWIPE_UP";
310             case GESTURE_4_FINGER_SWIPE_DOWN: return "GESTURE_4_FINGER_SWIPE_DOWN";
311             case GESTURE_4_FINGER_SWIPE_LEFT: return "GESTURE_4_FINGER_SWIPE_LEFT";
312             case GESTURE_4_FINGER_SWIPE_RIGHT: return "GESTURE_4_FINGER_SWIPE_RIGHT";
313             case GESTURE_4_FINGER_SWIPE_UP: return "GESTURE_4_FINGER_SWIPE_UP";
314             default: return Integer.toHexString(id);
315         }
316     }
317 
318     /**
319      * {@inheritDoc}
320      */
321     @Override
describeContents()322     public int describeContents() {
323         return 0;
324     }
325 
326     @Override
writeToParcel(@onNull Parcel parcel, int flags)327     public void writeToParcel(@NonNull Parcel parcel, int flags) {
328         parcel.writeInt(mGestureId);
329         parcel.writeInt(mDisplayId);
330         parcel.writeParcelable(new ParceledListSlice<MotionEvent>(mMotionEvents), 0);
331     }
332 
333     /**
334      * @see Parcelable.Creator
335      */
336     public static final @NonNull Parcelable.Creator<AccessibilityGestureEvent> CREATOR =
337             new Parcelable.Creator<AccessibilityGestureEvent>() {
338         public AccessibilityGestureEvent createFromParcel(Parcel parcel) {
339             return new AccessibilityGestureEvent(parcel);
340         }
341 
342         public AccessibilityGestureEvent[] newArray(int size) {
343             return new AccessibilityGestureEvent[size];
344         }
345     };
346 
347 }
348