blob: 7722dc318fd7b82d817303b760749bdd41aaac1c [file] [log] [blame]
svetoslavganov75986cf2009-05-14 22:28:01 -07001/*
2 * Copyright (C) 2009 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
17package android.accessibilityservice;
18
Phil Weavera6b64f52015-12-04 15:21:35 -080019import android.accessibilityservice.GestureDescription.MotionEventGenerator;
Jacky Kao09789e42020-01-15 16:23:52 +080020import android.annotation.CallbackExecutor;
Anna Galusza9b278112016-01-04 11:37:37 -080021import android.annotation.IntDef;
Alan Viverette7c9746d4e2014-11-19 17:02:16 -080022import android.annotation.NonNull;
Alan Viverette214fb682015-11-17 09:47:11 -050023import android.annotation.Nullable;
Phil Weaver27fcd9c2017-01-20 15:57:24 -080024import android.annotation.RequiresPermission;
svetoslavganov75986cf2009-05-14 22:28:01 -070025import android.app.Service;
Artur Satayevc895b1b2019-12-10 17:47:51 +000026import android.compat.annotation.UnsupportedAppUsage;
Svetoslav Ganov79311c42012-01-17 20:24:26 -080027import android.content.Context;
svetoslavganov75986cf2009-05-14 22:28:01 -070028import android.content.Intent;
Phil Weavera6b64f52015-12-04 15:21:35 -080029import android.content.pm.ParceledListSlice;
Jacky Kao09789e42020-01-15 16:23:52 +080030import android.graphics.Bitmap;
Alan Viverette214fb682015-11-17 09:47:11 -050031import android.graphics.Region;
Jacky Kao09789e42020-01-15 16:23:52 +080032import android.os.Binder;
Mathew Inwood8c854f82018-09-14 12:35:36 +010033import android.os.Build;
Alan Viverette214fb682015-11-17 09:47:11 -050034import android.os.Handler;
svetoslavganov75986cf2009-05-14 22:28:01 -070035import android.os.IBinder;
Svetoslav Ganov79311c42012-01-17 20:24:26 -080036import android.os.Looper;
svetoslavganov75986cf2009-05-14 22:28:01 -070037import android.os.Message;
Jacky Kao09789e42020-01-15 16:23:52 +080038import android.os.RemoteCallback;
svetoslavganov75986cf2009-05-14 22:28:01 -070039import android.os.RemoteException;
Alan Viverette214fb682015-11-17 09:47:11 -050040import android.util.ArrayMap;
svetoslavganov75986cf2009-05-14 22:28:01 -070041import android.util.Log;
Alan Viverette214fb682015-11-17 09:47:11 -050042import android.util.Slog;
Phil Weavera6b64f52015-12-04 15:21:35 -080043import android.util.SparseArray;
Rhed Jao02655dc2018-10-30 20:44:52 +080044import android.view.Display;
Svetoslavc4fccd12013-04-09 12:58:41 -070045import android.view.KeyEvent;
Svetoslav3a5c7212014-10-14 09:54:26 -070046import android.view.WindowManager;
Alan Viverette7c9746d4e2014-11-19 17:02:16 -080047import android.view.WindowManagerImpl;
svetoslavganov75986cf2009-05-14 22:28:01 -070048import android.view.accessibility.AccessibilityEvent;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -080049import android.view.accessibility.AccessibilityInteractionClient;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070050import android.view.accessibility.AccessibilityNodeInfo;
Hongming Jin8302c6c2020-01-10 17:45:18 -080051import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Svetoslav8e3feb12014-02-24 13:46:47 -080052import android.view.accessibility.AccessibilityWindowInfo;
svetoslavganov75986cf2009-05-14 22:28:01 -070053
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -080054import com.android.internal.os.HandlerCaller;
Svetoslav3a5c7212014-10-14 09:54:26 -070055import com.android.internal.os.SomeArgs;
Jacky Kao09789e42020-01-15 16:23:52 +080056import com.android.internal.util.Preconditions;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -080057
Anna Galusza9b278112016-01-04 11:37:37 -080058import java.lang.annotation.Retention;
59import java.lang.annotation.RetentionPolicy;
Hongming Jin8302c6c2020-01-10 17:45:18 -080060import java.util.Collections;
Svetoslav8e3feb12014-02-24 13:46:47 -080061import java.util.List;
Jacky Kao09789e42020-01-15 16:23:52 +080062import java.util.concurrent.Executor;
63import java.util.function.Consumer;
Svetoslav8e3feb12014-02-24 13:46:47 -080064
svetoslavganov75986cf2009-05-14 22:28:01 -070065/**
Phil Weaver752047d2016-09-08 10:35:49 -070066 * Accessibility services should only be used to assist users with disabilities in using
Phil Weaver40ded282016-01-25 15:49:02 -080067 * Android devices and apps. They run in the background and receive callbacks by the system
svetoslavganov75986cf2009-05-14 22:28:01 -070068 * when {@link AccessibilityEvent}s are fired. Such events denote some state transition
69 * in the user interface, for example, the focus has changed, a button has been clicked,
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070070 * etc. Such a service can optionally request the capability for querying the content
Scott Mainb303d832011-10-12 16:45:18 -070071 * of the active window. Development of an accessibility service requires extending this
72 * class and implementing its abstract methods.
Joe Fernandeze1302ed2012-02-06 14:30:15 -080073 *
74 * <div class="special reference">
75 * <h3>Developer Guides</h3>
76 * <p>For more information about creating AccessibilityServices, read the
77 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
78 * developer guide.</p>
79 * </div>
80 *
Scott Mainb303d832011-10-12 16:45:18 -070081 * <h3>Lifecycle</h3>
svetoslavganov75986cf2009-05-14 22:28:01 -070082 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070083 * The lifecycle of an accessibility service is managed exclusively by the system and
Phil Weaver40ded282016-01-25 15:49:02 -080084 * follows the established service life cycle. Starting an accessibility service is triggered
85 * exclusively by the user explicitly turning the service on in device settings. After the system
86 * binds to a service, it calls {@link AccessibilityService#onServiceConnected()}. This method can
koprivadebd4ee2018-09-13 10:59:46 -070087 * be overridden by clients that want to perform post binding setup.
Phil Weaver40ded282016-01-25 15:49:02 -080088 * </p>
89 * <p>
90 * An accessibility service stops either when the user turns it off in device settings or when
91 * it calls {@link AccessibilityService#disableSelf()}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070092 * </p>
Scott Mainb303d832011-10-12 16:45:18 -070093 * <h3>Declaration</h3>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070094 * <p>
Phil Weaver40ded282016-01-25 15:49:02 -080095 * An accessibility is declared as any other service in an AndroidManifest.xml, but it
96 * must do two things:
97 * <ul>
98 * <ol>
99 * Specify that it handles the "android.accessibilityservice.AccessibilityService"
100 * {@link android.content.Intent}.
101 * </ol>
102 * <ol>
103 * Request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to
104 * ensure that only the system can bind to it.
105 * </ol>
106 * </ul>
107 * If either of these items is missing, the system will ignore the accessibility service.
108 * Following is an example declaration:
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700109 * </p>
Svetoslav Ganov53e184d2012-05-16 15:57:10 -0700110 * <pre> &lt;service android:name=".MyAccessibilityService"
Scott Main53b0fda2012-08-06 12:50:48 -0700111 * android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"&gt;
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700112 * &lt;intent-filter&gt;
Scott Mainb303d832011-10-12 16:45:18 -0700113 * &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700114 * &lt;/intent-filter&gt;
115 * . . .
Scott Mainb303d832011-10-12 16:45:18 -0700116 * &lt;/service&gt;</pre>
117 * <h3>Configuration</h3>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700118 * <p>
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700119 * An accessibility service can be configured to receive specific types of accessibility events,
120 * listen only to specific packages, get events from each type only once in a given time frame,
121 * retrieve window content, specify a settings activity, etc.
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700122 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700123 * <p>
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700124 * There are two approaches for configuring an accessibility service:
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700125 * </p>
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700126 * <ul>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700127 * <li>
128 * Providing a {@link #SERVICE_META_DATA meta-data} entry in the manifest when declaring
129 * the service. A service declaration with a meta-data tag is presented below:
Scott Mainb303d832011-10-12 16:45:18 -0700130 * <pre> &lt;service android:name=".MyAccessibilityService"&gt;
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700131 * &lt;intent-filter&gt;
Scott Mainb303d832011-10-12 16:45:18 -0700132 * &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700133 * &lt;/intent-filter&gt;
134 * &lt;meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice" /&gt;
Scott Mainb303d832011-10-12 16:45:18 -0700135 * &lt;/service&gt;</pre>
136 * <p class="note">
137 * <strong>Note:</strong> This approach enables setting all properties.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700138 * </p>
139 * <p>
140 * For more details refer to {@link #SERVICE_META_DATA} and
Scott Mainb303d832011-10-12 16:45:18 -0700141 * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700142 * </p>
143 * </li>
144 * <li>
145 * Calling {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}. Note
146 * that this method can be called any time to dynamically change the service configuration.
Scott Mainb303d832011-10-12 16:45:18 -0700147 * <p class="note">
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700148 * <strong>Note:</strong> This approach enables setting only dynamically configurable properties:
149 * {@link AccessibilityServiceInfo#eventTypes},
150 * {@link AccessibilityServiceInfo#feedbackType},
151 * {@link AccessibilityServiceInfo#flags},
152 * {@link AccessibilityServiceInfo#notificationTimeout},
153 * {@link AccessibilityServiceInfo#packageNames}
154 * </p>
155 * <p>
156 * For more details refer to {@link AccessibilityServiceInfo}.
157 * </p>
158 * </li>
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700159 * </ul>
Scott Mainb303d832011-10-12 16:45:18 -0700160 * <h3>Retrieving window content</h3>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700161 * <p>
Phil Weaver40ded282016-01-25 15:49:02 -0800162 * A service can specify in its declaration that it can retrieve window
163 * content which is represented as a tree of {@link AccessibilityWindowInfo} and
164 * {@link AccessibilityNodeInfo} objects. Note that
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700165 * declaring this capability requires that the service declares its configuration via
166 * an XML resource referenced by {@link #SERVICE_META_DATA}.
167 * </p>
168 * <p>
Phil Weaver40ded282016-01-25 15:49:02 -0800169 * Window content may be retrieved with
170 * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()},
171 * {@link AccessibilityService#findFocus(int)},
172 * {@link AccessibilityService#getWindows()}, or
173 * {@link AccessibilityService#getRootInActiveWindow()}.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700174 * </p>
Scott Mainb303d832011-10-12 16:45:18 -0700175 * <p class="note">
176 * <strong>Note</strong> An accessibility service may have requested to be notified for
Phil Weaver40ded282016-01-25 15:49:02 -0800177 * a subset of the event types, and thus be unaware when the node hierarchy has changed. It is also
178 * possible for a node to contain outdated information because the window content may change at any
179 * time.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700180 * </p>
Scott Mainb303d832011-10-12 16:45:18 -0700181 * <h3>Notification strategy</h3>
svetoslavganov75986cf2009-05-14 22:28:01 -0700182 * <p>
Phil Weaver14ed6cf2015-11-20 14:46:28 -0800183 * All accessibility services are notified of all events they have requested, regardless of their
184 * feedback type.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700185 * </p>
Scott Mainb303d832011-10-12 16:45:18 -0700186 * <p class="note">
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700187 * <strong>Note:</strong> The event notification timeout is useful to avoid propagating
188 * events to the client too frequently since this is accomplished via an expensive
189 * interprocess call. One can think of the timeout as a criteria to determine when
Scott Mainb303d832011-10-12 16:45:18 -0700190 * event generation has settled down.</p>
191 * <h3>Event types</h3>
192 * <ul>
Svetoslav8e3feb12014-02-24 13:46:47 -0800193 * <li>{@link AccessibilityEvent#TYPE_VIEW_CLICKED}</li>
194 * <li>{@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}</li>
195 * <li>{@link AccessibilityEvent#TYPE_VIEW_FOCUSED}</li>
196 * <li>{@link AccessibilityEvent#TYPE_VIEW_SELECTED}</li>
197 * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}</li>
198 * <li>{@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}</li>
199 * <li>{@link AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED}</li>
200 * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START}</li>
201 * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END}</li>
202 * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}</li>
203 * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}</li>
204 * <li>{@link AccessibilityEvent#TYPE_VIEW_SCROLLED}</li>
205 * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED}</li>
206 * <li>{@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}</li>
207 * <li>{@link AccessibilityEvent#TYPE_ANNOUNCEMENT}</li>
208 * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_START}</li>
209 * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_END}</li>
210 * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_START}</li>
211 * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_END}</li>
212 * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED}</li>
213 * <li>{@link AccessibilityEvent#TYPE_WINDOWS_CHANGED}</li>
214 * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED}</li>
Scott Mainb303d832011-10-12 16:45:18 -0700215 * </ul>
216 * <h3>Feedback types</h3>
217 * <ul>
Svetoslav8e3feb12014-02-24 13:46:47 -0800218 * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li>
219 * <li>{@link AccessibilityServiceInfo#FEEDBACK_HAPTIC}</li>
220 * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li>
221 * <li>{@link AccessibilityServiceInfo#FEEDBACK_VISUAL}</li>
222 * <li>{@link AccessibilityServiceInfo#FEEDBACK_GENERIC}</li>
223 * <li>{@link AccessibilityServiceInfo#FEEDBACK_BRAILLE}</li>
Scott Mainb303d832011-10-12 16:45:18 -0700224 * </ul>
225 * @see AccessibilityEvent
226 * @see AccessibilityServiceInfo
227 * @see android.view.accessibility.AccessibilityManager
svetoslavganov75986cf2009-05-14 22:28:01 -0700228 */
229public abstract class AccessibilityService extends Service {
Svetoslav Ganov42138042012-03-20 11:51:39 -0700230
231 /**
232 * The user has performed a swipe up gesture on the touch screen.
233 */
234 public static final int GESTURE_SWIPE_UP = 1;
235
236 /**
237 * The user has performed a swipe down gesture on the touch screen.
238 */
239 public static final int GESTURE_SWIPE_DOWN = 2;
240
241 /**
242 * The user has performed a swipe left gesture on the touch screen.
243 */
244 public static final int GESTURE_SWIPE_LEFT = 3;
245
246 /**
247 * The user has performed a swipe right gesture on the touch screen.
248 */
249 public static final int GESTURE_SWIPE_RIGHT = 4;
250
251 /**
252 * The user has performed a swipe left and right gesture on the touch screen.
253 */
254 public static final int GESTURE_SWIPE_LEFT_AND_RIGHT = 5;
255
256 /**
257 * The user has performed a swipe right and left gesture on the touch screen.
258 */
259 public static final int GESTURE_SWIPE_RIGHT_AND_LEFT = 6;
260
261 /**
262 * The user has performed a swipe up and down gesture on the touch screen.
263 */
264 public static final int GESTURE_SWIPE_UP_AND_DOWN = 7;
265
266 /**
267 * The user has performed a swipe down and up gesture on the touch screen.
268 */
269 public static final int GESTURE_SWIPE_DOWN_AND_UP = 8;
270
271 /**
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700272 * The user has performed a left and up gesture on the touch screen.
273 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700274 public static final int GESTURE_SWIPE_LEFT_AND_UP = 9;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700275
276 /**
277 * The user has performed a left and down gesture on the touch screen.
278 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700279 public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 10;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700280
281 /**
282 * The user has performed a right and up gesture on the touch screen.
283 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700284 public static final int GESTURE_SWIPE_RIGHT_AND_UP = 11;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700285
286 /**
287 * The user has performed a right and down gesture on the touch screen.
288 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700289 public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 12;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700290
291 /**
292 * The user has performed an up and left gesture on the touch screen.
293 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700294 public static final int GESTURE_SWIPE_UP_AND_LEFT = 13;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700295
296 /**
297 * The user has performed an up and right gesture on the touch screen.
298 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700299 public static final int GESTURE_SWIPE_UP_AND_RIGHT = 14;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700300
301 /**
302 * The user has performed an down and left gesture on the touch screen.
303 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700304 public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 15;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700305
306 /**
307 * The user has performed an down and right gesture on the touch screen.
308 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700309 public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 16;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700310
311 /**
Ameer Armaly51106a32019-09-17 14:40:36 -0700312 * The user has performed a double tap gesture on the touch screen.
Ameer Armaly51106a32019-09-17 14:40:36 -0700313 */
314 public static final int GESTURE_DOUBLE_TAP = 17;
315
316 /**
317 * The user has performed a double tap and hold gesture on the touch screen.
Ameer Armaly51106a32019-09-17 14:40:36 -0700318 */
319 public static final int GESTURE_DOUBLE_TAP_AND_HOLD = 18;
320
321 /**
svetoslavganov75986cf2009-05-14 22:28:01 -0700322 * The {@link Intent} that must be declared as handled by the service.
323 */
324 public static final String SERVICE_INTERFACE =
325 "android.accessibilityservice.AccessibilityService";
326
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700327 /**
328 * Name under which an AccessibilityService component publishes information
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700329 * about itself. This meta-data must reference an XML resource containing an
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700330 * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>
Kevin Hufnagleb0becb22019-07-18 20:20:32 +0000331 * tag. This is a sample XML file configuring an accessibility service:
Scott Mainb303d832011-10-12 16:45:18 -0700332 * <pre> &lt;accessibility-service
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700333 * android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
334 * android:packageNames="foo.bar, foo.baz"
335 * android:accessibilityFeedbackType="feedbackSpoken"
336 * android:notificationTimeout="100"
337 * android:accessibilityFlags="flagDefault"
338 * android:settingsActivity="foo.bar.TestBackActivity"
339 * android:canRetrieveWindowContent="true"
Svetoslav688a6972013-04-16 18:55:38 -0700340 * android:canRequestTouchExplorationMode="true"
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700341 * . . .
Scott Mainb303d832011-10-12 16:45:18 -0700342 * /&gt;</pre>
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700343 */
344 public static final String SERVICE_META_DATA = "android.accessibilityservice";
345
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700346 /**
347 * Action to go back.
348 */
349 public static final int GLOBAL_ACTION_BACK = 1;
350
351 /**
352 * Action to go home.
353 */
354 public static final int GLOBAL_ACTION_HOME = 2;
355
356 /**
Phil Weaver3cdd6c72016-11-03 15:28:03 -0700357 * Action to toggle showing the overview of recent apps. Will fail on platforms that don't
358 * show recent apps.
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700359 */
360 public static final int GLOBAL_ACTION_RECENTS = 3;
361
362 /**
363 * Action to open the notifications.
364 */
365 public static final int GLOBAL_ACTION_NOTIFICATIONS = 4;
366
Svetoslav Ganove20a1772012-09-25 16:07:46 -0700367 /**
368 * Action to open the quick settings.
369 */
370 public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5;
371
Alan Viverettee34560b22014-07-10 14:50:06 -0700372 /**
373 * Action to open the power long-press dialog.
374 */
375 public static final int GLOBAL_ACTION_POWER_DIALOG = 6;
376
Phil Weaver315c34e2016-02-19 15:12:29 -0800377 /**
378 * Action to toggle docking the current app's window
379 */
380 public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7;
381
Eugene Suslaf9a651d2017-10-11 12:06:27 -0700382 /**
383 * Action to lock the screen
384 */
385 public static final int GLOBAL_ACTION_LOCK_SCREEN = 8;
386
Phil Weaverd0429742018-01-16 15:32:30 -0800387 /**
388 * Action to take a screenshot
389 */
390 public static final int GLOBAL_ACTION_TAKE_SCREENSHOT = 9;
391
svetoslavganov75986cf2009-05-14 22:28:01 -0700392 private static final String LOG_TAG = "AccessibilityService";
393
Svetoslav Ganov80943d82013-01-02 10:25:37 -0800394 /**
Hongming Jin8302c6c2020-01-10 17:45:18 -0800395 * Interface used by IAccessibilityServiceClientWrapper to call the service from its main
396 * thread.
Svetoslav Ganov80943d82013-01-02 10:25:37 -0800397 * @hide
398 */
399 public interface Callbacks {
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800400 void onAccessibilityEvent(AccessibilityEvent event);
401 void onInterrupt();
402 void onServiceConnected();
403 void init(int connectionId, IBinder windowToken);
RyanlwLina0daddd2019-06-19 11:39:01 +0800404 /** The detected gesture information for different displays */
RyanlwLin0d17f042019-09-02 21:22:09 +0800405 boolean onGesture(AccessibilityGestureEvent gestureInfo);
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800406 boolean onKeyEvent(KeyEvent event);
Rhed Jao02655dc2018-10-30 20:44:52 +0800407 /** Magnification changed callbacks for different displays */
408 void onMagnificationChanged(int displayId, @NonNull Region region,
Alan Viverette214fb682015-11-17 09:47:11 -0500409 float scale, float centerX, float centerY);
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800410 void onSoftKeyboardShowModeChanged(int showMode);
411 void onPerformGestureResult(int sequence, boolean completedSuccessfully);
412 void onFingerprintCapturingGesturesChanged(boolean active);
413 void onFingerprintGesture(int gesture);
minchelia52af2c2019-07-02 11:38:21 +0800414 /** Accessbility button clicked callbacks for different displays */
415 void onAccessibilityButtonClicked(int displayId);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800416 void onAccessibilityButtonAvailabilityChanged(boolean available);
Hongming Jin8302c6c2020-01-10 17:45:18 -0800417 /** This is called when the system action list is changed. */
418 void onSystemActionsChanged();
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800419 }
svetoslavganov75986cf2009-05-14 22:28:01 -0700420
Anna Galusza9b278112016-01-04 11:37:37 -0800421 /**
422 * Annotations for Soft Keyboard show modes so tools can catch invalid show modes.
423 * @hide
424 */
425 @Retention(RetentionPolicy.SOURCE)
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700426 @IntDef(prefix = { "SHOW_MODE_" }, value = {
427 SHOW_MODE_AUTO,
Phil Weaver03a65b02018-07-19 16:07:57 -0700428 SHOW_MODE_HIDDEN,
Phil Weavere05fba42018-09-04 13:36:00 -0700429 SHOW_MODE_IGNORE_HARD_KEYBOARD
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700430 })
431 public @interface SoftKeyboardShowMode {}
432
Phil Weaver03a65b02018-07-19 16:07:57 -0700433 /**
434 * Allow the system to control when the soft keyboard is shown.
435 * @see SoftKeyboardController
436 */
Anna Galusza9b278112016-01-04 11:37:37 -0800437 public static final int SHOW_MODE_AUTO = 0;
Phil Weaver03a65b02018-07-19 16:07:57 -0700438
439 /**
440 * Never show the soft keyboard.
441 * @see SoftKeyboardController
442 */
Anna Galusza9b278112016-01-04 11:37:37 -0800443 public static final int SHOW_MODE_HIDDEN = 1;
444
Phil Weaver03a65b02018-07-19 16:07:57 -0700445 /**
446 * Allow the soft keyboard to be shown, even if a hard keyboard is connected
447 * @see SoftKeyboardController
448 */
Phil Weavere05fba42018-09-04 13:36:00 -0700449 public static final int SHOW_MODE_IGNORE_HARD_KEYBOARD = 2;
Phil Weaver03a65b02018-07-19 16:07:57 -0700450
451 /**
452 * Mask used to cover the show modes supported in public API
453 * @hide
454 */
455 public static final int SHOW_MODE_MASK = 0x03;
456
457 /**
458 * Bit used to hold the old value of the hard IME setting to restore when a service is shut
459 * down.
460 * @hide
461 */
462 public static final int SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE = 0x20000000;
463
464 /**
465 * Bit for show mode setting to indicate that the user has overridden the hard keyboard
466 * behavior.
467 * @hide
468 */
469 public static final int SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN = 0x40000000;
470
Phil Weaver6f2da202017-09-05 16:00:38 -0700471 private int mConnectionId = AccessibilityInteractionClient.NO_ID;
svetoslavganov75986cf2009-05-14 22:28:01 -0700472
Mathew Inwood29b2e912018-08-01 14:21:18 +0100473 @UnsupportedAppUsage
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800474 private AccessibilityServiceInfo mInfo;
475
Mathew Inwood8c854f82018-09-14 12:35:36 +0100476 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Svetoslav3a5c7212014-10-14 09:54:26 -0700477 private IBinder mWindowToken;
478
479 private WindowManager mWindowManager;
480
Rhed Jao02655dc2018-10-30 20:44:52 +0800481 /** List of magnification controllers, mapping from displayId -> MagnificationController. */
482 private final SparseArray<MagnificationController> mMagnificationControllers =
483 new SparseArray<>(0);
Anna Galusza9b278112016-01-04 11:37:37 -0800484 private SoftKeyboardController mSoftKeyboardController;
minchelia52af2c2019-07-02 11:38:21 +0800485 private final SparseArray<AccessibilityButtonController> mAccessibilityButtonControllers =
486 new SparseArray<>(0);
Alan Viverette214fb682015-11-17 09:47:11 -0500487
Phil Weavera6b64f52015-12-04 15:21:35 -0800488 private int mGestureStatusCallbackSequence;
489
490 private SparseArray<GestureResultCallbackInfo> mGestureStatusCallbackInfos;
491
492 private final Object mLock = new Object();
493
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800494 private FingerprintGestureController mFingerprintGestureController;
495
Jacky Kao09789e42020-01-15 16:23:52 +0800496 /** @hide */
497 public static final String KEY_ACCESSIBILITY_SCREENSHOT = "screenshot";
498
svetoslavganov75986cf2009-05-14 22:28:01 -0700499 /**
500 * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
501 *
Phil Weaver96fea022016-03-08 13:05:10 -0800502 * @param event The new event. This event is owned by the caller and cannot be used after
503 * this method returns. Services wishing to use the event after this method returns should
504 * make a copy.
svetoslavganov75986cf2009-05-14 22:28:01 -0700505 */
Phil Weavere2319862017-02-23 18:51:34 +0000506 public abstract void onAccessibilityEvent(AccessibilityEvent event);
svetoslavganov75986cf2009-05-14 22:28:01 -0700507
508 /**
509 * Callback for interrupting the accessibility feedback.
510 */
Phil Weavere2319862017-02-23 18:51:34 +0000511 public abstract void onInterrupt();
svetoslavganov75986cf2009-05-14 22:28:01 -0700512
513 /**
Alan Viverette214fb682015-11-17 09:47:11 -0500514 * Dispatches service connection to internal components first, then the
515 * client code.
516 */
517 private void dispatchServiceConnected() {
Rhed Jao02655dc2018-10-30 20:44:52 +0800518 synchronized (mLock) {
519 for (int i = 0; i < mMagnificationControllers.size(); i++) {
520 mMagnificationControllers.valueAt(i).onServiceConnectedLocked();
521 }
Alan Viverette214fb682015-11-17 09:47:11 -0500522 }
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800523 if (mSoftKeyboardController != null) {
524 mSoftKeyboardController.onServiceConnected();
525 }
Alan Viverette214fb682015-11-17 09:47:11 -0500526
527 // The client gets to handle service connection last, after we've set
528 // up any state upon which their code may rely.
529 onServiceConnected();
530 }
531
532 /**
svetoslavganov75986cf2009-05-14 22:28:01 -0700533 * This method is a part of the {@link AccessibilityService} lifecycle and is
534 * called after the system has successfully bound to the service. If is
535 * convenient to use this method for setting the {@link AccessibilityServiceInfo}.
536 *
537 * @see AccessibilityServiceInfo
538 * @see #setServiceInfo(AccessibilityServiceInfo)
539 */
540 protected void onServiceConnected() {
541
542 }
543
544 /**
RyanlwLin0d17f042019-09-02 21:22:09 +0800545 * Called by {@link #onGesture(AccessibilityGestureEvent)} when the user performs a specific
RyanlwLina0daddd2019-06-19 11:39:01 +0800546 * gesture on the default display.
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700547 *
Svetoslav Ganove4abc512012-05-09 11:02:38 -0700548 * <strong>Note:</strong> To receive gestures an accessibility service must
549 * request that the device is in touch exploration mode by setting the
RyanlwLina0daddd2019-06-19 11:39:01 +0800550 * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}
Svetoslav Ganove4abc512012-05-09 11:02:38 -0700551 * flag.
Svetoslav Ganov42138042012-03-20 11:51:39 -0700552 *
553 * @param gestureId The unique id of the performed gesture.
554 *
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700555 * @return Whether the gesture was handled.
RyanlwLin0d17f042019-09-02 21:22:09 +0800556 * @deprecated Override {@link #onGesture(AccessibilityGestureEvent)} instead.
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700557 *
Svetoslav Ganov42138042012-03-20 11:51:39 -0700558 * @see #GESTURE_SWIPE_UP
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700559 * @see #GESTURE_SWIPE_UP_AND_LEFT
Svetoslav Ganov42138042012-03-20 11:51:39 -0700560 * @see #GESTURE_SWIPE_UP_AND_DOWN
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700561 * @see #GESTURE_SWIPE_UP_AND_RIGHT
562 * @see #GESTURE_SWIPE_DOWN
563 * @see #GESTURE_SWIPE_DOWN_AND_LEFT
Svetoslav Ganov42138042012-03-20 11:51:39 -0700564 * @see #GESTURE_SWIPE_DOWN_AND_UP
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700565 * @see #GESTURE_SWIPE_DOWN_AND_RIGHT
566 * @see #GESTURE_SWIPE_LEFT
567 * @see #GESTURE_SWIPE_LEFT_AND_UP
Svetoslav Ganov42138042012-03-20 11:51:39 -0700568 * @see #GESTURE_SWIPE_LEFT_AND_RIGHT
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700569 * @see #GESTURE_SWIPE_LEFT_AND_DOWN
570 * @see #GESTURE_SWIPE_RIGHT
571 * @see #GESTURE_SWIPE_RIGHT_AND_UP
Svetoslav Ganov42138042012-03-20 11:51:39 -0700572 * @see #GESTURE_SWIPE_RIGHT_AND_LEFT
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700573 * @see #GESTURE_SWIPE_RIGHT_AND_DOWN
Svetoslav Ganov42138042012-03-20 11:51:39 -0700574 */
RyanlwLina0daddd2019-06-19 11:39:01 +0800575 @Deprecated
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700576 protected boolean onGesture(int gestureId) {
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700577 return false;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700578 }
579
580 /**
RyanlwLina0daddd2019-06-19 11:39:01 +0800581 * Called by the system when the user performs a specific gesture on the
582 * specific touch screen.
583 *<p>
584 * <strong>Note:</strong> To receive gestures an accessibility service must
585 * request that the device is in touch exploration mode by setting the
586 * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}
587 * flag.
588 *<p>
589 * <strong>Note:</strong> The default implementation calls {@link #onGesture(int)} when the
590 * touch screen is default display.
591 *
RyanlwLin0d17f042019-09-02 21:22:09 +0800592 * @param gestureEvent The information of gesture.
RyanlwLina0daddd2019-06-19 11:39:01 +0800593 *
594 * @return Whether the gesture was handled.
595 *
596 */
RyanlwLin0d17f042019-09-02 21:22:09 +0800597 public boolean onGesture(@NonNull AccessibilityGestureEvent gestureEvent) {
598 if (gestureEvent.getDisplayId() == Display.DEFAULT_DISPLAY) {
599 onGesture(gestureEvent.getGestureId());
RyanlwLina0daddd2019-06-19 11:39:01 +0800600 }
601 return false;
602 }
603
604 /**
Svetoslavc4fccd12013-04-09 12:58:41 -0700605 * Callback that allows an accessibility service to observe the key events
606 * before they are passed to the rest of the system. This means that the events
607 * are first delivered here before they are passed to the device policy, the
608 * input method, or applications.
609 * <p>
610 * <strong>Note:</strong> It is important that key events are handled in such
611 * a way that the event stream that would be passed to the rest of the system
612 * is well-formed. For example, handling the down event but not the up event
613 * and vice versa would generate an inconsistent event stream.
614 * </p>
615 * <p>
616 * <strong>Note:</strong> The key events delivered in this method are copies
617 * and modifying them will have no effect on the events that will be passed
618 * to the system. This method is intended to perform purely filtering
619 * functionality.
620 * <p>
621 *
Phil Weaver96fea022016-03-08 13:05:10 -0800622 * @param event The event to be processed. This event is owned by the caller and cannot be used
623 * after this method returns. Services wishing to use the event after this method returns should
624 * make a copy.
Svetoslavc4fccd12013-04-09 12:58:41 -0700625 * @return If true then the event will be consumed and not delivered to
626 * applications, otherwise it will be delivered as usual.
627 */
628 protected boolean onKeyEvent(KeyEvent event) {
629 return false;
630 }
631
632 /**
Jacky Kaoc7be7b52019-09-27 16:14:16 +0800633 * Gets the windows on the screen of the default display. This method returns only the windows
Svetoslav8e3feb12014-02-24 13:46:47 -0800634 * that a sighted user can interact with, as opposed to all windows.
635 * For example, if there is a modal dialog shown and the user cannot touch
636 * anything behind it, then only the modal window will be reported
637 * (assuming it is the top one). For convenience the returned windows
638 * are ordered in a descending layer order, which is the windows that
Eugene Suslaf40da1a2018-02-26 10:41:28 -0800639 * are on top are reported first. Since the user can always
Svetoslavf7174e82014-06-12 11:29:35 -0700640 * interact with the window that has input focus by typing, the focused
641 * window is always returned (even if covered by a modal window).
Svetoslav8e3feb12014-02-24 13:46:47 -0800642 * <p>
643 * <strong>Note:</strong> In order to access the windows your service has
644 * to declare the capability to retrieve window content by setting the
645 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
646 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
647 * Also the service has to opt-in to retrieve the interactive windows by
648 * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
649 * flag.
650 * </p>
651 *
652 * @return The windows if there are windows and the service is can retrieve
653 * them, otherwise an empty list.
654 */
655 public List<AccessibilityWindowInfo> getWindows() {
656 return AccessibilityInteractionClient.getInstance().getWindows(mConnectionId);
657 }
658
659 /**
Jacky Kaoc7be7b52019-09-27 16:14:16 +0800660 * Gets the windows on the screen of all displays. This method returns only the windows
661 * that a sighted user can interact with, as opposed to all windows.
662 * For example, if there is a modal dialog shown and the user cannot touch
663 * anything behind it, then only the modal window will be reported
664 * (assuming it is the top one). For convenience the returned windows
665 * are ordered in a descending layer order, which is the windows that
666 * are on top are reported first. Since the user can always
667 * interact with the window that has input focus by typing, the focused
668 * window is always returned (even if covered by a modal window).
669 * <p>
670 * <strong>Note:</strong> In order to access the windows your service has
671 * to declare the capability to retrieve window content by setting the
672 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
673 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
674 * Also the service has to opt-in to retrieve the interactive windows by
675 * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
676 * flag.
677 * </p>
678 *
679 * @return The windows of all displays if there are windows and the service is can retrieve
680 * them, otherwise an empty list. The key of SparseArray is display ID.
681 */
682 @NonNull
683 public final SparseArray<List<AccessibilityWindowInfo>> getWindowsOnAllDisplays() {
684 return AccessibilityInteractionClient.getInstance().getWindowsOnAllDisplays(mConnectionId);
685 }
686
687 /**
Svetoslav Ganov0846e292012-04-18 18:47:13 -0700688 * Gets the root node in the currently active window if this service
Svetoslav8e3feb12014-02-24 13:46:47 -0800689 * can retrieve window content. The active window is the one that the user
690 * is currently touching or the window with input focus, if the user is not
RyanlwLined124d02019-08-27 14:06:18 +0800691 * touching any window. It could be from any logical display.
Svetoslav8e3feb12014-02-24 13:46:47 -0800692 * <p>
Phil Weaver40ded282016-01-25 15:49:02 -0800693 * The currently active window is defined as the window that most recently fired one
694 * of the following events:
695 * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
696 * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
697 * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}.
698 * In other words, the last window shown that also has input focus.
699 * </p>
700 * <p>
Svetoslav8e3feb12014-02-24 13:46:47 -0800701 * <strong>Note:</strong> In order to access the root node your service has
702 * to declare the capability to retrieve window content by setting the
703 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
704 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
705 * </p>
Svetoslav Ganov0846e292012-04-18 18:47:13 -0700706 *
707 * @return The root node if this service can retrieve window content.
708 */
709 public AccessibilityNodeInfo getRootInActiveWindow() {
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700710 return AccessibilityInteractionClient.getInstance().getRootInActiveWindow(mConnectionId);
Svetoslav Ganov0846e292012-04-18 18:47:13 -0700711 }
712
713 /**
Phil Weaver40ded282016-01-25 15:49:02 -0800714 * Disables the service. After calling this method, the service will be disabled and settings
715 * will show that it is turned off.
Jinsong Mua9e7a3b2015-12-14 15:58:41 -0800716 */
717 public final void disableSelf() {
718 final IAccessibilityServiceConnection connection =
719 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
720 if (connection != null) {
721 try {
722 connection.disableSelf();
723 } catch (RemoteException re) {
724 throw new RuntimeException(re);
725 }
726 }
727 }
728
mincheli5f435e72019-06-24 16:49:50 +0800729 @Override
730 public Context createDisplayContext(Display display) {
731 final Context context = super.createDisplayContext(display);
732 final int displayId = display.getDisplayId();
733 setDefaultTokenInternal(context, displayId);
734 return context;
735 }
736
737 private void setDefaultTokenInternal(Context context, int displayId) {
738 final WindowManagerImpl wm = (WindowManagerImpl) context.getSystemService(WINDOW_SERVICE);
739 final IAccessibilityServiceConnection connection =
740 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
741 IBinder token = null;
742 if (connection != null) {
743 synchronized (mLock) {
744 try {
745 token = connection.getOverlayWindowToken(displayId);
746 } catch (RemoteException re) {
747 Log.w(LOG_TAG, "Failed to get window token", re);
748 re.rethrowFromSystemServer();
749 }
750 }
751 wm.setDefaultToken(token);
752 }
753 }
754
Jinsong Mua9e7a3b2015-12-14 15:58:41 -0800755 /**
Alan Viverette214fb682015-11-17 09:47:11 -0500756 * Returns the magnification controller, which may be used to query and
757 * modify the state of display magnification.
758 * <p>
759 * <strong>Note:</strong> In order to control magnification, your service
760 * must declare the capability by setting the
761 * {@link android.R.styleable#AccessibilityService_canControlMagnification}
762 * property in its meta-data. For more information, see
763 * {@link #SERVICE_META_DATA}.
764 *
765 * @return the magnification controller
766 */
767 @NonNull
768 public final MagnificationController getMagnificationController() {
Rhed Jao02655dc2018-10-30 20:44:52 +0800769 return getMagnificationController(Display.DEFAULT_DISPLAY);
770 }
771
772 /**
773 * Returns the magnification controller of specified logical display, which may be used to
774 * query and modify the state of display magnification.
775 * <p>
776 * <strong>Note:</strong> In order to control magnification, your service
777 * must declare the capability by setting the
778 * {@link android.R.styleable#AccessibilityService_canControlMagnification}
779 * property in its meta-data. For more information, see
780 * {@link #SERVICE_META_DATA}.
781 *
782 * @param displayId The logic display id, use {@link Display#DEFAULT_DISPLAY} for
783 * default display.
784 * @return the magnification controller
785 *
786 * @hide
787 */
788 @NonNull
789 public final MagnificationController getMagnificationController(int displayId) {
Anna Galusza9b278112016-01-04 11:37:37 -0800790 synchronized (mLock) {
Rhed Jao02655dc2018-10-30 20:44:52 +0800791 MagnificationController controller = mMagnificationControllers.get(displayId);
792 if (controller == null) {
793 controller = new MagnificationController(this, mLock, displayId);
794 mMagnificationControllers.put(displayId, controller);
Anna Galusza9b278112016-01-04 11:37:37 -0800795 }
Rhed Jao02655dc2018-10-30 20:44:52 +0800796 return controller;
Alan Viverette214fb682015-11-17 09:47:11 -0500797 }
Alan Viverette214fb682015-11-17 09:47:11 -0500798 }
799
Phil Weavera6b64f52015-12-04 15:21:35 -0800800 /**
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800801 * Get the controller for fingerprint gestures. This feature requires {@link
Jeff Sharkey67f9d502017-08-05 13:49:13 -0600802 * AccessibilityServiceInfo#CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES}.
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800803 *
804 *<strong>Note: </strong> The service must be connected before this method is called.
805 *
806 * @return The controller for fingerprint gestures, or {@code null} if gestures are unavailable.
807 */
808 @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT)
Phil Weaverbe2922f2017-04-28 14:58:35 -0700809 public final @NonNull FingerprintGestureController getFingerprintGestureController() {
810 if (mFingerprintGestureController == null) {
811 mFingerprintGestureController = new FingerprintGestureController(
812 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId));
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800813 }
814 return mFingerprintGestureController;
815 }
816
817 /**
Phil Weavera6b64f52015-12-04 15:21:35 -0800818 * Dispatch a gesture to the touch screen. Any gestures currently in progress, whether from
819 * the user, this service, or another service, will be cancelled.
820 * <p>
Phil Weaver155dda12016-04-07 11:06:02 -0700821 * The gesture will be dispatched as if it were performed directly on the screen by a user, so
822 * the events may be affected by features such as magnification and explore by touch.
823 * </p>
824 * <p>
Phil Weavera6b64f52015-12-04 15:21:35 -0800825 * <strong>Note:</strong> In order to dispatch gestures, your service
826 * must declare the capability by setting the
827 * {@link android.R.styleable#AccessibilityService_canPerformGestures}
828 * property in its meta-data. For more information, see
829 * {@link #SERVICE_META_DATA}.
Phil Weaver155dda12016-04-07 11:06:02 -0700830 * </p>
Phil Weavera6b64f52015-12-04 15:21:35 -0800831 *
832 * @param gesture The gesture to dispatch
833 * @param callback The object to call back when the status of the gesture is known. If
834 * {@code null}, no status is reported.
835 * @param handler The handler on which to call back the {@code callback} object. If
836 * {@code null}, the object is called back on the service's main thread.
837 *
838 * @return {@code true} if the gesture is dispatched, {@code false} if not.
839 */
840 public final boolean dispatchGesture(@NonNull GestureDescription gesture,
841 @Nullable GestureResultCallback callback,
842 @Nullable Handler handler) {
843 final IAccessibilityServiceConnection connection =
844 AccessibilityInteractionClient.getInstance().getConnection(
845 mConnectionId);
846 if (connection == null) {
847 return false;
848 }
Phil Weavera8918f22016-08-05 11:23:50 -0700849 List<GestureDescription.GestureStep> steps =
850 MotionEventGenerator.getGestureStepsFromGestureDescription(gesture, 100);
Phil Weavera6b64f52015-12-04 15:21:35 -0800851 try {
852 synchronized (mLock) {
Phil Weaver78d2e2d2016-02-02 14:47:44 -0800853 mGestureStatusCallbackSequence++;
Phil Weavera6b64f52015-12-04 15:21:35 -0800854 if (callback != null) {
855 if (mGestureStatusCallbackInfos == null) {
856 mGestureStatusCallbackInfos = new SparseArray<>();
857 }
858 GestureResultCallbackInfo callbackInfo = new GestureResultCallbackInfo(gesture,
859 callback, handler);
860 mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo);
861 }
RyanlwLin80788132019-06-13 17:51:33 +0800862 connection.dispatchGesture(mGestureStatusCallbackSequence,
863 new ParceledListSlice<>(steps), gesture.getDisplayId());
Phil Weavera6b64f52015-12-04 15:21:35 -0800864 }
865 } catch (RemoteException re) {
866 throw new RuntimeException(re);
867 }
868 return true;
869 }
870
871 void onPerformGestureResult(int sequence, final boolean completedSuccessfully) {
872 if (mGestureStatusCallbackInfos == null) {
873 return;
874 }
875 GestureResultCallbackInfo callbackInfo;
876 synchronized (mLock) {
877 callbackInfo = mGestureStatusCallbackInfos.get(sequence);
Phil Weaver60219c12019-10-16 11:40:11 -0700878 mGestureStatusCallbackInfos.remove(sequence);
Phil Weavera6b64f52015-12-04 15:21:35 -0800879 }
880 final GestureResultCallbackInfo finalCallbackInfo = callbackInfo;
881 if ((callbackInfo != null) && (callbackInfo.gestureDescription != null)
882 && (callbackInfo.callback != null)) {
883 if (callbackInfo.handler != null) {
884 callbackInfo.handler.post(new Runnable() {
885 @Override
886 public void run() {
887 if (completedSuccessfully) {
888 finalCallbackInfo.callback
889 .onCompleted(finalCallbackInfo.gestureDescription);
890 } else {
891 finalCallbackInfo.callback
892 .onCancelled(finalCallbackInfo.gestureDescription);
893 }
894 }
895 });
896 return;
897 }
898 if (completedSuccessfully) {
899 callbackInfo.callback.onCompleted(callbackInfo.gestureDescription);
900 } else {
901 callbackInfo.callback.onCancelled(callbackInfo.gestureDescription);
902 }
903 }
904 }
905
Rhed Jao02655dc2018-10-30 20:44:52 +0800906 private void onMagnificationChanged(int displayId, @NonNull Region region, float scale,
Alan Viverette214fb682015-11-17 09:47:11 -0500907 float centerX, float centerY) {
Rhed Jao02655dc2018-10-30 20:44:52 +0800908 MagnificationController controller;
909 synchronized (mLock) {
910 controller = mMagnificationControllers.get(displayId);
911 }
912 if (controller != null) {
913 controller.dispatchMagnificationChanged(region, scale, centerX, centerY);
Alan Viverette214fb682015-11-17 09:47:11 -0500914 }
915 }
916
917 /**
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800918 * Callback for fingerprint gesture handling
919 * @param active If gesture detection is active
920 */
921 private void onFingerprintCapturingGesturesChanged(boolean active) {
922 getFingerprintGestureController().onGestureDetectionActiveChanged(active);
923 }
924
925 /**
926 * Callback for fingerprint gesture handling
927 * @param gesture The identifier for the gesture performed
928 */
929 private void onFingerprintGesture(int gesture) {
930 getFingerprintGestureController().onGesture(gesture);
931 }
932
933 /**
Alan Viverette214fb682015-11-17 09:47:11 -0500934 * Used to control and query the state of display magnification.
935 */
936 public static final class MagnificationController {
937 private final AccessibilityService mService;
Rhed Jao02655dc2018-10-30 20:44:52 +0800938 private final int mDisplayId;
Alan Viverette214fb682015-11-17 09:47:11 -0500939
940 /**
941 * Map of listeners to their handlers. Lazily created when adding the
942 * first magnification listener.
943 */
944 private ArrayMap<OnMagnificationChangedListener, Handler> mListeners;
Anna Galusza9b278112016-01-04 11:37:37 -0800945 private final Object mLock;
Alan Viverette214fb682015-11-17 09:47:11 -0500946
Rhed Jao02655dc2018-10-30 20:44:52 +0800947 MagnificationController(@NonNull AccessibilityService service, @NonNull Object lock,
948 int displayId) {
Alan Viverette214fb682015-11-17 09:47:11 -0500949 mService = service;
Anna Galusza9b278112016-01-04 11:37:37 -0800950 mLock = lock;
Rhed Jao02655dc2018-10-30 20:44:52 +0800951 mDisplayId = displayId;
Alan Viverette214fb682015-11-17 09:47:11 -0500952 }
953
954 /**
955 * Called when the service is connected.
956 */
Rhed Jao02655dc2018-10-30 20:44:52 +0800957 void onServiceConnectedLocked() {
958 if (mListeners != null && !mListeners.isEmpty()) {
959 setMagnificationCallbackEnabled(true);
Alan Viverette214fb682015-11-17 09:47:11 -0500960 }
961 }
962
963 /**
964 * Adds the specified change listener to the list of magnification
965 * change listeners. The callback will occur on the service's main
966 * thread.
967 *
968 * @param listener the listener to add, must be non-{@code null}
969 */
970 public void addListener(@NonNull OnMagnificationChangedListener listener) {
971 addListener(listener, null);
972 }
973
974 /**
975 * Adds the specified change listener to the list of magnification
976 * change listeners. The callback will occur on the specified
977 * {@link Handler}'s thread, or on the service's main thread if the
978 * handler is {@code null}.
979 *
980 * @param listener the listener to add, must be non-null
981 * @param handler the handler on which the callback should execute, or
982 * {@code null} to execute on the service's main thread
983 */
984 public void addListener(@NonNull OnMagnificationChangedListener listener,
985 @Nullable Handler handler) {
Anna Galusza9b278112016-01-04 11:37:37 -0800986 synchronized (mLock) {
987 if (mListeners == null) {
988 mListeners = new ArrayMap<>();
989 }
Alan Viverette214fb682015-11-17 09:47:11 -0500990
Anna Galusza9b278112016-01-04 11:37:37 -0800991 final boolean shouldEnableCallback = mListeners.isEmpty();
992 mListeners.put(listener, handler);
Alan Viverette214fb682015-11-17 09:47:11 -0500993
Anna Galusza9b278112016-01-04 11:37:37 -0800994 if (shouldEnableCallback) {
995 // This may fail if the service is not connected yet, but if we
996 // still have listeners when it connects then we can try again.
997 setMagnificationCallbackEnabled(true);
998 }
Alan Viverette214fb682015-11-17 09:47:11 -0500999 }
1000 }
1001
1002 /**
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001003 * Removes the specified change listener from the list of magnification change listeners.
Alan Viverette214fb682015-11-17 09:47:11 -05001004 *
1005 * @param listener the listener to remove, must be non-null
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001006 * @return {@code true} if the listener was removed, {@code false} otherwise
Alan Viverette214fb682015-11-17 09:47:11 -05001007 */
1008 public boolean removeListener(@NonNull OnMagnificationChangedListener listener) {
1009 if (mListeners == null) {
1010 return false;
1011 }
1012
Anna Galusza9b278112016-01-04 11:37:37 -08001013 synchronized (mLock) {
1014 final int keyIndex = mListeners.indexOfKey(listener);
1015 final boolean hasKey = keyIndex >= 0;
1016 if (hasKey) {
1017 mListeners.removeAt(keyIndex);
1018 }
Alan Viverette214fb682015-11-17 09:47:11 -05001019
Anna Galusza9b278112016-01-04 11:37:37 -08001020 if (hasKey && mListeners.isEmpty()) {
1021 // We just removed the last listener, so we don't need
1022 // callbacks from the service anymore.
1023 setMagnificationCallbackEnabled(false);
1024 }
Alan Viverette214fb682015-11-17 09:47:11 -05001025
Anna Galusza9b278112016-01-04 11:37:37 -08001026 return hasKey;
1027 }
Alan Viverette214fb682015-11-17 09:47:11 -05001028 }
1029
1030 private void setMagnificationCallbackEnabled(boolean enabled) {
1031 final IAccessibilityServiceConnection connection =
1032 AccessibilityInteractionClient.getInstance().getConnection(
1033 mService.mConnectionId);
1034 if (connection != null) {
1035 try {
Rhed Jao02655dc2018-10-30 20:44:52 +08001036 connection.setMagnificationCallbackEnabled(mDisplayId, enabled);
Alan Viverette214fb682015-11-17 09:47:11 -05001037 } catch (RemoteException re) {
1038 throw new RuntimeException(re);
1039 }
1040 }
1041 }
1042
1043 /**
1044 * Dispatches magnification changes to any registered listeners. This
1045 * should be called on the service's main thread.
1046 */
1047 void dispatchMagnificationChanged(final @NonNull Region region, final float scale,
1048 final float centerX, final float centerY) {
Anna Galusza9b278112016-01-04 11:37:37 -08001049 final ArrayMap<OnMagnificationChangedListener, Handler> entries;
1050 synchronized (mLock) {
1051 if (mListeners == null || mListeners.isEmpty()) {
1052 Slog.d(LOG_TAG, "Received magnification changed "
1053 + "callback with no listeners registered!");
1054 setMagnificationCallbackEnabled(false);
1055 return;
1056 }
Alan Viverette214fb682015-11-17 09:47:11 -05001057
Anna Galusza9b278112016-01-04 11:37:37 -08001058 // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
1059 // modification.
1060 entries = new ArrayMap<>(mListeners);
1061 }
Alan Viverette214fb682015-11-17 09:47:11 -05001062
1063 for (int i = 0, count = entries.size(); i < count; i++) {
1064 final OnMagnificationChangedListener listener = entries.keyAt(i);
1065 final Handler handler = entries.valueAt(i);
1066 if (handler != null) {
1067 handler.post(new Runnable() {
1068 @Override
1069 public void run() {
1070 listener.onMagnificationChanged(MagnificationController.this,
1071 region, scale, centerX, centerY);
1072 }
1073 });
1074 } else {
1075 // We're already on the main thread, just run the listener.
1076 listener.onMagnificationChanged(this, region, scale, centerX, centerY);
1077 }
1078 }
1079 }
1080
1081 /**
1082 * Returns the current magnification scale.
1083 * <p>
1084 * <strong>Note:</strong> If the service is not yet connected (e.g.
1085 * {@link AccessibilityService#onServiceConnected()} has not yet been
1086 * called) or the service has been disconnected, this method will
1087 * return a default value of {@code 1.0f}.
1088 *
1089 * @return the current magnification scale
1090 */
1091 public float getScale() {
1092 final IAccessibilityServiceConnection connection =
1093 AccessibilityInteractionClient.getInstance().getConnection(
1094 mService.mConnectionId);
1095 if (connection != null) {
1096 try {
Rhed Jao02655dc2018-10-30 20:44:52 +08001097 return connection.getMagnificationScale(mDisplayId);
Alan Viverette214fb682015-11-17 09:47:11 -05001098 } catch (RemoteException re) {
1099 Log.w(LOG_TAG, "Failed to obtain scale", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001100 re.rethrowFromSystemServer();
Alan Viverette214fb682015-11-17 09:47:11 -05001101 }
1102 }
1103 return 1.0f;
1104 }
1105
1106 /**
1107 * Returns the unscaled screen-relative X coordinate of the focal
1108 * center of the magnified region. This is the point around which
1109 * zooming occurs and is guaranteed to lie within the magnified
1110 * region.
1111 * <p>
1112 * <strong>Note:</strong> If the service is not yet connected (e.g.
1113 * {@link AccessibilityService#onServiceConnected()} has not yet been
1114 * called) or the service has been disconnected, this method will
1115 * return a default value of {@code 0.0f}.
1116 *
1117 * @return the unscaled screen-relative X coordinate of the center of
1118 * the magnified region
1119 */
1120 public float getCenterX() {
1121 final IAccessibilityServiceConnection connection =
1122 AccessibilityInteractionClient.getInstance().getConnection(
1123 mService.mConnectionId);
1124 if (connection != null) {
1125 try {
Rhed Jao02655dc2018-10-30 20:44:52 +08001126 return connection.getMagnificationCenterX(mDisplayId);
Alan Viverette214fb682015-11-17 09:47:11 -05001127 } catch (RemoteException re) {
1128 Log.w(LOG_TAG, "Failed to obtain center X", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001129 re.rethrowFromSystemServer();
Alan Viverette214fb682015-11-17 09:47:11 -05001130 }
1131 }
1132 return 0.0f;
1133 }
1134
1135 /**
1136 * Returns the unscaled screen-relative Y coordinate of the focal
1137 * center of the magnified region. This is the point around which
1138 * zooming occurs and is guaranteed to lie within the magnified
1139 * region.
1140 * <p>
1141 * <strong>Note:</strong> If the service is not yet connected (e.g.
1142 * {@link AccessibilityService#onServiceConnected()} has not yet been
1143 * called) or the service has been disconnected, this method will
1144 * return a default value of {@code 0.0f}.
1145 *
1146 * @return the unscaled screen-relative Y coordinate of the center of
1147 * the magnified region
1148 */
1149 public float getCenterY() {
1150 final IAccessibilityServiceConnection connection =
1151 AccessibilityInteractionClient.getInstance().getConnection(
1152 mService.mConnectionId);
1153 if (connection != null) {
1154 try {
Rhed Jao02655dc2018-10-30 20:44:52 +08001155 return connection.getMagnificationCenterY(mDisplayId);
Alan Viverette214fb682015-11-17 09:47:11 -05001156 } catch (RemoteException re) {
1157 Log.w(LOG_TAG, "Failed to obtain center Y", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001158 re.rethrowFromSystemServer();
Alan Viverette214fb682015-11-17 09:47:11 -05001159 }
1160 }
1161 return 0.0f;
1162 }
1163
1164 /**
Phil Weaver70439242016-03-10 15:15:49 -08001165 * Returns the region of the screen currently active for magnification. Changes to
1166 * magnification scale and center only affect this portion of the screen. The rest of the
1167 * screen, for example input methods, cannot be magnified. This region is relative to the
1168 * unscaled screen and is independent of the scale and center point.
1169 * <p>
1170 * The returned region will be empty if magnification is not active. Magnification is active
1171 * if magnification gestures are enabled or if a service is running that can control
1172 * magnification.
Alan Viverette214fb682015-11-17 09:47:11 -05001173 * <p>
1174 * <strong>Note:</strong> If the service is not yet connected (e.g.
1175 * {@link AccessibilityService#onServiceConnected()} has not yet been
1176 * called) or the service has been disconnected, this method will
1177 * return an empty region.
1178 *
Phil Weaver70439242016-03-10 15:15:49 -08001179 * @return the region of the screen currently active for magnification, or an empty region
1180 * if magnification is not active.
Alan Viverette214fb682015-11-17 09:47:11 -05001181 */
1182 @NonNull
Phil Weaver70439242016-03-10 15:15:49 -08001183 public Region getMagnificationRegion() {
Alan Viverette214fb682015-11-17 09:47:11 -05001184 final IAccessibilityServiceConnection connection =
1185 AccessibilityInteractionClient.getInstance().getConnection(
1186 mService.mConnectionId);
1187 if (connection != null) {
1188 try {
Rhed Jao02655dc2018-10-30 20:44:52 +08001189 return connection.getMagnificationRegion(mDisplayId);
Alan Viverette214fb682015-11-17 09:47:11 -05001190 } catch (RemoteException re) {
1191 Log.w(LOG_TAG, "Failed to obtain magnified region", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001192 re.rethrowFromSystemServer();
Alan Viverette214fb682015-11-17 09:47:11 -05001193 }
1194 }
1195 return Region.obtain();
1196 }
1197
1198 /**
1199 * Resets magnification scale and center to their default (e.g. no
1200 * magnification) values.
1201 * <p>
1202 * <strong>Note:</strong> If the service is not yet connected (e.g.
1203 * {@link AccessibilityService#onServiceConnected()} has not yet been
1204 * called) or the service has been disconnected, this method will have
1205 * no effect and return {@code false}.
1206 *
1207 * @param animate {@code true} to animate from the current scale and
1208 * center or {@code false} to reset the scale and center
1209 * immediately
1210 * @return {@code true} on success, {@code false} on failure
1211 */
1212 public boolean reset(boolean animate) {
1213 final IAccessibilityServiceConnection connection =
1214 AccessibilityInteractionClient.getInstance().getConnection(
1215 mService.mConnectionId);
1216 if (connection != null) {
1217 try {
Rhed Jao02655dc2018-10-30 20:44:52 +08001218 return connection.resetMagnification(mDisplayId, animate);
Alan Viverette214fb682015-11-17 09:47:11 -05001219 } catch (RemoteException re) {
1220 Log.w(LOG_TAG, "Failed to reset", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001221 re.rethrowFromSystemServer();
Alan Viverette214fb682015-11-17 09:47:11 -05001222 }
1223 }
1224 return false;
1225 }
1226
1227 /**
1228 * Sets the magnification scale.
1229 * <p>
1230 * <strong>Note:</strong> If the service is not yet connected (e.g.
1231 * {@link AccessibilityService#onServiceConnected()} has not yet been
1232 * called) or the service has been disconnected, this method will have
1233 * no effect and return {@code false}.
1234 *
Gilbert Leed38d6992018-12-27 10:04:27 +08001235 * @param scale the magnification scale to set, must be >= 1 and <= 8
Alan Viverette214fb682015-11-17 09:47:11 -05001236 * @param animate {@code true} to animate from the current scale or
1237 * {@code false} to set the scale immediately
1238 * @return {@code true} on success, {@code false} on failure
1239 */
1240 public boolean setScale(float scale, boolean animate) {
1241 final IAccessibilityServiceConnection connection =
1242 AccessibilityInteractionClient.getInstance().getConnection(
1243 mService.mConnectionId);
1244 if (connection != null) {
1245 try {
Rhed Jao02655dc2018-10-30 20:44:52 +08001246 return connection.setMagnificationScaleAndCenter(mDisplayId,
Alan Viverette214fb682015-11-17 09:47:11 -05001247 scale, Float.NaN, Float.NaN, animate);
1248 } catch (RemoteException re) {
1249 Log.w(LOG_TAG, "Failed to set scale", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001250 re.rethrowFromSystemServer();
Alan Viverette214fb682015-11-17 09:47:11 -05001251 }
1252 }
1253 return false;
1254 }
1255
1256 /**
1257 * Sets the center of the magnified viewport.
1258 * <p>
1259 * <strong>Note:</strong> If the service is not yet connected (e.g.
1260 * {@link AccessibilityService#onServiceConnected()} has not yet been
1261 * called) or the service has been disconnected, this method will have
1262 * no effect and return {@code false}.
1263 *
1264 * @param centerX the unscaled screen-relative X coordinate on which to
1265 * center the viewport
1266 * @param centerY the unscaled screen-relative Y coordinate on which to
1267 * center the viewport
1268 * @param animate {@code true} to animate from the current viewport
1269 * center or {@code false} to set the center immediately
1270 * @return {@code true} on success, {@code false} on failure
1271 */
1272 public boolean setCenter(float centerX, float centerY, boolean animate) {
1273 final IAccessibilityServiceConnection connection =
1274 AccessibilityInteractionClient.getInstance().getConnection(
1275 mService.mConnectionId);
1276 if (connection != null) {
1277 try {
Rhed Jao02655dc2018-10-30 20:44:52 +08001278 return connection.setMagnificationScaleAndCenter(mDisplayId,
Alan Viverette214fb682015-11-17 09:47:11 -05001279 Float.NaN, centerX, centerY, animate);
1280 } catch (RemoteException re) {
1281 Log.w(LOG_TAG, "Failed to set center", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001282 re.rethrowFromSystemServer();
Alan Viverette214fb682015-11-17 09:47:11 -05001283 }
1284 }
1285 return false;
1286 }
1287
1288 /**
1289 * Listener for changes in the state of magnification.
1290 */
1291 public interface OnMagnificationChangedListener {
1292 /**
1293 * Called when the magnified region, scale, or center changes.
1294 *
1295 * @param controller the magnification controller
Phil Weaver70439242016-03-10 15:15:49 -08001296 * @param region the magnification region
Alan Viverette214fb682015-11-17 09:47:11 -05001297 * @param scale the new scale
Phil Weaver70439242016-03-10 15:15:49 -08001298 * @param centerX the new X coordinate, in unscaled coordinates, around which
1299 * magnification is focused
1300 * @param centerY the new Y coordinate, in unscaled coordinates, around which
1301 * magnification is focused
Alan Viverette214fb682015-11-17 09:47:11 -05001302 */
1303 void onMagnificationChanged(@NonNull MagnificationController controller,
1304 @NonNull Region region, float scale, float centerX, float centerY);
1305 }
1306 }
1307
1308 /**
Anna Galusza9b278112016-01-04 11:37:37 -08001309 * Returns the soft keyboard controller, which may be used to query and modify the soft keyboard
1310 * show mode.
1311 *
1312 * @return the soft keyboard controller
1313 */
1314 @NonNull
1315 public final SoftKeyboardController getSoftKeyboardController() {
1316 synchronized (mLock) {
1317 if (mSoftKeyboardController == null) {
1318 mSoftKeyboardController = new SoftKeyboardController(this, mLock);
1319 }
1320 return mSoftKeyboardController;
1321 }
1322 }
1323
1324 private void onSoftKeyboardShowModeChanged(int showMode) {
1325 if (mSoftKeyboardController != null) {
1326 mSoftKeyboardController.dispatchSoftKeyboardShowModeChanged(showMode);
1327 }
1328 }
1329
1330 /**
Phil Weaver03a65b02018-07-19 16:07:57 -07001331 * Used to control, query, and listen for changes to the soft keyboard show mode.
1332 * <p>
1333 * Accessibility services may request to override the decisions normally made about whether or
1334 * not the soft keyboard is shown.
1335 * <p>
1336 * If multiple services make conflicting requests, the last request is honored. A service may
1337 * register a listener to find out if the mode has changed under it.
1338 * <p>
1339 * If the user takes action to override the behavior behavior requested by an accessibility
1340 * service, the user's request takes precendence, the show mode will be reset to
1341 * {@link AccessibilityService#SHOW_MODE_AUTO}, and services will no longer be able to control
1342 * that aspect of the soft keyboard's behavior.
1343 * <p>
1344 * Note: Because soft keyboards are independent apps, the framework does not have total control
1345 * over their behavior. They may choose to show themselves, or not, without regard to requests
1346 * made here. So the framework will make a best effort to deliver the behavior requested, but
1347 * cannot guarantee success.
1348 *
1349 * @see AccessibilityService#SHOW_MODE_AUTO
1350 * @see AccessibilityService#SHOW_MODE_HIDDEN
Phil Weavere05fba42018-09-04 13:36:00 -07001351 * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD
Anna Galusza9b278112016-01-04 11:37:37 -08001352 */
1353 public static final class SoftKeyboardController {
1354 private final AccessibilityService mService;
1355
1356 /**
1357 * Map of listeners to their handlers. Lazily created when adding the first
1358 * soft keyboard change listener.
1359 */
1360 private ArrayMap<OnShowModeChangedListener, Handler> mListeners;
1361 private final Object mLock;
1362
1363 SoftKeyboardController(@NonNull AccessibilityService service, @NonNull Object lock) {
1364 mService = service;
1365 mLock = lock;
1366 }
1367
1368 /**
1369 * Called when the service is connected.
1370 */
1371 void onServiceConnected() {
1372 synchronized(mLock) {
1373 if (mListeners != null && !mListeners.isEmpty()) {
1374 setSoftKeyboardCallbackEnabled(true);
1375 }
1376 }
1377 }
1378
1379 /**
1380 * Adds the specified change listener to the list of show mode change listeners. The
1381 * callback will occur on the service's main thread. Listener is not called on registration.
1382 */
1383 public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
1384 addOnShowModeChangedListener(listener, null);
1385 }
1386
1387 /**
1388 * Adds the specified change listener to the list of soft keyboard show mode change
1389 * listeners. The callback will occur on the specified {@link Handler}'s thread, or on the
1390 * services's main thread if the handler is {@code null}.
1391 *
1392 * @param listener the listener to add, must be non-null
1393 * @param handler the handler on which to callback should execute, or {@code null} to
1394 * execute on the service's main thread
1395 */
1396 public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener,
1397 @Nullable Handler handler) {
1398 synchronized (mLock) {
1399 if (mListeners == null) {
1400 mListeners = new ArrayMap<>();
1401 }
1402
1403 final boolean shouldEnableCallback = mListeners.isEmpty();
1404 mListeners.put(listener, handler);
1405
1406 if (shouldEnableCallback) {
1407 // This may fail if the service is not connected yet, but if we still have
1408 // listeners when it connects, we can try again.
1409 setSoftKeyboardCallbackEnabled(true);
1410 }
1411 }
1412 }
1413
1414 /**
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001415 * Removes the specified change listener from the list of keyboard show mode change
1416 * listeners.
Anna Galusza9b278112016-01-04 11:37:37 -08001417 *
1418 * @param listener the listener to remove, must be non-null
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001419 * @return {@code true} if the listener was removed, {@code false} otherwise
Anna Galusza9b278112016-01-04 11:37:37 -08001420 */
Phil Weaver03a65b02018-07-19 16:07:57 -07001421 public boolean removeOnShowModeChangedListener(
1422 @NonNull OnShowModeChangedListener listener) {
Anna Galusza9b278112016-01-04 11:37:37 -08001423 if (mListeners == null) {
1424 return false;
1425 }
1426
1427 synchronized (mLock) {
1428 final int keyIndex = mListeners.indexOfKey(listener);
1429 final boolean hasKey = keyIndex >= 0;
1430 if (hasKey) {
1431 mListeners.removeAt(keyIndex);
1432 }
1433
1434 if (hasKey && mListeners.isEmpty()) {
1435 // We just removed the last listener, so we don't need callbacks from the
1436 // service anymore.
1437 setSoftKeyboardCallbackEnabled(false);
1438 }
1439
1440 return hasKey;
1441 }
1442 }
1443
1444 private void setSoftKeyboardCallbackEnabled(boolean enabled) {
1445 final IAccessibilityServiceConnection connection =
1446 AccessibilityInteractionClient.getInstance().getConnection(
1447 mService.mConnectionId);
1448 if (connection != null) {
1449 try {
1450 connection.setSoftKeyboardCallbackEnabled(enabled);
1451 } catch (RemoteException re) {
1452 throw new RuntimeException(re);
1453 }
1454 }
1455 }
1456
1457 /**
1458 * Dispatches the soft keyboard show mode change to any registered listeners. This should
1459 * be called on the service's main thread.
1460 */
1461 void dispatchSoftKeyboardShowModeChanged(final int showMode) {
1462 final ArrayMap<OnShowModeChangedListener, Handler> entries;
1463 synchronized (mLock) {
1464 if (mListeners == null || mListeners.isEmpty()) {
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001465 Slog.w(LOG_TAG, "Received soft keyboard show mode changed callback"
Anna Galusza9b278112016-01-04 11:37:37 -08001466 + " with no listeners registered!");
1467 setSoftKeyboardCallbackEnabled(false);
1468 return;
1469 }
1470
1471 // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
1472 // modification.
1473 entries = new ArrayMap<>(mListeners);
1474 }
1475
1476 for (int i = 0, count = entries.size(); i < count; i++) {
1477 final OnShowModeChangedListener listener = entries.keyAt(i);
1478 final Handler handler = entries.valueAt(i);
1479 if (handler != null) {
1480 handler.post(new Runnable() {
1481 @Override
1482 public void run() {
1483 listener.onShowModeChanged(SoftKeyboardController.this, showMode);
1484 }
1485 });
1486 } else {
1487 // We're already on the main thread, just run the listener.
1488 listener.onShowModeChanged(this, showMode);
1489 }
1490 }
1491 }
1492
1493 /**
Phil Weaver03a65b02018-07-19 16:07:57 -07001494 * Returns the show mode of the soft keyboard.
Anna Galusza9b278112016-01-04 11:37:37 -08001495 *
1496 * @return the current soft keyboard show mode
Phil Weaver03a65b02018-07-19 16:07:57 -07001497 *
1498 * @see AccessibilityService#SHOW_MODE_AUTO
1499 * @see AccessibilityService#SHOW_MODE_HIDDEN
Phil Weavere05fba42018-09-04 13:36:00 -07001500 * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD
Anna Galusza9b278112016-01-04 11:37:37 -08001501 */
1502 @SoftKeyboardShowMode
1503 public int getShowMode() {
Phil Weaver03a65b02018-07-19 16:07:57 -07001504 final IAccessibilityServiceConnection connection =
1505 AccessibilityInteractionClient.getInstance().getConnection(
1506 mService.mConnectionId);
1507 if (connection != null) {
1508 try {
1509 return connection.getSoftKeyboardShowMode();
1510 } catch (RemoteException re) {
1511 Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re);
1512 re.rethrowFromSystemServer();
1513 }
1514 }
1515 return SHOW_MODE_AUTO;
Anna Galusza9b278112016-01-04 11:37:37 -08001516 }
1517
1518 /**
Phil Weaver03a65b02018-07-19 16:07:57 -07001519 * Sets the soft keyboard show mode.
Anna Galusza9b278112016-01-04 11:37:37 -08001520 * <p>
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001521 * <strong>Note:</strong> If the service is not yet connected (e.g.
Anna Galusza9b278112016-01-04 11:37:37 -08001522 * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001523 * service has been disconnected, this method will have no effect and return {@code false}.
Anna Galusza9b278112016-01-04 11:37:37 -08001524 *
1525 * @param showMode the new show mode for the soft keyboard
1526 * @return {@code true} on success
Phil Weaver03a65b02018-07-19 16:07:57 -07001527 *
1528 * @see AccessibilityService#SHOW_MODE_AUTO
1529 * @see AccessibilityService#SHOW_MODE_HIDDEN
Phil Weavere05fba42018-09-04 13:36:00 -07001530 * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD
Anna Galusza9b278112016-01-04 11:37:37 -08001531 */
1532 public boolean setShowMode(@SoftKeyboardShowMode int showMode) {
1533 final IAccessibilityServiceConnection connection =
1534 AccessibilityInteractionClient.getInstance().getConnection(
1535 mService.mConnectionId);
1536 if (connection != null) {
1537 try {
1538 return connection.setSoftKeyboardShowMode(showMode);
1539 } catch (RemoteException re) {
Anna Galusza32042512016-02-29 15:39:08 -08001540 Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re);
1541 re.rethrowFromSystemServer();
Anna Galusza9b278112016-01-04 11:37:37 -08001542 }
1543 }
1544 return false;
1545 }
1546
1547 /**
1548 * Listener for changes in the soft keyboard show mode.
1549 */
1550 public interface OnShowModeChangedListener {
1551 /**
1552 * Called when the soft keyboard behavior changes. The default show mode is
Anna Galusza32042512016-02-29 15:39:08 -08001553 * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
1554 * focused. An AccessibilityService can also request the show mode
1555 * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
Anna Galusza9b278112016-01-04 11:37:37 -08001556 *
1557 * @param controller the soft keyboard controller
1558 * @param showMode the current soft keyboard show mode
1559 */
1560 void onShowModeChanged(@NonNull SoftKeyboardController controller,
1561 @SoftKeyboardShowMode int showMode);
1562 }
mincheli850892b2019-12-05 19:47:59 +08001563
1564 /**
1565 * Switches the current IME for the user for whom the service is enabled. The change will
1566 * persist until the current IME is explicitly changed again, and may persist beyond the
1567 * life cycle of the requesting service.
1568 *
1569 * @param imeId The ID of the input method to make current. This IME must be installed and
1570 * enabled.
1571 * @return {@code true} if the current input method was successfully switched to the input
1572 * method by {@code imeId},
1573 * {@code false} if the input method specified is not installed, not enabled, or
1574 * otherwise not available to become the current IME
1575 *
1576 * @see android.view.inputmethod.InputMethodInfo#getId()
1577 */
1578 public boolean switchToInputMethod(@NonNull String imeId) {
1579 final IAccessibilityServiceConnection connection =
1580 AccessibilityInteractionClient.getInstance().getConnection(
1581 mService.mConnectionId);
1582 if (connection != null) {
1583 try {
1584 return connection.switchToInputMethod(imeId);
1585 } catch (RemoteException re) {
1586 throw new RuntimeException(re);
1587 }
1588 }
1589 return false;
1590 }
Anna Galusza9b278112016-01-04 11:37:37 -08001591 }
1592
1593 /**
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001594 * Returns the controller for the accessibility button within the system's navigation area.
1595 * This instance may be used to query the accessibility button's state and register listeners
1596 * for interactions with and state changes for the accessibility button when
1597 * {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set.
1598 * <p>
1599 * <strong>Note:</strong> Not all devices are capable of displaying the accessibility button
1600 * within a navigation area, and as such, use of this class should be considered only as an
1601 * optional feature or shortcut on supported device implementations.
1602 * </p>
1603 *
1604 * @return the accessibility button controller for this {@link AccessibilityService}
1605 */
1606 @NonNull
1607 public final AccessibilityButtonController getAccessibilityButtonController() {
minchelia52af2c2019-07-02 11:38:21 +08001608 return getAccessibilityButtonController(Display.DEFAULT_DISPLAY);
1609 }
1610
1611 /**
1612 * Returns the controller of specified logical display for the accessibility button within the
1613 * system's navigation area. This instance may be used to query the accessibility button's
1614 * state and register listeners for interactions with and state changes for the accessibility
1615 * button when {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set.
1616 * <p>
1617 * <strong>Note:</strong> Not all devices are capable of displaying the accessibility button
1618 * within a navigation area, and as such, use of this class should be considered only as an
1619 * optional feature or shortcut on supported device implementations.
1620 * </p>
1621 *
1622 * @param displayId The logic display id, use {@link Display#DEFAULT_DISPLAY} for default
1623 * display.
1624 * @return the accessibility button controller for this {@link AccessibilityService}
1625 */
1626 @NonNull
1627 public final AccessibilityButtonController getAccessibilityButtonController(int displayId) {
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001628 synchronized (mLock) {
minchelia52af2c2019-07-02 11:38:21 +08001629 AccessibilityButtonController controller = mAccessibilityButtonControllers.get(
1630 displayId);
1631 if (controller == null) {
1632 controller = new AccessibilityButtonController(
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001633 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId));
minchelia52af2c2019-07-02 11:38:21 +08001634 mAccessibilityButtonControllers.put(displayId, controller);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001635 }
minchelia52af2c2019-07-02 11:38:21 +08001636 return controller;
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001637 }
1638 }
1639
minchelia52af2c2019-07-02 11:38:21 +08001640 private void onAccessibilityButtonClicked(int displayId) {
1641 getAccessibilityButtonController(displayId).dispatchAccessibilityButtonClicked();
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001642 }
1643
1644 private void onAccessibilityButtonAvailabilityChanged(boolean available) {
1645 getAccessibilityButtonController().dispatchAccessibilityButtonAvailabilityChanged(
1646 available);
1647 }
1648
Hongming Jin8302c6c2020-01-10 17:45:18 -08001649 /** This is called when the system action list is changed. */
1650 public void onSystemActionsChanged() {
1651 }
1652
1653 /**
1654 * Returns a list of system actions available in the system right now.
1655 *
1656 * @return A list of available system actions.
1657 */
1658 public final @NonNull List<AccessibilityAction> getSystemActions() {
1659 IAccessibilityServiceConnection connection =
1660 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
1661 if (connection != null) {
1662 try {
1663 return connection.getSystemActions();
1664 } catch (RemoteException re) {
1665 Log.w(LOG_TAG, "Error while calling getSystemActions", re);
1666 re.rethrowFromSystemServer();
1667 }
1668 }
1669 return Collections.emptyList();
1670 }
1671
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001672 /**
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07001673 * Performs a global action. Such an action can be performed
1674 * at any moment regardless of the current application or user
1675 * location in that application. For example going back, going
1676 * home, opening recents, etc.
1677 *
1678 * @param action The action to perform.
1679 * @return Whether the action was successfully performed.
1680 *
1681 * @see #GLOBAL_ACTION_BACK
1682 * @see #GLOBAL_ACTION_HOME
1683 * @see #GLOBAL_ACTION_NOTIFICATIONS
1684 * @see #GLOBAL_ACTION_RECENTS
1685 */
1686 public final boolean performGlobalAction(int action) {
1687 IAccessibilityServiceConnection connection =
1688 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
1689 if (connection != null) {
1690 try {
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -07001691 return connection.performGlobalAction(action);
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07001692 } catch (RemoteException re) {
1693 Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001694 re.rethrowFromSystemServer();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07001695 }
1696 }
1697 return false;
1698 }
1699
1700 /**
Svetoslav1e0d4af2014-04-10 17:41:29 -07001701 * Find the view that has the specified focus type. The search is performed
1702 * across all windows.
1703 * <p>
1704 * <strong>Note:</strong> In order to access the windows your service has
1705 * to declare the capability to retrieve window content by setting the
1706 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
1707 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
1708 * Also the service has to opt-in to retrieve the interactive windows by
1709 * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
Phil Weaver40ded282016-01-25 15:49:02 -08001710 * flag. Otherwise, the search will be performed only in the active window.
Svetoslav1e0d4af2014-04-10 17:41:29 -07001711 * </p>
1712 *
1713 * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
1714 * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
1715 * @return The node info of the focused view or null.
1716 *
1717 * @see AccessibilityNodeInfo#FOCUS_INPUT
1718 * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
1719 */
1720 public AccessibilityNodeInfo findFocus(int focus) {
1721 return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
Phil Weaverf00cd142017-03-03 13:44:00 -08001722 AccessibilityWindowInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
Svetoslav1e0d4af2014-04-10 17:41:29 -07001723 }
1724
1725 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -07001726 * Gets the an {@link AccessibilityServiceInfo} describing this
1727 * {@link AccessibilityService}. This method is useful if one wants
1728 * to change some of the dynamically configurable properties at
1729 * runtime.
1730 *
1731 * @return The accessibility service info.
1732 *
Svetoslavbbfa5852013-02-11 19:38:12 -08001733 * @see AccessibilityServiceInfo
Svetoslav Ganov42138042012-03-20 11:51:39 -07001734 */
1735 public final AccessibilityServiceInfo getServiceInfo() {
1736 IAccessibilityServiceConnection connection =
1737 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
1738 if (connection != null) {
1739 try {
1740 return connection.getServiceInfo();
1741 } catch (RemoteException re) {
1742 Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001743 re.rethrowFromSystemServer();
Svetoslav Ganov42138042012-03-20 11:51:39 -07001744 }
1745 }
1746 return null;
1747 }
1748
1749 /**
svetoslavganov75986cf2009-05-14 22:28:01 -07001750 * Sets the {@link AccessibilityServiceInfo} that describes this service.
1751 * <p>
1752 * Note: You can call this method any time but the info will be picked up after
1753 * the system has bound to this service and when this method is called thereafter.
1754 *
1755 * @param info The info.
1756 */
1757 public final void setServiceInfo(AccessibilityServiceInfo info) {
1758 mInfo = info;
1759 sendServiceInfo();
1760 }
1761
1762 /**
1763 * Sets the {@link AccessibilityServiceInfo} for this service if the latter is
1764 * properly set and there is an {@link IAccessibilityServiceConnection} to the
1765 * AccessibilityManagerService.
1766 */
1767 private void sendServiceInfo() {
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001768 IAccessibilityServiceConnection connection =
1769 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
1770 if (mInfo != null && connection != null) {
svetoslavganov75986cf2009-05-14 22:28:01 -07001771 try {
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001772 connection.setServiceInfo(mInfo);
Svetoslav Ganov42138042012-03-20 11:51:39 -07001773 mInfo = null;
1774 AccessibilityInteractionClient.getInstance().clearCache();
svetoslavganov75986cf2009-05-14 22:28:01 -07001775 } catch (RemoteException re) {
1776 Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001777 re.rethrowFromSystemServer();
svetoslavganov75986cf2009-05-14 22:28:01 -07001778 }
1779 }
1780 }
1781
Alan Viverette7c9746d4e2014-11-19 17:02:16 -08001782 @Override
1783 public Object getSystemService(@ServiceName @NonNull String name) {
1784 if (getBaseContext() == null) {
1785 throw new IllegalStateException(
1786 "System services not available to Activities before onCreate()");
1787 }
1788
1789 // Guarantee that we always return the same window manager instance.
1790 if (WINDOW_SERVICE.equals(name)) {
1791 if (mWindowManager == null) {
1792 mWindowManager = (WindowManager) getBaseContext().getSystemService(name);
1793 }
1794 return mWindowManager;
1795 }
1796 return super.getSystemService(name);
1797 }
1798
Dianne Hackborn7f205432009-07-28 00:13:47 -07001799 /**
Jacky Kao09789e42020-01-15 16:23:52 +08001800 * Takes a screenshot of the specified display and returns it by {@link Bitmap.Config#HARDWARE}
1801 * format.
1802 * <p>
1803 * <strong>Note:</strong> In order to take screenshot your service has
1804 * to declare the capability to take screenshot by setting the
1805 * {@link android.R.styleable#AccessibilityService_canTakeScreenshot}
1806 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
1807 * Besides, This API is only supported for default display now
1808 * {@link Display#DEFAULT_DISPLAY}.
1809 * </p>
1810 *
1811 * @param displayId The logic display id, must be {@link Display#DEFAULT_DISPLAY} for
1812 * default display.
1813 * @param executor Executor on which to run the callback.
1814 * @param callback The callback invoked when the taking screenshot is done.
1815 *
1816 * @return {@code true} if the taking screenshot accepted, {@code false} if not.
1817 */
1818 public boolean takeScreenshot(int displayId, @NonNull @CallbackExecutor Executor executor,
1819 @NonNull Consumer<Bitmap> callback) {
1820 Preconditions.checkNotNull(executor, "executor cannot be null");
1821 Preconditions.checkNotNull(callback, "callback cannot be null");
1822 final IAccessibilityServiceConnection connection =
1823 AccessibilityInteractionClient.getInstance().getConnection(
1824 mConnectionId);
1825 if (connection == null) {
1826 return false;
1827 }
1828 try {
1829 connection.takeScreenshotWithCallback(displayId, new RemoteCallback((result) -> {
1830 final Bitmap screenshot = result.getParcelable(KEY_ACCESSIBILITY_SCREENSHOT);
1831 final long identity = Binder.clearCallingIdentity();
1832 try {
1833 executor.execute(() -> callback.accept(screenshot));
1834 } finally {
1835 Binder.restoreCallingIdentity(identity);
1836 }
1837 }));
1838 } catch (RemoteException re) {
1839 throw new RuntimeException(re);
1840 }
1841 return true;
1842 }
1843
1844 /**
Dianne Hackborn7f205432009-07-28 00:13:47 -07001845 * Implement to return the implementation of the internal accessibility
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001846 * service interface.
Dianne Hackborn7f205432009-07-28 00:13:47 -07001847 */
svetoslavganov75986cf2009-05-14 22:28:01 -07001848 @Override
1849 public final IBinder onBind(Intent intent) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07001850 return new IAccessibilityServiceClientWrapper(this, getMainLooper(), new Callbacks() {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001851 @Override
1852 public void onServiceConnected() {
Alan Viverette214fb682015-11-17 09:47:11 -05001853 AccessibilityService.this.dispatchServiceConnected();
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001854 }
1855
1856 @Override
1857 public void onInterrupt() {
1858 AccessibilityService.this.onInterrupt();
1859 }
1860
1861 @Override
1862 public void onAccessibilityEvent(AccessibilityEvent event) {
1863 AccessibilityService.this.onAccessibilityEvent(event);
1864 }
1865
1866 @Override
Svetoslav3a5c7212014-10-14 09:54:26 -07001867 public void init(int connectionId, IBinder windowToken) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001868 mConnectionId = connectionId;
Svetoslav3a5c7212014-10-14 09:54:26 -07001869 mWindowToken = windowToken;
Alan Viveretted2fa5142014-11-04 17:40:29 -08001870
Alan Viverette7c9746d4e2014-11-19 17:02:16 -08001871 // The client may have already obtained the window manager, so
1872 // update the default token on whatever manager we gave them.
1873 final WindowManagerImpl wm = (WindowManagerImpl) getSystemService(WINDOW_SERVICE);
1874 wm.setDefaultToken(windowToken);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001875 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07001876
1877 @Override
RyanlwLin0d17f042019-09-02 21:22:09 +08001878 public boolean onGesture(AccessibilityGestureEvent gestureEvent) {
1879 return AccessibilityService.this.onGesture(gestureEvent);
Svetoslav Ganov42138042012-03-20 11:51:39 -07001880 }
Svetoslavc4fccd12013-04-09 12:58:41 -07001881
1882 @Override
1883 public boolean onKeyEvent(KeyEvent event) {
1884 return AccessibilityService.this.onKeyEvent(event);
1885 }
Alan Viverette214fb682015-11-17 09:47:11 -05001886
1887 @Override
Rhed Jao02655dc2018-10-30 20:44:52 +08001888 public void onMagnificationChanged(int displayId, @NonNull Region region,
Alan Viverette214fb682015-11-17 09:47:11 -05001889 float scale, float centerX, float centerY) {
Rhed Jao02655dc2018-10-30 20:44:52 +08001890 AccessibilityService.this.onMagnificationChanged(displayId, region, scale,
1891 centerX, centerY);
Alan Viverette214fb682015-11-17 09:47:11 -05001892 }
Phil Weavera6b64f52015-12-04 15:21:35 -08001893
1894 @Override
Anna Galusza9b278112016-01-04 11:37:37 -08001895 public void onSoftKeyboardShowModeChanged(int showMode) {
1896 AccessibilityService.this.onSoftKeyboardShowModeChanged(showMode);
1897 }
1898
1899 @Override
Phil Weavera6b64f52015-12-04 15:21:35 -08001900 public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
1901 AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully);
1902 }
Phil Weaver27fcd9c2017-01-20 15:57:24 -08001903
1904 @Override
1905 public void onFingerprintCapturingGesturesChanged(boolean active) {
1906 AccessibilityService.this.onFingerprintCapturingGesturesChanged(active);
1907 }
1908
1909 @Override
1910 public void onFingerprintGesture(int gesture) {
1911 AccessibilityService.this.onFingerprintGesture(gesture);
1912 }
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001913
1914 @Override
minchelia52af2c2019-07-02 11:38:21 +08001915 public void onAccessibilityButtonClicked(int displayId) {
1916 AccessibilityService.this.onAccessibilityButtonClicked(displayId);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001917 }
1918
1919 @Override
1920 public void onAccessibilityButtonAvailabilityChanged(boolean available) {
1921 AccessibilityService.this.onAccessibilityButtonAvailabilityChanged(available);
1922 }
Hongming Jin8302c6c2020-01-10 17:45:18 -08001923
1924 @Override
1925 public void onSystemActionsChanged() {
1926 AccessibilityService.this.onSystemActionsChanged();
1927 }
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001928 });
svetoslavganov75986cf2009-05-14 22:28:01 -07001929 }
1930
1931 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -07001932 * Implements the internal {@link IAccessibilityServiceClient} interface to convert
svetoslavganov75986cf2009-05-14 22:28:01 -07001933 * incoming calls to it back to calls on an {@link AccessibilityService}.
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001934 *
1935 * @hide
svetoslavganov75986cf2009-05-14 22:28:01 -07001936 */
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001937 public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
svetoslavganov75986cf2009-05-14 22:28:01 -07001938 implements HandlerCaller.Callback {
Svetoslav3a5c7212014-10-14 09:54:26 -07001939 private static final int DO_INIT = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -08001940 private static final int DO_ON_INTERRUPT = 2;
1941 private static final int DO_ON_ACCESSIBILITY_EVENT = 3;
1942 private static final int DO_ON_GESTURE = 4;
1943 private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5;
1944 private static final int DO_ON_KEY_EVENT = 6;
Alan Viverette214fb682015-11-17 09:47:11 -05001945 private static final int DO_ON_MAGNIFICATION_CHANGED = 7;
Anna Galusza9b278112016-01-04 11:37:37 -08001946 private static final int DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED = 8;
1947 private static final int DO_GESTURE_COMPLETE = 9;
Phil Weaver27fcd9c2017-01-20 15:57:24 -08001948 private static final int DO_ON_FINGERPRINT_ACTIVE_CHANGED = 10;
1949 private static final int DO_ON_FINGERPRINT_GESTURE = 11;
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001950 private static final int DO_ACCESSIBILITY_BUTTON_CLICKED = 12;
1951 private static final int DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 13;
Hongming Jin8302c6c2020-01-10 17:45:18 -08001952 private static final int DO_ON_SYSTEM_ACTIONS_CHANGED = 14;
svetoslavganov75986cf2009-05-14 22:28:01 -07001953
1954 private final HandlerCaller mCaller;
1955
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001956 private final Callbacks mCallback;
svetoslavganov75986cf2009-05-14 22:28:01 -07001957
Phil Weaver6f2da202017-09-05 16:00:38 -07001958 private int mConnectionId = AccessibilityInteractionClient.NO_ID;
Svetoslavc4fccd12013-04-09 12:58:41 -07001959
Svetoslav Ganov42138042012-03-20 11:51:39 -07001960 public IAccessibilityServiceClientWrapper(Context context, Looper looper,
1961 Callbacks callback) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001962 mCallback = callback;
Mita Yuned218c72012-12-06 17:18:25 -08001963 mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/);
svetoslavganov75986cf2009-05-14 22:28:01 -07001964 }
1965
Svetoslav3a5c7212014-10-14 09:54:26 -07001966 public void init(IAccessibilityServiceConnection connection, int connectionId,
1967 IBinder windowToken) {
1968 Message message = mCaller.obtainMessageIOO(DO_INIT, connectionId,
1969 connection, windowToken);
svetoslavganov75986cf2009-05-14 22:28:01 -07001970 mCaller.sendMessage(message);
1971 }
1972
1973 public void onInterrupt() {
1974 Message message = mCaller.obtainMessage(DO_ON_INTERRUPT);
1975 mCaller.sendMessage(message);
1976 }
1977
Eugene Suslaeb1375c2016-12-20 16:32:59 -08001978 public void onAccessibilityEvent(AccessibilityEvent event, boolean serviceWantsEvent) {
1979 Message message = mCaller.obtainMessageBO(
1980 DO_ON_ACCESSIBILITY_EVENT, serviceWantsEvent, event);
svetoslavganov75986cf2009-05-14 22:28:01 -07001981 mCaller.sendMessage(message);
1982 }
1983
RyanlwLina0daddd2019-06-19 11:39:01 +08001984 @Override
RyanlwLin0d17f042019-09-02 21:22:09 +08001985 public void onGesture(AccessibilityGestureEvent gestureInfo) {
RyanlwLina0daddd2019-06-19 11:39:01 +08001986 Message message = mCaller.obtainMessageO(DO_ON_GESTURE, gestureInfo);
Svetoslav Ganov42138042012-03-20 11:51:39 -07001987 mCaller.sendMessage(message);
1988 }
1989
Svetoslav8e3feb12014-02-24 13:46:47 -08001990 public void clearAccessibilityCache() {
1991 Message message = mCaller.obtainMessage(DO_CLEAR_ACCESSIBILITY_CACHE);
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07001992 mCaller.sendMessage(message);
1993 }
1994
Svetoslavc4fccd12013-04-09 12:58:41 -07001995 @Override
1996 public void onKeyEvent(KeyEvent event, int sequence) {
1997 Message message = mCaller.obtainMessageIO(DO_ON_KEY_EVENT, sequence, event);
1998 mCaller.sendMessage(message);
1999 }
2000
Rhed Jao02655dc2018-10-30 20:44:52 +08002001 /** Magnification changed callbacks for different displays */
2002 public void onMagnificationChanged(int displayId, @NonNull Region region,
Alan Viverette214fb682015-11-17 09:47:11 -05002003 float scale, float centerX, float centerY) {
2004 final SomeArgs args = SomeArgs.obtain();
2005 args.arg1 = region;
2006 args.arg2 = scale;
2007 args.arg3 = centerX;
2008 args.arg4 = centerY;
Rhed Jao02655dc2018-10-30 20:44:52 +08002009 args.argi1 = displayId;
Alan Viverette214fb682015-11-17 09:47:11 -05002010
2011 final Message message = mCaller.obtainMessageO(DO_ON_MAGNIFICATION_CHANGED, args);
2012 mCaller.sendMessage(message);
2013 }
2014
Anna Galusza9b278112016-01-04 11:37:37 -08002015 public void onSoftKeyboardShowModeChanged(int showMode) {
2016 final Message message =
2017 mCaller.obtainMessageI(DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED, showMode);
2018 mCaller.sendMessage(message);
2019 }
2020
Phil Weavera6b64f52015-12-04 15:21:35 -08002021 public void onPerformGestureResult(int sequence, boolean successfully) {
2022 Message message = mCaller.obtainMessageII(DO_GESTURE_COMPLETE, sequence,
2023 successfully ? 1 : 0);
2024 mCaller.sendMessage(message);
2025 }
2026
Phil Weaver27fcd9c2017-01-20 15:57:24 -08002027 public void onFingerprintCapturingGesturesChanged(boolean active) {
2028 mCaller.sendMessage(mCaller.obtainMessageI(
2029 DO_ON_FINGERPRINT_ACTIVE_CHANGED, active ? 1 : 0));
2030 }
2031
2032 public void onFingerprintGesture(int gesture) {
2033 mCaller.sendMessage(mCaller.obtainMessageI(DO_ON_FINGERPRINT_GESTURE, gesture));
2034 }
2035
minchelia52af2c2019-07-02 11:38:21 +08002036 /** Accessibility button clicked callbacks for different displays */
2037 public void onAccessibilityButtonClicked(int displayId) {
2038 final Message message = mCaller.obtainMessageI(DO_ACCESSIBILITY_BUTTON_CLICKED,
2039 displayId);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08002040 mCaller.sendMessage(message);
2041 }
2042
2043 public void onAccessibilityButtonAvailabilityChanged(boolean available) {
2044 final Message message = mCaller.obtainMessageI(
2045 DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED, (available ? 1 : 0));
2046 mCaller.sendMessage(message);
2047 }
2048
Hongming Jin8302c6c2020-01-10 17:45:18 -08002049 /** This is called when the system action list is changed. */
2050 public void onSystemActionsChanged() {
2051 mCaller.sendMessage(mCaller.obtainMessage(DO_ON_SYSTEM_ACTIONS_CHANGED));
2052 }
2053
Svetoslav8e3feb12014-02-24 13:46:47 -08002054 @Override
svetoslavganov75986cf2009-05-14 22:28:01 -07002055 public void executeMessage(Message message) {
2056 switch (message.what) {
Svetoslavc4fccd12013-04-09 12:58:41 -07002057 case DO_ON_ACCESSIBILITY_EVENT: {
svetoslavganov75986cf2009-05-14 22:28:01 -07002058 AccessibilityEvent event = (AccessibilityEvent) message.obj;
Eugene Suslaeb1375c2016-12-20 16:32:59 -08002059 boolean serviceWantsEvent = message.arg1 != 0;
Dianne Hackborn7ed6ee52009-09-10 18:41:28 -07002060 if (event != null) {
Eugene Suslaeb1375c2016-12-20 16:32:59 -08002061 // Send the event to AccessibilityCache via AccessibilityInteractionClient
Svetoslav Ganov79311c42012-01-17 20:24:26 -08002062 AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event);
Phil Weaver6f2da202017-09-05 16:00:38 -07002063 if (serviceWantsEvent
2064 && (mConnectionId != AccessibilityInteractionClient.NO_ID)) {
Eugene Suslaeb1375c2016-12-20 16:32:59 -08002065 // Send the event to AccessibilityService
2066 mCallback.onAccessibilityEvent(event);
2067 }
Svetoslav8e3feb12014-02-24 13:46:47 -08002068 // Make sure the event is recycled.
2069 try {
2070 event.recycle();
2071 } catch (IllegalStateException ise) {
2072 /* ignore - best effort */
2073 }
Charles Chen85f6fb72009-08-28 11:32:23 -07002074 }
Hongming Jin8302c6c2020-01-10 17:45:18 -08002075 return;
2076 }
Svetoslavc4fccd12013-04-09 12:58:41 -07002077 case DO_ON_INTERRUPT: {
Phil Weaver6f2da202017-09-05 16:00:38 -07002078 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
2079 mCallback.onInterrupt();
2080 }
Hongming Jin8302c6c2020-01-10 17:45:18 -08002081 return;
2082 }
Svetoslav3a5c7212014-10-14 09:54:26 -07002083 case DO_INIT: {
Svetoslavc4fccd12013-04-09 12:58:41 -07002084 mConnectionId = message.arg1;
Svetoslav3a5c7212014-10-14 09:54:26 -07002085 SomeArgs args = (SomeArgs) message.obj;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002086 IAccessibilityServiceConnection connection =
Svetoslav3a5c7212014-10-14 09:54:26 -07002087 (IAccessibilityServiceConnection) args.arg1;
2088 IBinder windowToken = (IBinder) args.arg2;
2089 args.recycle();
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002090 if (connection != null) {
Svetoslavc4fccd12013-04-09 12:58:41 -07002091 AccessibilityInteractionClient.getInstance().addConnection(mConnectionId,
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002092 connection);
Svetoslav3a5c7212014-10-14 09:54:26 -07002093 mCallback.init(mConnectionId, windowToken);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08002094 mCallback.onServiceConnected();
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002095 } else {
Svetoslav8e3feb12014-02-24 13:46:47 -08002096 AccessibilityInteractionClient.getInstance().removeConnection(
2097 mConnectionId);
Svetoslav3a5c7212014-10-14 09:54:26 -07002098 mConnectionId = AccessibilityInteractionClient.NO_ID;
Svetoslavf7e50992013-01-22 18:15:40 -08002099 AccessibilityInteractionClient.getInstance().clearCache();
Svetoslav3a5c7212014-10-14 09:54:26 -07002100 mCallback.init(AccessibilityInteractionClient.NO_ID, null);
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002101 }
Hongming Jin8302c6c2020-01-10 17:45:18 -08002102 return;
2103 }
Svetoslavc4fccd12013-04-09 12:58:41 -07002104 case DO_ON_GESTURE: {
Phil Weaver6f2da202017-09-05 16:00:38 -07002105 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
RyanlwLin0d17f042019-09-02 21:22:09 +08002106 mCallback.onGesture((AccessibilityGestureEvent) message.obj);
Phil Weaver6f2da202017-09-05 16:00:38 -07002107 }
Hongming Jin8302c6c2020-01-10 17:45:18 -08002108 return;
2109 }
Svetoslav8e3feb12014-02-24 13:46:47 -08002110 case DO_CLEAR_ACCESSIBILITY_CACHE: {
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07002111 AccessibilityInteractionClient.getInstance().clearCache();
Hongming Jin8302c6c2020-01-10 17:45:18 -08002112 return;
2113 }
Svetoslavc4fccd12013-04-09 12:58:41 -07002114 case DO_ON_KEY_EVENT: {
2115 KeyEvent event = (KeyEvent) message.obj;
2116 try {
2117 IAccessibilityServiceConnection connection = AccessibilityInteractionClient
2118 .getInstance().getConnection(mConnectionId);
2119 if (connection != null) {
2120 final boolean result = mCallback.onKeyEvent(event);
2121 final int sequence = message.arg1;
2122 try {
2123 connection.setOnKeyEventResult(result, sequence);
2124 } catch (RemoteException re) {
2125 /* ignore */
2126 }
2127 }
2128 } finally {
Svetoslav8e3feb12014-02-24 13:46:47 -08002129 // Make sure the event is recycled.
2130 try {
2131 event.recycle();
2132 } catch (IllegalStateException ise) {
2133 /* ignore - best effort */
2134 }
Svetoslavc4fccd12013-04-09 12:58:41 -07002135 }
Hongming Jin8302c6c2020-01-10 17:45:18 -08002136 return;
2137 }
Alan Viverette214fb682015-11-17 09:47:11 -05002138 case DO_ON_MAGNIFICATION_CHANGED: {
Phil Weaver6f2da202017-09-05 16:00:38 -07002139 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
2140 final SomeArgs args = (SomeArgs) message.obj;
2141 final Region region = (Region) args.arg1;
2142 final float scale = (float) args.arg2;
2143 final float centerX = (float) args.arg3;
2144 final float centerY = (float) args.arg4;
Rhed Jao02655dc2018-10-30 20:44:52 +08002145 final int displayId = args.argi1;
2146 args.recycle();
2147 mCallback.onMagnificationChanged(displayId, region, scale,
2148 centerX, centerY);
Phil Weaver6f2da202017-09-05 16:00:38 -07002149 }
Hongming Jin8302c6c2020-01-10 17:45:18 -08002150 return;
2151 }
Anna Galusza9b278112016-01-04 11:37:37 -08002152 case DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED: {
Phil Weaver6f2da202017-09-05 16:00:38 -07002153 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
2154 final int showMode = (int) message.arg1;
2155 mCallback.onSoftKeyboardShowModeChanged(showMode);
2156 }
Hongming Jin8302c6c2020-01-10 17:45:18 -08002157 return;
2158 }
Phil Weavera6b64f52015-12-04 15:21:35 -08002159 case DO_GESTURE_COMPLETE: {
Phil Weaver6f2da202017-09-05 16:00:38 -07002160 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
2161 final boolean successfully = message.arg2 == 1;
2162 mCallback.onPerformGestureResult(message.arg1, successfully);
2163 }
Hongming Jin8302c6c2020-01-10 17:45:18 -08002164 return;
2165 }
Phil Weaver27fcd9c2017-01-20 15:57:24 -08002166 case DO_ON_FINGERPRINT_ACTIVE_CHANGED: {
Phil Weaver6f2da202017-09-05 16:00:38 -07002167 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
2168 mCallback.onFingerprintCapturingGesturesChanged(message.arg1 == 1);
2169 }
Hongming Jin8302c6c2020-01-10 17:45:18 -08002170 return;
2171 }
Phil Weaver27fcd9c2017-01-20 15:57:24 -08002172 case DO_ON_FINGERPRINT_GESTURE: {
Phil Weaver6f2da202017-09-05 16:00:38 -07002173 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
2174 mCallback.onFingerprintGesture(message.arg1);
2175 }
Hongming Jin8302c6c2020-01-10 17:45:18 -08002176 return;
2177 }
2178 case DO_ACCESSIBILITY_BUTTON_CLICKED: {
Phil Weaver6f2da202017-09-05 16:00:38 -07002179 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
minchelia52af2c2019-07-02 11:38:21 +08002180 mCallback.onAccessibilityButtonClicked(message.arg1);
Phil Weaver6f2da202017-09-05 16:00:38 -07002181 }
Hongming Jin8302c6c2020-01-10 17:45:18 -08002182 return;
2183 }
2184 case DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED: {
Phil Weaver6f2da202017-09-05 16:00:38 -07002185 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
2186 final boolean available = (message.arg1 != 0);
2187 mCallback.onAccessibilityButtonAvailabilityChanged(available);
2188 }
Hongming Jin8302c6c2020-01-10 17:45:18 -08002189 return;
2190 }
2191 case DO_ON_SYSTEM_ACTIONS_CHANGED: {
2192 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
2193 mCallback.onSystemActionsChanged();
2194 }
2195 return;
2196 }
svetoslavganov75986cf2009-05-14 22:28:01 -07002197 default :
2198 Log.w(LOG_TAG, "Unknown message type " + message.what);
2199 }
2200 }
2201 }
Phil Weavera6b64f52015-12-04 15:21:35 -08002202
2203 /**
2204 * Class used to report status of dispatched gestures
2205 */
2206 public static abstract class GestureResultCallback {
2207 /** Called when the gesture has completed successfully
2208 *
2209 * @param gestureDescription The description of the gesture that completed.
2210 */
2211 public void onCompleted(GestureDescription gestureDescription) {
2212 }
2213
2214 /** Called when the gesture was cancelled
2215 *
2216 * @param gestureDescription The description of the gesture that was cancelled.
2217 */
2218 public void onCancelled(GestureDescription gestureDescription) {
2219 }
2220 }
2221
2222 /* Object to keep track of gesture result callbacks */
2223 private static class GestureResultCallbackInfo {
2224 GestureDescription gestureDescription;
2225 GestureResultCallback callback;
2226 Handler handler;
2227
2228 GestureResultCallbackInfo(GestureDescription gestureDescription,
2229 GestureResultCallback callback, Handler handler) {
2230 this.gestureDescription = gestureDescription;
2231 this.callback = callback;
2232 this.handler = handler;
2233 }
2234 }
svetoslavganov75986cf2009-05-14 22:28:01 -07002235}