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