blob: cd0ef6f0e40359c865051ed8e4025a6f4ded9250 [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;
Anna Galusza9b278112016-01-04 11:37:37 -080020import android.annotation.IntDef;
Alan Viverette7c9746d4e2014-11-19 17:02:16 -080021import android.annotation.NonNull;
Alan Viverette214fb682015-11-17 09:47:11 -050022import android.annotation.Nullable;
Phil Weaver27fcd9c2017-01-20 15:57:24 -080023import android.annotation.RequiresPermission;
Mathew Inwood62992f12018-08-01 14:28:00 +010024import android.annotation.UnsupportedAppUsage;
svetoslavganov75986cf2009-05-14 22:28:01 -070025import android.app.Service;
Svetoslav Ganov79311c42012-01-17 20:24:26 -080026import android.content.Context;
svetoslavganov75986cf2009-05-14 22:28:01 -070027import android.content.Intent;
Phil Weavera6b64f52015-12-04 15:21:35 -080028import android.content.pm.ParceledListSlice;
Alan Viverette214fb682015-11-17 09:47:11 -050029import android.graphics.Region;
Mathew Inwood45d2c252018-09-14 12:35:36 +010030import android.os.Build;
Alan Viverette214fb682015-11-17 09:47:11 -050031import android.os.Handler;
svetoslavganov75986cf2009-05-14 22:28:01 -070032import android.os.IBinder;
Svetoslav Ganov79311c42012-01-17 20:24:26 -080033import android.os.Looper;
svetoslavganov75986cf2009-05-14 22:28:01 -070034import android.os.Message;
35import android.os.RemoteException;
Anna Galusza9b278112016-01-04 11:37:37 -080036import android.provider.Settings;
Alan Viverette214fb682015-11-17 09:47:11 -050037import android.util.ArrayMap;
svetoslavganov75986cf2009-05-14 22:28:01 -070038import android.util.Log;
Alan Viverette214fb682015-11-17 09:47:11 -050039import android.util.Slog;
Phil Weavera6b64f52015-12-04 15:21:35 -080040import android.util.SparseArray;
Svetoslavc4fccd12013-04-09 12:58:41 -070041import android.view.KeyEvent;
Svetoslav3a5c7212014-10-14 09:54:26 -070042import android.view.WindowManager;
Alan Viverette7c9746d4e2014-11-19 17:02:16 -080043import android.view.WindowManagerImpl;
svetoslavganov75986cf2009-05-14 22:28:01 -070044import android.view.accessibility.AccessibilityEvent;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -080045import android.view.accessibility.AccessibilityInteractionClient;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070046import android.view.accessibility.AccessibilityNodeInfo;
Svetoslav8e3feb12014-02-24 13:46:47 -080047import android.view.accessibility.AccessibilityWindowInfo;
svetoslavganov75986cf2009-05-14 22:28:01 -070048
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -080049import com.android.internal.os.HandlerCaller;
Svetoslav3a5c7212014-10-14 09:54:26 -070050import com.android.internal.os.SomeArgs;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -080051
Anna Galusza9b278112016-01-04 11:37:37 -080052import java.lang.annotation.Retention;
53import java.lang.annotation.RetentionPolicy;
Svetoslav8e3feb12014-02-24 13:46:47 -080054import java.util.List;
55
svetoslavganov75986cf2009-05-14 22:28:01 -070056/**
Phil Weaver752047d2016-09-08 10:35:49 -070057 * Accessibility services should only be used to assist users with disabilities in using
Phil Weaver40ded282016-01-25 15:49:02 -080058 * Android devices and apps. They run in the background and receive callbacks by the system
svetoslavganov75986cf2009-05-14 22:28:01 -070059 * when {@link AccessibilityEvent}s are fired. Such events denote some state transition
60 * in the user interface, for example, the focus has changed, a button has been clicked,
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070061 * etc. Such a service can optionally request the capability for querying the content
Scott Mainb303d832011-10-12 16:45:18 -070062 * of the active window. Development of an accessibility service requires extending this
63 * class and implementing its abstract methods.
Joe Fernandeze1302ed2012-02-06 14:30:15 -080064 *
65 * <div class="special reference">
66 * <h3>Developer Guides</h3>
67 * <p>For more information about creating AccessibilityServices, read the
68 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
69 * developer guide.</p>
70 * </div>
71 *
Scott Mainb303d832011-10-12 16:45:18 -070072 * <h3>Lifecycle</h3>
svetoslavganov75986cf2009-05-14 22:28:01 -070073 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070074 * The lifecycle of an accessibility service is managed exclusively by the system and
Phil Weaver40ded282016-01-25 15:49:02 -080075 * follows the established service life cycle. Starting an accessibility service is triggered
76 * exclusively by the user explicitly turning the service on in device settings. After the system
77 * binds to a service, it calls {@link AccessibilityService#onServiceConnected()}. This method can
78 * be overriden by clients that want to perform post binding setup.
79 * </p>
80 * <p>
81 * An accessibility service stops either when the user turns it off in device settings or when
82 * it calls {@link AccessibilityService#disableSelf()}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070083 * </p>
Scott Mainb303d832011-10-12 16:45:18 -070084 * <h3>Declaration</h3>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070085 * <p>
Phil Weaver40ded282016-01-25 15:49:02 -080086 * An accessibility is declared as any other service in an AndroidManifest.xml, but it
87 * must do two things:
88 * <ul>
89 * <ol>
90 * Specify that it handles the "android.accessibilityservice.AccessibilityService"
91 * {@link android.content.Intent}.
92 * </ol>
93 * <ol>
94 * Request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to
95 * ensure that only the system can bind to it.
96 * </ol>
97 * </ul>
98 * If either of these items is missing, the system will ignore the accessibility service.
99 * Following is an example declaration:
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700100 * </p>
Svetoslav Ganov53e184d2012-05-16 15:57:10 -0700101 * <pre> &lt;service android:name=".MyAccessibilityService"
Scott Main53b0fda2012-08-06 12:50:48 -0700102 * android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"&gt;
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700103 * &lt;intent-filter&gt;
Scott Mainb303d832011-10-12 16:45:18 -0700104 * &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700105 * &lt;/intent-filter&gt;
106 * . . .
Scott Mainb303d832011-10-12 16:45:18 -0700107 * &lt;/service&gt;</pre>
108 * <h3>Configuration</h3>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700109 * <p>
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700110 * An accessibility service can be configured to receive specific types of accessibility events,
111 * listen only to specific packages, get events from each type only once in a given time frame,
112 * retrieve window content, specify a settings activity, etc.
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700113 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700114 * <p>
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700115 * There are two approaches for configuring an accessibility service:
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700116 * </p>
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700117 * <ul>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700118 * <li>
119 * Providing a {@link #SERVICE_META_DATA meta-data} entry in the manifest when declaring
120 * the service. A service declaration with a meta-data tag is presented below:
Scott Mainb303d832011-10-12 16:45:18 -0700121 * <pre> &lt;service android:name=".MyAccessibilityService"&gt;
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700122 * &lt;intent-filter&gt;
Scott Mainb303d832011-10-12 16:45:18 -0700123 * &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700124 * &lt;/intent-filter&gt;
125 * &lt;meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice" /&gt;
Scott Mainb303d832011-10-12 16:45:18 -0700126 * &lt;/service&gt;</pre>
127 * <p class="note">
128 * <strong>Note:</strong> This approach enables setting all properties.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700129 * </p>
130 * <p>
131 * For more details refer to {@link #SERVICE_META_DATA} and
Scott Mainb303d832011-10-12 16:45:18 -0700132 * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700133 * </p>
134 * </li>
135 * <li>
136 * Calling {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}. Note
137 * that this method can be called any time to dynamically change the service configuration.
Scott Mainb303d832011-10-12 16:45:18 -0700138 * <p class="note">
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700139 * <strong>Note:</strong> This approach enables setting only dynamically configurable properties:
140 * {@link AccessibilityServiceInfo#eventTypes},
141 * {@link AccessibilityServiceInfo#feedbackType},
142 * {@link AccessibilityServiceInfo#flags},
143 * {@link AccessibilityServiceInfo#notificationTimeout},
144 * {@link AccessibilityServiceInfo#packageNames}
145 * </p>
146 * <p>
147 * For more details refer to {@link AccessibilityServiceInfo}.
148 * </p>
149 * </li>
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700150 * </ul>
Scott Mainb303d832011-10-12 16:45:18 -0700151 * <h3>Retrieving window content</h3>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700152 * <p>
Phil Weaver40ded282016-01-25 15:49:02 -0800153 * A service can specify in its declaration that it can retrieve window
154 * content which is represented as a tree of {@link AccessibilityWindowInfo} and
155 * {@link AccessibilityNodeInfo} objects. Note that
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700156 * declaring this capability requires that the service declares its configuration via
157 * an XML resource referenced by {@link #SERVICE_META_DATA}.
158 * </p>
159 * <p>
Phil Weaver40ded282016-01-25 15:49:02 -0800160 * Window content may be retrieved with
161 * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()},
162 * {@link AccessibilityService#findFocus(int)},
163 * {@link AccessibilityService#getWindows()}, or
164 * {@link AccessibilityService#getRootInActiveWindow()}.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700165 * </p>
Scott Mainb303d832011-10-12 16:45:18 -0700166 * <p class="note">
167 * <strong>Note</strong> An accessibility service may have requested to be notified for
Phil Weaver40ded282016-01-25 15:49:02 -0800168 * a subset of the event types, and thus be unaware when the node hierarchy has changed. It is also
169 * possible for a node to contain outdated information because the window content may change at any
170 * time.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700171 * </p>
Scott Mainb303d832011-10-12 16:45:18 -0700172 * <h3>Notification strategy</h3>
svetoslavganov75986cf2009-05-14 22:28:01 -0700173 * <p>
Phil Weaver14ed6cf2015-11-20 14:46:28 -0800174 * All accessibility services are notified of all events they have requested, regardless of their
175 * feedback type.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700176 * </p>
Scott Mainb303d832011-10-12 16:45:18 -0700177 * <p class="note">
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700178 * <strong>Note:</strong> The event notification timeout is useful to avoid propagating
179 * events to the client too frequently since this is accomplished via an expensive
180 * interprocess call. One can think of the timeout as a criteria to determine when
Scott Mainb303d832011-10-12 16:45:18 -0700181 * event generation has settled down.</p>
182 * <h3>Event types</h3>
183 * <ul>
Svetoslav8e3feb12014-02-24 13:46:47 -0800184 * <li>{@link AccessibilityEvent#TYPE_VIEW_CLICKED}</li>
185 * <li>{@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}</li>
186 * <li>{@link AccessibilityEvent#TYPE_VIEW_FOCUSED}</li>
187 * <li>{@link AccessibilityEvent#TYPE_VIEW_SELECTED}</li>
188 * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}</li>
189 * <li>{@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}</li>
190 * <li>{@link AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED}</li>
191 * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START}</li>
192 * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END}</li>
193 * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}</li>
194 * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}</li>
195 * <li>{@link AccessibilityEvent#TYPE_VIEW_SCROLLED}</li>
196 * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED}</li>
197 * <li>{@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}</li>
198 * <li>{@link AccessibilityEvent#TYPE_ANNOUNCEMENT}</li>
199 * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_START}</li>
200 * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_END}</li>
201 * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_START}</li>
202 * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_END}</li>
203 * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED}</li>
204 * <li>{@link AccessibilityEvent#TYPE_WINDOWS_CHANGED}</li>
205 * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED}</li>
Scott Mainb303d832011-10-12 16:45:18 -0700206 * </ul>
207 * <h3>Feedback types</h3>
208 * <ul>
Svetoslav8e3feb12014-02-24 13:46:47 -0800209 * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li>
210 * <li>{@link AccessibilityServiceInfo#FEEDBACK_HAPTIC}</li>
211 * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li>
212 * <li>{@link AccessibilityServiceInfo#FEEDBACK_VISUAL}</li>
213 * <li>{@link AccessibilityServiceInfo#FEEDBACK_GENERIC}</li>
214 * <li>{@link AccessibilityServiceInfo#FEEDBACK_BRAILLE}</li>
Scott Mainb303d832011-10-12 16:45:18 -0700215 * </ul>
216 * @see AccessibilityEvent
217 * @see AccessibilityServiceInfo
218 * @see android.view.accessibility.AccessibilityManager
svetoslavganov75986cf2009-05-14 22:28:01 -0700219 */
220public abstract class AccessibilityService extends Service {
Svetoslav Ganov42138042012-03-20 11:51:39 -0700221
222 /**
223 * The user has performed a swipe up gesture on the touch screen.
224 */
225 public static final int GESTURE_SWIPE_UP = 1;
226
227 /**
228 * The user has performed a swipe down gesture on the touch screen.
229 */
230 public static final int GESTURE_SWIPE_DOWN = 2;
231
232 /**
233 * The user has performed a swipe left gesture on the touch screen.
234 */
235 public static final int GESTURE_SWIPE_LEFT = 3;
236
237 /**
238 * The user has performed a swipe right gesture on the touch screen.
239 */
240 public static final int GESTURE_SWIPE_RIGHT = 4;
241
242 /**
243 * The user has performed a swipe left and right gesture on the touch screen.
244 */
245 public static final int GESTURE_SWIPE_LEFT_AND_RIGHT = 5;
246
247 /**
248 * The user has performed a swipe right and left gesture on the touch screen.
249 */
250 public static final int GESTURE_SWIPE_RIGHT_AND_LEFT = 6;
251
252 /**
253 * The user has performed a swipe up and down gesture on the touch screen.
254 */
255 public static final int GESTURE_SWIPE_UP_AND_DOWN = 7;
256
257 /**
258 * The user has performed a swipe down and up gesture on the touch screen.
259 */
260 public static final int GESTURE_SWIPE_DOWN_AND_UP = 8;
261
262 /**
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700263 * The user has performed a left and up gesture on the touch screen.
264 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700265 public static final int GESTURE_SWIPE_LEFT_AND_UP = 9;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700266
267 /**
268 * The user has performed a left and down gesture on the touch screen.
269 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700270 public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 10;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700271
272 /**
273 * The user has performed a right and up gesture on the touch screen.
274 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700275 public static final int GESTURE_SWIPE_RIGHT_AND_UP = 11;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700276
277 /**
278 * The user has performed a right and down gesture on the touch screen.
279 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700280 public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 12;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700281
282 /**
283 * The user has performed an up and left gesture on the touch screen.
284 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700285 public static final int GESTURE_SWIPE_UP_AND_LEFT = 13;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700286
287 /**
288 * The user has performed an up and right gesture on the touch screen.
289 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700290 public static final int GESTURE_SWIPE_UP_AND_RIGHT = 14;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700291
292 /**
293 * The user has performed an down and left gesture on the touch screen.
294 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700295 public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 15;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700296
297 /**
298 * The user has performed an down and right gesture on the touch screen.
299 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700300 public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 16;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700301
302 /**
svetoslavganov75986cf2009-05-14 22:28:01 -0700303 * The {@link Intent} that must be declared as handled by the service.
304 */
305 public static final String SERVICE_INTERFACE =
306 "android.accessibilityservice.AccessibilityService";
307
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700308 /**
309 * Name under which an AccessibilityService component publishes information
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700310 * about itself. This meta-data must reference an XML resource containing an
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700311 * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>
312 * tag. This is a a sample XML file configuring an accessibility service:
Scott Mainb303d832011-10-12 16:45:18 -0700313 * <pre> &lt;accessibility-service
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700314 * android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
315 * android:packageNames="foo.bar, foo.baz"
316 * android:accessibilityFeedbackType="feedbackSpoken"
317 * android:notificationTimeout="100"
318 * android:accessibilityFlags="flagDefault"
319 * android:settingsActivity="foo.bar.TestBackActivity"
320 * android:canRetrieveWindowContent="true"
Svetoslav688a6972013-04-16 18:55:38 -0700321 * android:canRequestTouchExplorationMode="true"
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700322 * . . .
Scott Mainb303d832011-10-12 16:45:18 -0700323 * /&gt;</pre>
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700324 */
325 public static final String SERVICE_META_DATA = "android.accessibilityservice";
326
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700327 /**
328 * Action to go back.
329 */
330 public static final int GLOBAL_ACTION_BACK = 1;
331
332 /**
333 * Action to go home.
334 */
335 public static final int GLOBAL_ACTION_HOME = 2;
336
337 /**
Phil Weaver3cdd6c72016-11-03 15:28:03 -0700338 * Action to toggle showing the overview of recent apps. Will fail on platforms that don't
339 * show recent apps.
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700340 */
341 public static final int GLOBAL_ACTION_RECENTS = 3;
342
343 /**
344 * Action to open the notifications.
345 */
346 public static final int GLOBAL_ACTION_NOTIFICATIONS = 4;
347
Svetoslav Ganove20a1772012-09-25 16:07:46 -0700348 /**
349 * Action to open the quick settings.
350 */
351 public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5;
352
Alan Viverettee34560b22014-07-10 14:50:06 -0700353 /**
354 * Action to open the power long-press dialog.
355 */
356 public static final int GLOBAL_ACTION_POWER_DIALOG = 6;
357
Phil Weaver315c34e2016-02-19 15:12:29 -0800358 /**
359 * Action to toggle docking the current app's window
360 */
361 public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7;
362
Eugene Suslaf9a651d2017-10-11 12:06:27 -0700363 /**
364 * Action to lock the screen
365 */
366 public static final int GLOBAL_ACTION_LOCK_SCREEN = 8;
367
Phil Weaverd0429742018-01-16 15:32:30 -0800368 /**
369 * Action to take a screenshot
370 */
371 public static final int GLOBAL_ACTION_TAKE_SCREENSHOT = 9;
372
svetoslavganov75986cf2009-05-14 22:28:01 -0700373 private static final String LOG_TAG = "AccessibilityService";
374
Svetoslav Ganov80943d82013-01-02 10:25:37 -0800375 /**
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800376 * Interface used by IAccessibilityServiceWrapper to call the service from its main thread.
Svetoslav Ganov80943d82013-01-02 10:25:37 -0800377 * @hide
378 */
379 public interface Callbacks {
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800380 void onAccessibilityEvent(AccessibilityEvent event);
381 void onInterrupt();
382 void onServiceConnected();
383 void init(int connectionId, IBinder windowToken);
384 boolean onGesture(int gestureId);
385 boolean onKeyEvent(KeyEvent event);
386 void onMagnificationChanged(@NonNull Region region,
Alan Viverette214fb682015-11-17 09:47:11 -0500387 float scale, float centerX, float centerY);
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800388 void onSoftKeyboardShowModeChanged(int showMode);
389 void onPerformGestureResult(int sequence, boolean completedSuccessfully);
390 void onFingerprintCapturingGesturesChanged(boolean active);
391 void onFingerprintGesture(int gesture);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800392 void onAccessibilityButtonClicked();
393 void onAccessibilityButtonAvailabilityChanged(boolean available);
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800394 }
svetoslavganov75986cf2009-05-14 22:28:01 -0700395
Anna Galusza9b278112016-01-04 11:37:37 -0800396 /**
397 * Annotations for Soft Keyboard show modes so tools can catch invalid show modes.
398 * @hide
399 */
400 @Retention(RetentionPolicy.SOURCE)
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700401 @IntDef(prefix = { "SHOW_MODE_" }, value = {
402 SHOW_MODE_AUTO,
403 SHOW_MODE_HIDDEN
404 })
405 public @interface SoftKeyboardShowMode {}
406
Anna Galusza9b278112016-01-04 11:37:37 -0800407 public static final int SHOW_MODE_AUTO = 0;
Anna Galusza9b278112016-01-04 11:37:37 -0800408 public static final int SHOW_MODE_HIDDEN = 1;
409
Phil Weaver6f2da202017-09-05 16:00:38 -0700410 private int mConnectionId = AccessibilityInteractionClient.NO_ID;
svetoslavganov75986cf2009-05-14 22:28:01 -0700411
Mathew Inwood62992f12018-08-01 14:28:00 +0100412 @UnsupportedAppUsage
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800413 private AccessibilityServiceInfo mInfo;
414
Mathew Inwood45d2c252018-09-14 12:35:36 +0100415 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Svetoslav3a5c7212014-10-14 09:54:26 -0700416 private IBinder mWindowToken;
417
418 private WindowManager mWindowManager;
419
Alan Viverette214fb682015-11-17 09:47:11 -0500420 private MagnificationController mMagnificationController;
Anna Galusza9b278112016-01-04 11:37:37 -0800421 private SoftKeyboardController mSoftKeyboardController;
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800422 private AccessibilityButtonController mAccessibilityButtonController;
Alan Viverette214fb682015-11-17 09:47:11 -0500423
Phil Weavera6b64f52015-12-04 15:21:35 -0800424 private int mGestureStatusCallbackSequence;
425
426 private SparseArray<GestureResultCallbackInfo> mGestureStatusCallbackInfos;
427
428 private final Object mLock = new Object();
429
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800430 private FingerprintGestureController mFingerprintGestureController;
431
svetoslavganov75986cf2009-05-14 22:28:01 -0700432 /**
433 * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
434 *
Phil Weaver96fea022016-03-08 13:05:10 -0800435 * @param event The new event. This event is owned by the caller and cannot be used after
436 * this method returns. Services wishing to use the event after this method returns should
437 * make a copy.
svetoslavganov75986cf2009-05-14 22:28:01 -0700438 */
Phil Weavere2319862017-02-23 18:51:34 +0000439 public abstract void onAccessibilityEvent(AccessibilityEvent event);
svetoslavganov75986cf2009-05-14 22:28:01 -0700440
441 /**
442 * Callback for interrupting the accessibility feedback.
443 */
Phil Weavere2319862017-02-23 18:51:34 +0000444 public abstract void onInterrupt();
svetoslavganov75986cf2009-05-14 22:28:01 -0700445
446 /**
Alan Viverette214fb682015-11-17 09:47:11 -0500447 * Dispatches service connection to internal components first, then the
448 * client code.
449 */
450 private void dispatchServiceConnected() {
451 if (mMagnificationController != null) {
452 mMagnificationController.onServiceConnected();
453 }
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800454 if (mSoftKeyboardController != null) {
455 mSoftKeyboardController.onServiceConnected();
456 }
Alan Viverette214fb682015-11-17 09:47:11 -0500457
458 // The client gets to handle service connection last, after we've set
459 // up any state upon which their code may rely.
460 onServiceConnected();
461 }
462
463 /**
svetoslavganov75986cf2009-05-14 22:28:01 -0700464 * This method is a part of the {@link AccessibilityService} lifecycle and is
465 * called after the system has successfully bound to the service. If is
466 * convenient to use this method for setting the {@link AccessibilityServiceInfo}.
467 *
468 * @see AccessibilityServiceInfo
469 * @see #setServiceInfo(AccessibilityServiceInfo)
470 */
471 protected void onServiceConnected() {
472
473 }
474
475 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700476 * Called by the system when the user performs a specific gesture on the
Svetoslav Ganove4abc512012-05-09 11:02:38 -0700477 * touch screen.
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700478 *
Svetoslav Ganove4abc512012-05-09 11:02:38 -0700479 * <strong>Note:</strong> To receive gestures an accessibility service must
480 * request that the device is in touch exploration mode by setting the
Svetoslav Ganov7b1e0c72012-05-13 11:57:29 -0700481 * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}
Svetoslav Ganove4abc512012-05-09 11:02:38 -0700482 * flag.
Svetoslav Ganov42138042012-03-20 11:51:39 -0700483 *
484 * @param gestureId The unique id of the performed gesture.
485 *
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700486 * @return Whether the gesture was handled.
487 *
Svetoslav Ganov42138042012-03-20 11:51:39 -0700488 * @see #GESTURE_SWIPE_UP
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700489 * @see #GESTURE_SWIPE_UP_AND_LEFT
Svetoslav Ganov42138042012-03-20 11:51:39 -0700490 * @see #GESTURE_SWIPE_UP_AND_DOWN
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700491 * @see #GESTURE_SWIPE_UP_AND_RIGHT
492 * @see #GESTURE_SWIPE_DOWN
493 * @see #GESTURE_SWIPE_DOWN_AND_LEFT
Svetoslav Ganov42138042012-03-20 11:51:39 -0700494 * @see #GESTURE_SWIPE_DOWN_AND_UP
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700495 * @see #GESTURE_SWIPE_DOWN_AND_RIGHT
496 * @see #GESTURE_SWIPE_LEFT
497 * @see #GESTURE_SWIPE_LEFT_AND_UP
Svetoslav Ganov42138042012-03-20 11:51:39 -0700498 * @see #GESTURE_SWIPE_LEFT_AND_RIGHT
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700499 * @see #GESTURE_SWIPE_LEFT_AND_DOWN
500 * @see #GESTURE_SWIPE_RIGHT
501 * @see #GESTURE_SWIPE_RIGHT_AND_UP
Svetoslav Ganov42138042012-03-20 11:51:39 -0700502 * @see #GESTURE_SWIPE_RIGHT_AND_LEFT
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700503 * @see #GESTURE_SWIPE_RIGHT_AND_DOWN
Svetoslav Ganov42138042012-03-20 11:51:39 -0700504 */
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700505 protected boolean onGesture(int gestureId) {
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700506 return false;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700507 }
508
509 /**
Svetoslavc4fccd12013-04-09 12:58:41 -0700510 * Callback that allows an accessibility service to observe the key events
511 * before they are passed to the rest of the system. This means that the events
512 * are first delivered here before they are passed to the device policy, the
513 * input method, or applications.
514 * <p>
515 * <strong>Note:</strong> It is important that key events are handled in such
516 * a way that the event stream that would be passed to the rest of the system
517 * is well-formed. For example, handling the down event but not the up event
518 * and vice versa would generate an inconsistent event stream.
519 * </p>
520 * <p>
521 * <strong>Note:</strong> The key events delivered in this method are copies
522 * and modifying them will have no effect on the events that will be passed
523 * to the system. This method is intended to perform purely filtering
524 * functionality.
525 * <p>
526 *
Phil Weaver96fea022016-03-08 13:05:10 -0800527 * @param event The event to be processed. This event is owned by the caller and cannot be used
528 * after this method returns. Services wishing to use the event after this method returns should
529 * make a copy.
Svetoslavc4fccd12013-04-09 12:58:41 -0700530 * @return If true then the event will be consumed and not delivered to
531 * applications, otherwise it will be delivered as usual.
532 */
533 protected boolean onKeyEvent(KeyEvent event) {
534 return false;
535 }
536
537 /**
Svetoslav8e3feb12014-02-24 13:46:47 -0800538 * Gets the windows on the screen. This method returns only the windows
539 * that a sighted user can interact with, as opposed to all windows.
540 * For example, if there is a modal dialog shown and the user cannot touch
541 * anything behind it, then only the modal window will be reported
542 * (assuming it is the top one). For convenience the returned windows
543 * are ordered in a descending layer order, which is the windows that
Eugene Suslabd573232018-02-26 10:41:28 -0800544 * are on top are reported first. Since the user can always
Svetoslavf7174e82014-06-12 11:29:35 -0700545 * interact with the window that has input focus by typing, the focused
546 * window is always returned (even if covered by a modal window).
Svetoslav8e3feb12014-02-24 13:46:47 -0800547 * <p>
548 * <strong>Note:</strong> In order to access the windows your service has
549 * to declare the capability to retrieve window content by setting the
550 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
551 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
552 * Also the service has to opt-in to retrieve the interactive windows by
553 * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
554 * flag.
555 * </p>
556 *
557 * @return The windows if there are windows and the service is can retrieve
558 * them, otherwise an empty list.
559 */
560 public List<AccessibilityWindowInfo> getWindows() {
561 return AccessibilityInteractionClient.getInstance().getWindows(mConnectionId);
562 }
563
564 /**
Svetoslav Ganov0846e292012-04-18 18:47:13 -0700565 * Gets the root node in the currently active window if this service
Svetoslav8e3feb12014-02-24 13:46:47 -0800566 * can retrieve window content. The active window is the one that the user
567 * is currently touching or the window with input focus, if the user is not
568 * touching any window.
569 * <p>
Phil Weaver40ded282016-01-25 15:49:02 -0800570 * The currently active window is defined as the window that most recently fired one
571 * of the following events:
572 * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
573 * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
574 * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}.
575 * In other words, the last window shown that also has input focus.
576 * </p>
577 * <p>
Svetoslav8e3feb12014-02-24 13:46:47 -0800578 * <strong>Note:</strong> In order to access the root node your service has
579 * to declare the capability to retrieve window content by setting the
580 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
581 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
582 * </p>
Svetoslav Ganov0846e292012-04-18 18:47:13 -0700583 *
584 * @return The root node if this service can retrieve window content.
585 */
586 public AccessibilityNodeInfo getRootInActiveWindow() {
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700587 return AccessibilityInteractionClient.getInstance().getRootInActiveWindow(mConnectionId);
Svetoslav Ganov0846e292012-04-18 18:47:13 -0700588 }
589
590 /**
Phil Weaver40ded282016-01-25 15:49:02 -0800591 * Disables the service. After calling this method, the service will be disabled and settings
592 * will show that it is turned off.
Jinsong Mua9e7a3b2015-12-14 15:58:41 -0800593 */
594 public final void disableSelf() {
595 final IAccessibilityServiceConnection connection =
596 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
597 if (connection != null) {
598 try {
599 connection.disableSelf();
600 } catch (RemoteException re) {
601 throw new RuntimeException(re);
602 }
603 }
604 }
605
606 /**
Alan Viverette214fb682015-11-17 09:47:11 -0500607 * Returns the magnification controller, which may be used to query and
608 * modify the state of display magnification.
609 * <p>
610 * <strong>Note:</strong> In order to control magnification, your service
611 * must declare the capability by setting the
612 * {@link android.R.styleable#AccessibilityService_canControlMagnification}
613 * property in its meta-data. For more information, see
614 * {@link #SERVICE_META_DATA}.
615 *
616 * @return the magnification controller
617 */
618 @NonNull
619 public final MagnificationController getMagnificationController() {
Anna Galusza9b278112016-01-04 11:37:37 -0800620 synchronized (mLock) {
621 if (mMagnificationController == null) {
622 mMagnificationController = new MagnificationController(this, mLock);
623 }
624 return mMagnificationController;
Alan Viverette214fb682015-11-17 09:47:11 -0500625 }
Alan Viverette214fb682015-11-17 09:47:11 -0500626 }
627
Phil Weavera6b64f52015-12-04 15:21:35 -0800628 /**
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800629 * Get the controller for fingerprint gestures. This feature requires {@link
Jeff Sharkey67f9d502017-08-05 13:49:13 -0600630 * AccessibilityServiceInfo#CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES}.
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800631 *
632 *<strong>Note: </strong> The service must be connected before this method is called.
633 *
634 * @return The controller for fingerprint gestures, or {@code null} if gestures are unavailable.
635 */
636 @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT)
Phil Weaverbe2922f2017-04-28 14:58:35 -0700637 public final @NonNull FingerprintGestureController getFingerprintGestureController() {
638 if (mFingerprintGestureController == null) {
639 mFingerprintGestureController = new FingerprintGestureController(
640 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId));
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800641 }
642 return mFingerprintGestureController;
643 }
644
645 /**
Phil Weavera6b64f52015-12-04 15:21:35 -0800646 * Dispatch a gesture to the touch screen. Any gestures currently in progress, whether from
647 * the user, this service, or another service, will be cancelled.
648 * <p>
Phil Weaver155dda12016-04-07 11:06:02 -0700649 * The gesture will be dispatched as if it were performed directly on the screen by a user, so
650 * the events may be affected by features such as magnification and explore by touch.
651 * </p>
652 * <p>
Phil Weavera6b64f52015-12-04 15:21:35 -0800653 * <strong>Note:</strong> In order to dispatch gestures, your service
654 * must declare the capability by setting the
655 * {@link android.R.styleable#AccessibilityService_canPerformGestures}
656 * property in its meta-data. For more information, see
657 * {@link #SERVICE_META_DATA}.
Phil Weaver155dda12016-04-07 11:06:02 -0700658 * </p>
Phil Weavera6b64f52015-12-04 15:21:35 -0800659 *
660 * @param gesture The gesture to dispatch
661 * @param callback The object to call back when the status of the gesture is known. If
662 * {@code null}, no status is reported.
663 * @param handler The handler on which to call back the {@code callback} object. If
664 * {@code null}, the object is called back on the service's main thread.
665 *
666 * @return {@code true} if the gesture is dispatched, {@code false} if not.
667 */
668 public final boolean dispatchGesture(@NonNull GestureDescription gesture,
669 @Nullable GestureResultCallback callback,
670 @Nullable Handler handler) {
671 final IAccessibilityServiceConnection connection =
672 AccessibilityInteractionClient.getInstance().getConnection(
673 mConnectionId);
674 if (connection == null) {
675 return false;
676 }
Phil Weavera8918f22016-08-05 11:23:50 -0700677 List<GestureDescription.GestureStep> steps =
678 MotionEventGenerator.getGestureStepsFromGestureDescription(gesture, 100);
Phil Weavera6b64f52015-12-04 15:21:35 -0800679 try {
680 synchronized (mLock) {
Phil Weaver78d2e2d2016-02-02 14:47:44 -0800681 mGestureStatusCallbackSequence++;
Phil Weavera6b64f52015-12-04 15:21:35 -0800682 if (callback != null) {
683 if (mGestureStatusCallbackInfos == null) {
684 mGestureStatusCallbackInfos = new SparseArray<>();
685 }
686 GestureResultCallbackInfo callbackInfo = new GestureResultCallbackInfo(gesture,
687 callback, handler);
688 mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo);
689 }
Phil Weavera8918f22016-08-05 11:23:50 -0700690 connection.sendGesture(mGestureStatusCallbackSequence,
691 new ParceledListSlice<>(steps));
Phil Weavera6b64f52015-12-04 15:21:35 -0800692 }
693 } catch (RemoteException re) {
694 throw new RuntimeException(re);
695 }
696 return true;
697 }
698
699 void onPerformGestureResult(int sequence, final boolean completedSuccessfully) {
700 if (mGestureStatusCallbackInfos == null) {
701 return;
702 }
703 GestureResultCallbackInfo callbackInfo;
704 synchronized (mLock) {
705 callbackInfo = mGestureStatusCallbackInfos.get(sequence);
706 }
707 final GestureResultCallbackInfo finalCallbackInfo = callbackInfo;
708 if ((callbackInfo != null) && (callbackInfo.gestureDescription != null)
709 && (callbackInfo.callback != null)) {
710 if (callbackInfo.handler != null) {
711 callbackInfo.handler.post(new Runnable() {
712 @Override
713 public void run() {
714 if (completedSuccessfully) {
715 finalCallbackInfo.callback
716 .onCompleted(finalCallbackInfo.gestureDescription);
717 } else {
718 finalCallbackInfo.callback
719 .onCancelled(finalCallbackInfo.gestureDescription);
720 }
721 }
722 });
723 return;
724 }
725 if (completedSuccessfully) {
726 callbackInfo.callback.onCompleted(callbackInfo.gestureDescription);
727 } else {
728 callbackInfo.callback.onCancelled(callbackInfo.gestureDescription);
729 }
730 }
731 }
732
Alan Viverette214fb682015-11-17 09:47:11 -0500733 private void onMagnificationChanged(@NonNull Region region, float scale,
734 float centerX, float centerY) {
735 if (mMagnificationController != null) {
736 mMagnificationController.dispatchMagnificationChanged(
737 region, scale, centerX, centerY);
738 }
739 }
740
741 /**
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800742 * Callback for fingerprint gesture handling
743 * @param active If gesture detection is active
744 */
745 private void onFingerprintCapturingGesturesChanged(boolean active) {
746 getFingerprintGestureController().onGestureDetectionActiveChanged(active);
747 }
748
749 /**
750 * Callback for fingerprint gesture handling
751 * @param gesture The identifier for the gesture performed
752 */
753 private void onFingerprintGesture(int gesture) {
754 getFingerprintGestureController().onGesture(gesture);
755 }
756
757 /**
Alan Viverette214fb682015-11-17 09:47:11 -0500758 * Used to control and query the state of display magnification.
759 */
760 public static final class MagnificationController {
761 private final AccessibilityService mService;
762
763 /**
764 * Map of listeners to their handlers. Lazily created when adding the
765 * first magnification listener.
766 */
767 private ArrayMap<OnMagnificationChangedListener, Handler> mListeners;
Anna Galusza9b278112016-01-04 11:37:37 -0800768 private final Object mLock;
Alan Viverette214fb682015-11-17 09:47:11 -0500769
Anna Galusza9b278112016-01-04 11:37:37 -0800770 MagnificationController(@NonNull AccessibilityService service, @NonNull Object lock) {
Alan Viverette214fb682015-11-17 09:47:11 -0500771 mService = service;
Anna Galusza9b278112016-01-04 11:37:37 -0800772 mLock = lock;
Alan Viverette214fb682015-11-17 09:47:11 -0500773 }
774
775 /**
776 * Called when the service is connected.
777 */
778 void onServiceConnected() {
Anna Galusza9b278112016-01-04 11:37:37 -0800779 synchronized (mLock) {
780 if (mListeners != null && !mListeners.isEmpty()) {
781 setMagnificationCallbackEnabled(true);
782 }
Alan Viverette214fb682015-11-17 09:47:11 -0500783 }
784 }
785
786 /**
787 * Adds the specified change listener to the list of magnification
788 * change listeners. The callback will occur on the service's main
789 * thread.
790 *
791 * @param listener the listener to add, must be non-{@code null}
792 */
793 public void addListener(@NonNull OnMagnificationChangedListener listener) {
794 addListener(listener, null);
795 }
796
797 /**
798 * Adds the specified change listener to the list of magnification
799 * change listeners. The callback will occur on the specified
800 * {@link Handler}'s thread, or on the service's main thread if the
801 * handler is {@code null}.
802 *
803 * @param listener the listener to add, must be non-null
804 * @param handler the handler on which the callback should execute, or
805 * {@code null} to execute on the service's main thread
806 */
807 public void addListener(@NonNull OnMagnificationChangedListener listener,
808 @Nullable Handler handler) {
Anna Galusza9b278112016-01-04 11:37:37 -0800809 synchronized (mLock) {
810 if (mListeners == null) {
811 mListeners = new ArrayMap<>();
812 }
Alan Viverette214fb682015-11-17 09:47:11 -0500813
Anna Galusza9b278112016-01-04 11:37:37 -0800814 final boolean shouldEnableCallback = mListeners.isEmpty();
815 mListeners.put(listener, handler);
Alan Viverette214fb682015-11-17 09:47:11 -0500816
Anna Galusza9b278112016-01-04 11:37:37 -0800817 if (shouldEnableCallback) {
818 // This may fail if the service is not connected yet, but if we
819 // still have listeners when it connects then we can try again.
820 setMagnificationCallbackEnabled(true);
821 }
Alan Viverette214fb682015-11-17 09:47:11 -0500822 }
823 }
824
825 /**
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800826 * Removes the specified change listener from the list of magnification change listeners.
Alan Viverette214fb682015-11-17 09:47:11 -0500827 *
828 * @param listener the listener to remove, must be non-null
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800829 * @return {@code true} if the listener was removed, {@code false} otherwise
Alan Viverette214fb682015-11-17 09:47:11 -0500830 */
831 public boolean removeListener(@NonNull OnMagnificationChangedListener listener) {
832 if (mListeners == null) {
833 return false;
834 }
835
Anna Galusza9b278112016-01-04 11:37:37 -0800836 synchronized (mLock) {
837 final int keyIndex = mListeners.indexOfKey(listener);
838 final boolean hasKey = keyIndex >= 0;
839 if (hasKey) {
840 mListeners.removeAt(keyIndex);
841 }
Alan Viverette214fb682015-11-17 09:47:11 -0500842
Anna Galusza9b278112016-01-04 11:37:37 -0800843 if (hasKey && mListeners.isEmpty()) {
844 // We just removed the last listener, so we don't need
845 // callbacks from the service anymore.
846 setMagnificationCallbackEnabled(false);
847 }
Alan Viverette214fb682015-11-17 09:47:11 -0500848
Anna Galusza9b278112016-01-04 11:37:37 -0800849 return hasKey;
850 }
Alan Viverette214fb682015-11-17 09:47:11 -0500851 }
852
853 private void setMagnificationCallbackEnabled(boolean enabled) {
854 final IAccessibilityServiceConnection connection =
855 AccessibilityInteractionClient.getInstance().getConnection(
856 mService.mConnectionId);
857 if (connection != null) {
858 try {
859 connection.setMagnificationCallbackEnabled(enabled);
860 } catch (RemoteException re) {
861 throw new RuntimeException(re);
862 }
863 }
864 }
865
866 /**
867 * Dispatches magnification changes to any registered listeners. This
868 * should be called on the service's main thread.
869 */
870 void dispatchMagnificationChanged(final @NonNull Region region, final float scale,
871 final float centerX, final float centerY) {
Anna Galusza9b278112016-01-04 11:37:37 -0800872 final ArrayMap<OnMagnificationChangedListener, Handler> entries;
873 synchronized (mLock) {
874 if (mListeners == null || mListeners.isEmpty()) {
875 Slog.d(LOG_TAG, "Received magnification changed "
876 + "callback with no listeners registered!");
877 setMagnificationCallbackEnabled(false);
878 return;
879 }
Alan Viverette214fb682015-11-17 09:47:11 -0500880
Anna Galusza9b278112016-01-04 11:37:37 -0800881 // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
882 // modification.
883 entries = new ArrayMap<>(mListeners);
884 }
Alan Viverette214fb682015-11-17 09:47:11 -0500885
886 for (int i = 0, count = entries.size(); i < count; i++) {
887 final OnMagnificationChangedListener listener = entries.keyAt(i);
888 final Handler handler = entries.valueAt(i);
889 if (handler != null) {
890 handler.post(new Runnable() {
891 @Override
892 public void run() {
893 listener.onMagnificationChanged(MagnificationController.this,
894 region, scale, centerX, centerY);
895 }
896 });
897 } else {
898 // We're already on the main thread, just run the listener.
899 listener.onMagnificationChanged(this, region, scale, centerX, centerY);
900 }
901 }
902 }
903
904 /**
905 * Returns the current magnification scale.
906 * <p>
907 * <strong>Note:</strong> If the service is not yet connected (e.g.
908 * {@link AccessibilityService#onServiceConnected()} has not yet been
909 * called) or the service has been disconnected, this method will
910 * return a default value of {@code 1.0f}.
911 *
912 * @return the current magnification scale
913 */
914 public float getScale() {
915 final IAccessibilityServiceConnection connection =
916 AccessibilityInteractionClient.getInstance().getConnection(
917 mService.mConnectionId);
918 if (connection != null) {
919 try {
920 return connection.getMagnificationScale();
921 } catch (RemoteException re) {
922 Log.w(LOG_TAG, "Failed to obtain scale", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -0800923 re.rethrowFromSystemServer();
Alan Viverette214fb682015-11-17 09:47:11 -0500924 }
925 }
926 return 1.0f;
927 }
928
929 /**
930 * Returns the unscaled screen-relative X coordinate of the focal
931 * center of the magnified region. This is the point around which
932 * zooming occurs and is guaranteed to lie within the magnified
933 * region.
934 * <p>
935 * <strong>Note:</strong> If the service is not yet connected (e.g.
936 * {@link AccessibilityService#onServiceConnected()} has not yet been
937 * called) or the service has been disconnected, this method will
938 * return a default value of {@code 0.0f}.
939 *
940 * @return the unscaled screen-relative X coordinate of the center of
941 * the magnified region
942 */
943 public float getCenterX() {
944 final IAccessibilityServiceConnection connection =
945 AccessibilityInteractionClient.getInstance().getConnection(
946 mService.mConnectionId);
947 if (connection != null) {
948 try {
949 return connection.getMagnificationCenterX();
950 } catch (RemoteException re) {
951 Log.w(LOG_TAG, "Failed to obtain center X", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -0800952 re.rethrowFromSystemServer();
Alan Viverette214fb682015-11-17 09:47:11 -0500953 }
954 }
955 return 0.0f;
956 }
957
958 /**
959 * Returns the unscaled screen-relative Y coordinate of the focal
960 * center of the magnified region. This is the point around which
961 * zooming occurs and is guaranteed to lie within the magnified
962 * region.
963 * <p>
964 * <strong>Note:</strong> If the service is not yet connected (e.g.
965 * {@link AccessibilityService#onServiceConnected()} has not yet been
966 * called) or the service has been disconnected, this method will
967 * return a default value of {@code 0.0f}.
968 *
969 * @return the unscaled screen-relative Y coordinate of the center of
970 * the magnified region
971 */
972 public float getCenterY() {
973 final IAccessibilityServiceConnection connection =
974 AccessibilityInteractionClient.getInstance().getConnection(
975 mService.mConnectionId);
976 if (connection != null) {
977 try {
978 return connection.getMagnificationCenterY();
979 } catch (RemoteException re) {
980 Log.w(LOG_TAG, "Failed to obtain center Y", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -0800981 re.rethrowFromSystemServer();
Alan Viverette214fb682015-11-17 09:47:11 -0500982 }
983 }
984 return 0.0f;
985 }
986
987 /**
Phil Weaver70439242016-03-10 15:15:49 -0800988 * Returns the region of the screen currently active for magnification. Changes to
989 * magnification scale and center only affect this portion of the screen. The rest of the
990 * screen, for example input methods, cannot be magnified. This region is relative to the
991 * unscaled screen and is independent of the scale and center point.
992 * <p>
993 * The returned region will be empty if magnification is not active. Magnification is active
994 * if magnification gestures are enabled or if a service is running that can control
995 * magnification.
Alan Viverette214fb682015-11-17 09:47:11 -0500996 * <p>
997 * <strong>Note:</strong> If the service is not yet connected (e.g.
998 * {@link AccessibilityService#onServiceConnected()} has not yet been
999 * called) or the service has been disconnected, this method will
1000 * return an empty region.
1001 *
Phil Weaver70439242016-03-10 15:15:49 -08001002 * @return the region of the screen currently active for magnification, or an empty region
1003 * if magnification is not active.
Alan Viverette214fb682015-11-17 09:47:11 -05001004 */
1005 @NonNull
Phil Weaver70439242016-03-10 15:15:49 -08001006 public Region getMagnificationRegion() {
Alan Viverette214fb682015-11-17 09:47:11 -05001007 final IAccessibilityServiceConnection connection =
1008 AccessibilityInteractionClient.getInstance().getConnection(
1009 mService.mConnectionId);
1010 if (connection != null) {
1011 try {
Phil Weaver2fbdd482016-05-02 09:39:07 -07001012 return connection.getMagnificationRegion();
Alan Viverette214fb682015-11-17 09:47:11 -05001013 } catch (RemoteException re) {
1014 Log.w(LOG_TAG, "Failed to obtain magnified region", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001015 re.rethrowFromSystemServer();
Alan Viverette214fb682015-11-17 09:47:11 -05001016 }
1017 }
1018 return Region.obtain();
1019 }
1020
1021 /**
1022 * Resets magnification scale and center to their default (e.g. no
1023 * magnification) values.
1024 * <p>
1025 * <strong>Note:</strong> If the service is not yet connected (e.g.
1026 * {@link AccessibilityService#onServiceConnected()} has not yet been
1027 * called) or the service has been disconnected, this method will have
1028 * no effect and return {@code false}.
1029 *
1030 * @param animate {@code true} to animate from the current scale and
1031 * center or {@code false} to reset the scale and center
1032 * immediately
1033 * @return {@code true} on success, {@code false} on failure
1034 */
1035 public boolean reset(boolean animate) {
1036 final IAccessibilityServiceConnection connection =
1037 AccessibilityInteractionClient.getInstance().getConnection(
1038 mService.mConnectionId);
1039 if (connection != null) {
1040 try {
1041 return connection.resetMagnification(animate);
1042 } catch (RemoteException re) {
1043 Log.w(LOG_TAG, "Failed to reset", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001044 re.rethrowFromSystemServer();
Alan Viverette214fb682015-11-17 09:47:11 -05001045 }
1046 }
1047 return false;
1048 }
1049
1050 /**
1051 * Sets the magnification scale.
1052 * <p>
1053 * <strong>Note:</strong> If the service is not yet connected (e.g.
1054 * {@link AccessibilityService#onServiceConnected()} has not yet been
1055 * called) or the service has been disconnected, this method will have
1056 * no effect and return {@code false}.
1057 *
1058 * @param scale the magnification scale to set, must be >= 1 and <= 5
1059 * @param animate {@code true} to animate from the current scale or
1060 * {@code false} to set the scale immediately
1061 * @return {@code true} on success, {@code false} on failure
1062 */
1063 public boolean setScale(float scale, boolean animate) {
1064 final IAccessibilityServiceConnection connection =
1065 AccessibilityInteractionClient.getInstance().getConnection(
1066 mService.mConnectionId);
1067 if (connection != null) {
1068 try {
1069 return connection.setMagnificationScaleAndCenter(
1070 scale, Float.NaN, Float.NaN, animate);
1071 } catch (RemoteException re) {
1072 Log.w(LOG_TAG, "Failed to set scale", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001073 re.rethrowFromSystemServer();
Alan Viverette214fb682015-11-17 09:47:11 -05001074 }
1075 }
1076 return false;
1077 }
1078
1079 /**
1080 * Sets the center of the magnified viewport.
1081 * <p>
1082 * <strong>Note:</strong> If the service is not yet connected (e.g.
1083 * {@link AccessibilityService#onServiceConnected()} has not yet been
1084 * called) or the service has been disconnected, this method will have
1085 * no effect and return {@code false}.
1086 *
1087 * @param centerX the unscaled screen-relative X coordinate on which to
1088 * center the viewport
1089 * @param centerY the unscaled screen-relative Y coordinate on which to
1090 * center the viewport
1091 * @param animate {@code true} to animate from the current viewport
1092 * center or {@code false} to set the center immediately
1093 * @return {@code true} on success, {@code false} on failure
1094 */
1095 public boolean setCenter(float centerX, float centerY, boolean animate) {
1096 final IAccessibilityServiceConnection connection =
1097 AccessibilityInteractionClient.getInstance().getConnection(
1098 mService.mConnectionId);
1099 if (connection != null) {
1100 try {
1101 return connection.setMagnificationScaleAndCenter(
1102 Float.NaN, centerX, centerY, animate);
1103 } catch (RemoteException re) {
1104 Log.w(LOG_TAG, "Failed to set center", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001105 re.rethrowFromSystemServer();
Alan Viverette214fb682015-11-17 09:47:11 -05001106 }
1107 }
1108 return false;
1109 }
1110
1111 /**
1112 * Listener for changes in the state of magnification.
1113 */
1114 public interface OnMagnificationChangedListener {
1115 /**
1116 * Called when the magnified region, scale, or center changes.
1117 *
1118 * @param controller the magnification controller
Phil Weaver70439242016-03-10 15:15:49 -08001119 * @param region the magnification region
Alan Viverette214fb682015-11-17 09:47:11 -05001120 * @param scale the new scale
Phil Weaver70439242016-03-10 15:15:49 -08001121 * @param centerX the new X coordinate, in unscaled coordinates, around which
1122 * magnification is focused
1123 * @param centerY the new Y coordinate, in unscaled coordinates, around which
1124 * magnification is focused
Alan Viverette214fb682015-11-17 09:47:11 -05001125 */
1126 void onMagnificationChanged(@NonNull MagnificationController controller,
1127 @NonNull Region region, float scale, float centerX, float centerY);
1128 }
1129 }
1130
1131 /**
Anna Galusza9b278112016-01-04 11:37:37 -08001132 * Returns the soft keyboard controller, which may be used to query and modify the soft keyboard
1133 * show mode.
1134 *
1135 * @return the soft keyboard controller
1136 */
1137 @NonNull
1138 public final SoftKeyboardController getSoftKeyboardController() {
1139 synchronized (mLock) {
1140 if (mSoftKeyboardController == null) {
1141 mSoftKeyboardController = new SoftKeyboardController(this, mLock);
1142 }
1143 return mSoftKeyboardController;
1144 }
1145 }
1146
1147 private void onSoftKeyboardShowModeChanged(int showMode) {
1148 if (mSoftKeyboardController != null) {
1149 mSoftKeyboardController.dispatchSoftKeyboardShowModeChanged(showMode);
1150 }
1151 }
1152
1153 /**
1154 * Used to control and query the soft keyboard show mode.
1155 */
1156 public static final class SoftKeyboardController {
1157 private final AccessibilityService mService;
1158
1159 /**
1160 * Map of listeners to their handlers. Lazily created when adding the first
1161 * soft keyboard change listener.
1162 */
1163 private ArrayMap<OnShowModeChangedListener, Handler> mListeners;
1164 private final Object mLock;
1165
1166 SoftKeyboardController(@NonNull AccessibilityService service, @NonNull Object lock) {
1167 mService = service;
1168 mLock = lock;
1169 }
1170
1171 /**
1172 * Called when the service is connected.
1173 */
1174 void onServiceConnected() {
1175 synchronized(mLock) {
1176 if (mListeners != null && !mListeners.isEmpty()) {
1177 setSoftKeyboardCallbackEnabled(true);
1178 }
1179 }
1180 }
1181
1182 /**
1183 * Adds the specified change listener to the list of show mode change listeners. The
1184 * callback will occur on the service's main thread. Listener is not called on registration.
1185 */
1186 public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
1187 addOnShowModeChangedListener(listener, null);
1188 }
1189
1190 /**
1191 * Adds the specified change listener to the list of soft keyboard show mode change
1192 * listeners. The callback will occur on the specified {@link Handler}'s thread, or on the
1193 * services's main thread if the handler is {@code null}.
1194 *
1195 * @param listener the listener to add, must be non-null
1196 * @param handler the handler on which to callback should execute, or {@code null} to
1197 * execute on the service's main thread
1198 */
1199 public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener,
1200 @Nullable Handler handler) {
1201 synchronized (mLock) {
1202 if (mListeners == null) {
1203 mListeners = new ArrayMap<>();
1204 }
1205
1206 final boolean shouldEnableCallback = mListeners.isEmpty();
1207 mListeners.put(listener, handler);
1208
1209 if (shouldEnableCallback) {
1210 // This may fail if the service is not connected yet, but if we still have
1211 // listeners when it connects, we can try again.
1212 setSoftKeyboardCallbackEnabled(true);
1213 }
1214 }
1215 }
1216
1217 /**
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001218 * Removes the specified change listener from the list of keyboard show mode change
1219 * listeners.
Anna Galusza9b278112016-01-04 11:37:37 -08001220 *
1221 * @param listener the listener to remove, must be non-null
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001222 * @return {@code true} if the listener was removed, {@code false} otherwise
Anna Galusza9b278112016-01-04 11:37:37 -08001223 */
1224 public boolean removeOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
1225 if (mListeners == null) {
1226 return false;
1227 }
1228
1229 synchronized (mLock) {
1230 final int keyIndex = mListeners.indexOfKey(listener);
1231 final boolean hasKey = keyIndex >= 0;
1232 if (hasKey) {
1233 mListeners.removeAt(keyIndex);
1234 }
1235
1236 if (hasKey && mListeners.isEmpty()) {
1237 // We just removed the last listener, so we don't need callbacks from the
1238 // service anymore.
1239 setSoftKeyboardCallbackEnabled(false);
1240 }
1241
1242 return hasKey;
1243 }
1244 }
1245
1246 private void setSoftKeyboardCallbackEnabled(boolean enabled) {
1247 final IAccessibilityServiceConnection connection =
1248 AccessibilityInteractionClient.getInstance().getConnection(
1249 mService.mConnectionId);
1250 if (connection != null) {
1251 try {
1252 connection.setSoftKeyboardCallbackEnabled(enabled);
1253 } catch (RemoteException re) {
1254 throw new RuntimeException(re);
1255 }
1256 }
1257 }
1258
1259 /**
1260 * Dispatches the soft keyboard show mode change to any registered listeners. This should
1261 * be called on the service's main thread.
1262 */
1263 void dispatchSoftKeyboardShowModeChanged(final int showMode) {
1264 final ArrayMap<OnShowModeChangedListener, Handler> entries;
1265 synchronized (mLock) {
1266 if (mListeners == null || mListeners.isEmpty()) {
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001267 Slog.w(LOG_TAG, "Received soft keyboard show mode changed callback"
Anna Galusza9b278112016-01-04 11:37:37 -08001268 + " with no listeners registered!");
1269 setSoftKeyboardCallbackEnabled(false);
1270 return;
1271 }
1272
1273 // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
1274 // modification.
1275 entries = new ArrayMap<>(mListeners);
1276 }
1277
1278 for (int i = 0, count = entries.size(); i < count; i++) {
1279 final OnShowModeChangedListener listener = entries.keyAt(i);
1280 final Handler handler = entries.valueAt(i);
1281 if (handler != null) {
1282 handler.post(new Runnable() {
1283 @Override
1284 public void run() {
1285 listener.onShowModeChanged(SoftKeyboardController.this, showMode);
1286 }
1287 });
1288 } else {
1289 // We're already on the main thread, just run the listener.
1290 listener.onShowModeChanged(this, showMode);
1291 }
1292 }
1293 }
1294
1295 /**
1296 * Returns the show mode of the soft keyboard. The default show mode is
Anna Galusza32042512016-02-29 15:39:08 -08001297 * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
1298 * focused. An AccessibilityService can also request the show mode
1299 * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
Anna Galusza9b278112016-01-04 11:37:37 -08001300 *
1301 * @return the current soft keyboard show mode
Anna Galusza9b278112016-01-04 11:37:37 -08001302 */
1303 @SoftKeyboardShowMode
1304 public int getShowMode() {
1305 try {
1306 return Settings.Secure.getInt(mService.getContentResolver(),
1307 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
1308 } catch (Settings.SettingNotFoundException e) {
1309 Log.v(LOG_TAG, "Failed to obtain the soft keyboard mode", e);
1310 // The settings hasn't been changed yet, so it's value is null. Return the default.
1311 return 0;
1312 }
1313 }
1314
1315 /**
1316 * Sets the soft keyboard show mode. The default show mode is
Anna Galusza32042512016-02-29 15:39:08 -08001317 * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
1318 * focused. An AccessibilityService can also request the show mode
1319 * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. The
Anna Galusza9b278112016-01-04 11:37:37 -08001320 * The lastto this method will be honored, regardless of any previous calls (including those
1321 * made by other AccessibilityServices).
1322 * <p>
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001323 * <strong>Note:</strong> If the service is not yet connected (e.g.
Anna Galusza9b278112016-01-04 11:37:37 -08001324 * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001325 * service has been disconnected, this method will have no effect and return {@code false}.
Anna Galusza9b278112016-01-04 11:37:37 -08001326 *
1327 * @param showMode the new show mode for the soft keyboard
1328 * @return {@code true} on success
Anna Galusza9b278112016-01-04 11:37:37 -08001329 */
1330 public boolean setShowMode(@SoftKeyboardShowMode int showMode) {
1331 final IAccessibilityServiceConnection connection =
1332 AccessibilityInteractionClient.getInstance().getConnection(
1333 mService.mConnectionId);
1334 if (connection != null) {
1335 try {
1336 return connection.setSoftKeyboardShowMode(showMode);
1337 } catch (RemoteException re) {
Anna Galusza32042512016-02-29 15:39:08 -08001338 Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re);
1339 re.rethrowFromSystemServer();
Anna Galusza9b278112016-01-04 11:37:37 -08001340 }
1341 }
1342 return false;
1343 }
1344
1345 /**
1346 * Listener for changes in the soft keyboard show mode.
1347 */
1348 public interface OnShowModeChangedListener {
1349 /**
1350 * Called when the soft keyboard behavior changes. The default show mode is
Anna Galusza32042512016-02-29 15:39:08 -08001351 * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
1352 * focused. An AccessibilityService can also request the show mode
1353 * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
Anna Galusza9b278112016-01-04 11:37:37 -08001354 *
1355 * @param controller the soft keyboard controller
1356 * @param showMode the current soft keyboard show mode
1357 */
1358 void onShowModeChanged(@NonNull SoftKeyboardController controller,
1359 @SoftKeyboardShowMode int showMode);
1360 }
1361 }
1362
1363 /**
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001364 * Returns the controller for the accessibility button within the system's navigation area.
1365 * This instance may be used to query the accessibility button's state and register listeners
1366 * for interactions with and state changes for the accessibility button when
1367 * {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set.
1368 * <p>
1369 * <strong>Note:</strong> Not all devices are capable of displaying the accessibility button
1370 * within a navigation area, and as such, use of this class should be considered only as an
1371 * optional feature or shortcut on supported device implementations.
1372 * </p>
1373 *
1374 * @return the accessibility button controller for this {@link AccessibilityService}
1375 */
1376 @NonNull
1377 public final AccessibilityButtonController getAccessibilityButtonController() {
1378 synchronized (mLock) {
1379 if (mAccessibilityButtonController == null) {
1380 mAccessibilityButtonController = new AccessibilityButtonController(
1381 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId));
1382 }
1383 return mAccessibilityButtonController;
1384 }
1385 }
1386
1387 private void onAccessibilityButtonClicked() {
1388 getAccessibilityButtonController().dispatchAccessibilityButtonClicked();
1389 }
1390
1391 private void onAccessibilityButtonAvailabilityChanged(boolean available) {
1392 getAccessibilityButtonController().dispatchAccessibilityButtonAvailabilityChanged(
1393 available);
1394 }
1395
1396 /**
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07001397 * Performs a global action. Such an action can be performed
1398 * at any moment regardless of the current application or user
1399 * location in that application. For example going back, going
1400 * home, opening recents, etc.
1401 *
1402 * @param action The action to perform.
1403 * @return Whether the action was successfully performed.
1404 *
1405 * @see #GLOBAL_ACTION_BACK
1406 * @see #GLOBAL_ACTION_HOME
1407 * @see #GLOBAL_ACTION_NOTIFICATIONS
1408 * @see #GLOBAL_ACTION_RECENTS
1409 */
1410 public final boolean performGlobalAction(int action) {
1411 IAccessibilityServiceConnection connection =
1412 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
1413 if (connection != null) {
1414 try {
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -07001415 return connection.performGlobalAction(action);
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07001416 } catch (RemoteException re) {
1417 Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001418 re.rethrowFromSystemServer();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07001419 }
1420 }
1421 return false;
1422 }
1423
1424 /**
Svetoslav1e0d4af2014-04-10 17:41:29 -07001425 * Find the view that has the specified focus type. The search is performed
1426 * across all windows.
1427 * <p>
1428 * <strong>Note:</strong> In order to access the windows your service has
1429 * to declare the capability to retrieve window content by setting the
1430 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
1431 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
1432 * Also the service has to opt-in to retrieve the interactive windows by
1433 * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
Phil Weaver40ded282016-01-25 15:49:02 -08001434 * flag. Otherwise, the search will be performed only in the active window.
Svetoslav1e0d4af2014-04-10 17:41:29 -07001435 * </p>
1436 *
1437 * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
1438 * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
1439 * @return The node info of the focused view or null.
1440 *
1441 * @see AccessibilityNodeInfo#FOCUS_INPUT
1442 * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
1443 */
1444 public AccessibilityNodeInfo findFocus(int focus) {
1445 return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
Phil Weaverf00cd142017-03-03 13:44:00 -08001446 AccessibilityWindowInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
Svetoslav1e0d4af2014-04-10 17:41:29 -07001447 }
1448
1449 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -07001450 * Gets the an {@link AccessibilityServiceInfo} describing this
1451 * {@link AccessibilityService}. This method is useful if one wants
1452 * to change some of the dynamically configurable properties at
1453 * runtime.
1454 *
1455 * @return The accessibility service info.
1456 *
Svetoslavbbfa5852013-02-11 19:38:12 -08001457 * @see AccessibilityServiceInfo
Svetoslav Ganov42138042012-03-20 11:51:39 -07001458 */
1459 public final AccessibilityServiceInfo getServiceInfo() {
1460 IAccessibilityServiceConnection connection =
1461 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
1462 if (connection != null) {
1463 try {
1464 return connection.getServiceInfo();
1465 } catch (RemoteException re) {
1466 Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001467 re.rethrowFromSystemServer();
Svetoslav Ganov42138042012-03-20 11:51:39 -07001468 }
1469 }
1470 return null;
1471 }
1472
1473 /**
svetoslavganov75986cf2009-05-14 22:28:01 -07001474 * Sets the {@link AccessibilityServiceInfo} that describes this service.
1475 * <p>
1476 * Note: You can call this method any time but the info will be picked up after
1477 * the system has bound to this service and when this method is called thereafter.
1478 *
1479 * @param info The info.
1480 */
1481 public final void setServiceInfo(AccessibilityServiceInfo info) {
1482 mInfo = info;
1483 sendServiceInfo();
1484 }
1485
1486 /**
1487 * Sets the {@link AccessibilityServiceInfo} for this service if the latter is
1488 * properly set and there is an {@link IAccessibilityServiceConnection} to the
1489 * AccessibilityManagerService.
1490 */
1491 private void sendServiceInfo() {
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001492 IAccessibilityServiceConnection connection =
1493 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
1494 if (mInfo != null && connection != null) {
svetoslavganov75986cf2009-05-14 22:28:01 -07001495 try {
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001496 connection.setServiceInfo(mInfo);
Svetoslav Ganov42138042012-03-20 11:51:39 -07001497 mInfo = null;
1498 AccessibilityInteractionClient.getInstance().clearCache();
svetoslavganov75986cf2009-05-14 22:28:01 -07001499 } catch (RemoteException re) {
1500 Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
Phil Weaver4503fcf2016-03-08 16:29:44 -08001501 re.rethrowFromSystemServer();
svetoslavganov75986cf2009-05-14 22:28:01 -07001502 }
1503 }
1504 }
1505
Alan Viverette7c9746d4e2014-11-19 17:02:16 -08001506 @Override
1507 public Object getSystemService(@ServiceName @NonNull String name) {
1508 if (getBaseContext() == null) {
1509 throw new IllegalStateException(
1510 "System services not available to Activities before onCreate()");
1511 }
1512
1513 // Guarantee that we always return the same window manager instance.
1514 if (WINDOW_SERVICE.equals(name)) {
1515 if (mWindowManager == null) {
1516 mWindowManager = (WindowManager) getBaseContext().getSystemService(name);
1517 }
1518 return mWindowManager;
1519 }
1520 return super.getSystemService(name);
1521 }
1522
Dianne Hackborn7f205432009-07-28 00:13:47 -07001523 /**
1524 * Implement to return the implementation of the internal accessibility
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001525 * service interface.
Dianne Hackborn7f205432009-07-28 00:13:47 -07001526 */
svetoslavganov75986cf2009-05-14 22:28:01 -07001527 @Override
1528 public final IBinder onBind(Intent intent) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07001529 return new IAccessibilityServiceClientWrapper(this, getMainLooper(), new Callbacks() {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001530 @Override
1531 public void onServiceConnected() {
Alan Viverette214fb682015-11-17 09:47:11 -05001532 AccessibilityService.this.dispatchServiceConnected();
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001533 }
1534
1535 @Override
1536 public void onInterrupt() {
1537 AccessibilityService.this.onInterrupt();
1538 }
1539
1540 @Override
1541 public void onAccessibilityEvent(AccessibilityEvent event) {
1542 AccessibilityService.this.onAccessibilityEvent(event);
1543 }
1544
1545 @Override
Svetoslav3a5c7212014-10-14 09:54:26 -07001546 public void init(int connectionId, IBinder windowToken) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001547 mConnectionId = connectionId;
Svetoslav3a5c7212014-10-14 09:54:26 -07001548 mWindowToken = windowToken;
Alan Viveretted2fa5142014-11-04 17:40:29 -08001549
Alan Viverette7c9746d4e2014-11-19 17:02:16 -08001550 // The client may have already obtained the window manager, so
1551 // update the default token on whatever manager we gave them.
1552 final WindowManagerImpl wm = (WindowManagerImpl) getSystemService(WINDOW_SERVICE);
1553 wm.setDefaultToken(windowToken);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001554 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07001555
1556 @Override
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -07001557 public boolean onGesture(int gestureId) {
1558 return AccessibilityService.this.onGesture(gestureId);
Svetoslav Ganov42138042012-03-20 11:51:39 -07001559 }
Svetoslavc4fccd12013-04-09 12:58:41 -07001560
1561 @Override
1562 public boolean onKeyEvent(KeyEvent event) {
1563 return AccessibilityService.this.onKeyEvent(event);
1564 }
Alan Viverette214fb682015-11-17 09:47:11 -05001565
1566 @Override
1567 public void onMagnificationChanged(@NonNull Region region,
1568 float scale, float centerX, float centerY) {
1569 AccessibilityService.this.onMagnificationChanged(region, scale, centerX, centerY);
1570 }
Phil Weavera6b64f52015-12-04 15:21:35 -08001571
1572 @Override
Anna Galusza9b278112016-01-04 11:37:37 -08001573 public void onSoftKeyboardShowModeChanged(int showMode) {
1574 AccessibilityService.this.onSoftKeyboardShowModeChanged(showMode);
1575 }
1576
1577 @Override
Phil Weavera6b64f52015-12-04 15:21:35 -08001578 public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
1579 AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully);
1580 }
Phil Weaver27fcd9c2017-01-20 15:57:24 -08001581
1582 @Override
1583 public void onFingerprintCapturingGesturesChanged(boolean active) {
1584 AccessibilityService.this.onFingerprintCapturingGesturesChanged(active);
1585 }
1586
1587 @Override
1588 public void onFingerprintGesture(int gesture) {
1589 AccessibilityService.this.onFingerprintGesture(gesture);
1590 }
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001591
1592 @Override
1593 public void onAccessibilityButtonClicked() {
1594 AccessibilityService.this.onAccessibilityButtonClicked();
1595 }
1596
1597 @Override
1598 public void onAccessibilityButtonAvailabilityChanged(boolean available) {
1599 AccessibilityService.this.onAccessibilityButtonAvailabilityChanged(available);
1600 }
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001601 });
svetoslavganov75986cf2009-05-14 22:28:01 -07001602 }
1603
1604 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -07001605 * Implements the internal {@link IAccessibilityServiceClient} interface to convert
svetoslavganov75986cf2009-05-14 22:28:01 -07001606 * incoming calls to it back to calls on an {@link AccessibilityService}.
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001607 *
1608 * @hide
svetoslavganov75986cf2009-05-14 22:28:01 -07001609 */
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001610 public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
svetoslavganov75986cf2009-05-14 22:28:01 -07001611 implements HandlerCaller.Callback {
Svetoslav3a5c7212014-10-14 09:54:26 -07001612 private static final int DO_INIT = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -08001613 private static final int DO_ON_INTERRUPT = 2;
1614 private static final int DO_ON_ACCESSIBILITY_EVENT = 3;
1615 private static final int DO_ON_GESTURE = 4;
1616 private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5;
1617 private static final int DO_ON_KEY_EVENT = 6;
Alan Viverette214fb682015-11-17 09:47:11 -05001618 private static final int DO_ON_MAGNIFICATION_CHANGED = 7;
Anna Galusza9b278112016-01-04 11:37:37 -08001619 private static final int DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED = 8;
1620 private static final int DO_GESTURE_COMPLETE = 9;
Phil Weaver27fcd9c2017-01-20 15:57:24 -08001621 private static final int DO_ON_FINGERPRINT_ACTIVE_CHANGED = 10;
1622 private static final int DO_ON_FINGERPRINT_GESTURE = 11;
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001623 private static final int DO_ACCESSIBILITY_BUTTON_CLICKED = 12;
1624 private static final int DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 13;
svetoslavganov75986cf2009-05-14 22:28:01 -07001625
1626 private final HandlerCaller mCaller;
1627
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001628 private final Callbacks mCallback;
svetoslavganov75986cf2009-05-14 22:28:01 -07001629
Phil Weaver6f2da202017-09-05 16:00:38 -07001630 private int mConnectionId = AccessibilityInteractionClient.NO_ID;
Svetoslavc4fccd12013-04-09 12:58:41 -07001631
Svetoslav Ganov42138042012-03-20 11:51:39 -07001632 public IAccessibilityServiceClientWrapper(Context context, Looper looper,
1633 Callbacks callback) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001634 mCallback = callback;
Mita Yuned218c72012-12-06 17:18:25 -08001635 mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/);
svetoslavganov75986cf2009-05-14 22:28:01 -07001636 }
1637
Svetoslav3a5c7212014-10-14 09:54:26 -07001638 public void init(IAccessibilityServiceConnection connection, int connectionId,
1639 IBinder windowToken) {
1640 Message message = mCaller.obtainMessageIOO(DO_INIT, connectionId,
1641 connection, windowToken);
svetoslavganov75986cf2009-05-14 22:28:01 -07001642 mCaller.sendMessage(message);
1643 }
1644
1645 public void onInterrupt() {
1646 Message message = mCaller.obtainMessage(DO_ON_INTERRUPT);
1647 mCaller.sendMessage(message);
1648 }
1649
Eugene Suslaeb1375c2016-12-20 16:32:59 -08001650 public void onAccessibilityEvent(AccessibilityEvent event, boolean serviceWantsEvent) {
1651 Message message = mCaller.obtainMessageBO(
1652 DO_ON_ACCESSIBILITY_EVENT, serviceWantsEvent, event);
svetoslavganov75986cf2009-05-14 22:28:01 -07001653 mCaller.sendMessage(message);
1654 }
1655
Svetoslav Ganov7b1e0c72012-05-13 11:57:29 -07001656 public void onGesture(int gestureId) {
1657 Message message = mCaller.obtainMessageI(DO_ON_GESTURE, gestureId);
Svetoslav Ganov42138042012-03-20 11:51:39 -07001658 mCaller.sendMessage(message);
1659 }
1660
Svetoslav8e3feb12014-02-24 13:46:47 -08001661 public void clearAccessibilityCache() {
1662 Message message = mCaller.obtainMessage(DO_CLEAR_ACCESSIBILITY_CACHE);
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07001663 mCaller.sendMessage(message);
1664 }
1665
Svetoslavc4fccd12013-04-09 12:58:41 -07001666 @Override
1667 public void onKeyEvent(KeyEvent event, int sequence) {
1668 Message message = mCaller.obtainMessageIO(DO_ON_KEY_EVENT, sequence, event);
1669 mCaller.sendMessage(message);
1670 }
1671
Alan Viverette214fb682015-11-17 09:47:11 -05001672 public void onMagnificationChanged(@NonNull Region region,
1673 float scale, float centerX, float centerY) {
1674 final SomeArgs args = SomeArgs.obtain();
1675 args.arg1 = region;
1676 args.arg2 = scale;
1677 args.arg3 = centerX;
1678 args.arg4 = centerY;
1679
1680 final Message message = mCaller.obtainMessageO(DO_ON_MAGNIFICATION_CHANGED, args);
1681 mCaller.sendMessage(message);
1682 }
1683
Anna Galusza9b278112016-01-04 11:37:37 -08001684 public void onSoftKeyboardShowModeChanged(int showMode) {
1685 final Message message =
1686 mCaller.obtainMessageI(DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED, showMode);
1687 mCaller.sendMessage(message);
1688 }
1689
Phil Weavera6b64f52015-12-04 15:21:35 -08001690 public void onPerformGestureResult(int sequence, boolean successfully) {
1691 Message message = mCaller.obtainMessageII(DO_GESTURE_COMPLETE, sequence,
1692 successfully ? 1 : 0);
1693 mCaller.sendMessage(message);
1694 }
1695
Phil Weaver27fcd9c2017-01-20 15:57:24 -08001696 public void onFingerprintCapturingGesturesChanged(boolean active) {
1697 mCaller.sendMessage(mCaller.obtainMessageI(
1698 DO_ON_FINGERPRINT_ACTIVE_CHANGED, active ? 1 : 0));
1699 }
1700
1701 public void onFingerprintGesture(int gesture) {
1702 mCaller.sendMessage(mCaller.obtainMessageI(DO_ON_FINGERPRINT_GESTURE, gesture));
1703 }
1704
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001705 public void onAccessibilityButtonClicked() {
1706 final Message message = mCaller.obtainMessage(DO_ACCESSIBILITY_BUTTON_CLICKED);
1707 mCaller.sendMessage(message);
1708 }
1709
1710 public void onAccessibilityButtonAvailabilityChanged(boolean available) {
1711 final Message message = mCaller.obtainMessageI(
1712 DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED, (available ? 1 : 0));
1713 mCaller.sendMessage(message);
1714 }
1715
Svetoslav8e3feb12014-02-24 13:46:47 -08001716 @Override
svetoslavganov75986cf2009-05-14 22:28:01 -07001717 public void executeMessage(Message message) {
1718 switch (message.what) {
Svetoslavc4fccd12013-04-09 12:58:41 -07001719 case DO_ON_ACCESSIBILITY_EVENT: {
svetoslavganov75986cf2009-05-14 22:28:01 -07001720 AccessibilityEvent event = (AccessibilityEvent) message.obj;
Eugene Suslaeb1375c2016-12-20 16:32:59 -08001721 boolean serviceWantsEvent = message.arg1 != 0;
Dianne Hackborn7ed6ee52009-09-10 18:41:28 -07001722 if (event != null) {
Eugene Suslaeb1375c2016-12-20 16:32:59 -08001723 // Send the event to AccessibilityCache via AccessibilityInteractionClient
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001724 AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event);
Phil Weaver6f2da202017-09-05 16:00:38 -07001725 if (serviceWantsEvent
1726 && (mConnectionId != AccessibilityInteractionClient.NO_ID)) {
Eugene Suslaeb1375c2016-12-20 16:32:59 -08001727 // Send the event to AccessibilityService
1728 mCallback.onAccessibilityEvent(event);
1729 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001730 // Make sure the event is recycled.
1731 try {
1732 event.recycle();
1733 } catch (IllegalStateException ise) {
1734 /* ignore - best effort */
1735 }
Charles Chen85f6fb72009-08-28 11:32:23 -07001736 }
Svetoslavc4fccd12013-04-09 12:58:41 -07001737 } return;
Svetoslav8e3feb12014-02-24 13:46:47 -08001738
Svetoslavc4fccd12013-04-09 12:58:41 -07001739 case DO_ON_INTERRUPT: {
Phil Weaver6f2da202017-09-05 16:00:38 -07001740 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1741 mCallback.onInterrupt();
1742 }
Svetoslavc4fccd12013-04-09 12:58:41 -07001743 } return;
Svetoslav8e3feb12014-02-24 13:46:47 -08001744
Svetoslav3a5c7212014-10-14 09:54:26 -07001745 case DO_INIT: {
Svetoslavc4fccd12013-04-09 12:58:41 -07001746 mConnectionId = message.arg1;
Svetoslav3a5c7212014-10-14 09:54:26 -07001747 SomeArgs args = (SomeArgs) message.obj;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001748 IAccessibilityServiceConnection connection =
Svetoslav3a5c7212014-10-14 09:54:26 -07001749 (IAccessibilityServiceConnection) args.arg1;
1750 IBinder windowToken = (IBinder) args.arg2;
1751 args.recycle();
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001752 if (connection != null) {
Svetoslavc4fccd12013-04-09 12:58:41 -07001753 AccessibilityInteractionClient.getInstance().addConnection(mConnectionId,
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001754 connection);
Svetoslav3a5c7212014-10-14 09:54:26 -07001755 mCallback.init(mConnectionId, windowToken);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001756 mCallback.onServiceConnected();
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001757 } else {
Svetoslav8e3feb12014-02-24 13:46:47 -08001758 AccessibilityInteractionClient.getInstance().removeConnection(
1759 mConnectionId);
Svetoslav3a5c7212014-10-14 09:54:26 -07001760 mConnectionId = AccessibilityInteractionClient.NO_ID;
Svetoslavf7e50992013-01-22 18:15:40 -08001761 AccessibilityInteractionClient.getInstance().clearCache();
Svetoslav3a5c7212014-10-14 09:54:26 -07001762 mCallback.init(AccessibilityInteractionClient.NO_ID, null);
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001763 }
Svetoslavc4fccd12013-04-09 12:58:41 -07001764 } return;
Svetoslav8e3feb12014-02-24 13:46:47 -08001765
Svetoslavc4fccd12013-04-09 12:58:41 -07001766 case DO_ON_GESTURE: {
Phil Weaver6f2da202017-09-05 16:00:38 -07001767 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1768 final int gestureId = message.arg1;
1769 mCallback.onGesture(gestureId);
1770 }
Svetoslavc4fccd12013-04-09 12:58:41 -07001771 } return;
Svetoslav8e3feb12014-02-24 13:46:47 -08001772
1773 case DO_CLEAR_ACCESSIBILITY_CACHE: {
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07001774 AccessibilityInteractionClient.getInstance().clearCache();
Svetoslavc4fccd12013-04-09 12:58:41 -07001775 } return;
Svetoslav8e3feb12014-02-24 13:46:47 -08001776
Svetoslavc4fccd12013-04-09 12:58:41 -07001777 case DO_ON_KEY_EVENT: {
1778 KeyEvent event = (KeyEvent) message.obj;
1779 try {
1780 IAccessibilityServiceConnection connection = AccessibilityInteractionClient
1781 .getInstance().getConnection(mConnectionId);
1782 if (connection != null) {
1783 final boolean result = mCallback.onKeyEvent(event);
1784 final int sequence = message.arg1;
1785 try {
1786 connection.setOnKeyEventResult(result, sequence);
1787 } catch (RemoteException re) {
1788 /* ignore */
1789 }
1790 }
1791 } finally {
Svetoslav8e3feb12014-02-24 13:46:47 -08001792 // Make sure the event is recycled.
1793 try {
1794 event.recycle();
1795 } catch (IllegalStateException ise) {
1796 /* ignore - best effort */
1797 }
Svetoslavc4fccd12013-04-09 12:58:41 -07001798 }
1799 } return;
Svetoslav8e3feb12014-02-24 13:46:47 -08001800
Alan Viverette214fb682015-11-17 09:47:11 -05001801 case DO_ON_MAGNIFICATION_CHANGED: {
Phil Weaver6f2da202017-09-05 16:00:38 -07001802 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1803 final SomeArgs args = (SomeArgs) message.obj;
1804 final Region region = (Region) args.arg1;
1805 final float scale = (float) args.arg2;
1806 final float centerX = (float) args.arg3;
1807 final float centerY = (float) args.arg4;
1808 mCallback.onMagnificationChanged(region, scale, centerX, centerY);
1809 }
Alan Viverette214fb682015-11-17 09:47:11 -05001810 } return;
1811
Anna Galusza9b278112016-01-04 11:37:37 -08001812 case DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED: {
Phil Weaver6f2da202017-09-05 16:00:38 -07001813 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1814 final int showMode = (int) message.arg1;
1815 mCallback.onSoftKeyboardShowModeChanged(showMode);
1816 }
Anna Galusza9b278112016-01-04 11:37:37 -08001817 } return;
1818
Phil Weavera6b64f52015-12-04 15:21:35 -08001819 case DO_GESTURE_COMPLETE: {
Phil Weaver6f2da202017-09-05 16:00:38 -07001820 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1821 final boolean successfully = message.arg2 == 1;
1822 mCallback.onPerformGestureResult(message.arg1, successfully);
1823 }
Phil Weavera6b64f52015-12-04 15:21:35 -08001824 } return;
Phil Weaver27fcd9c2017-01-20 15:57:24 -08001825 case DO_ON_FINGERPRINT_ACTIVE_CHANGED: {
Phil Weaver6f2da202017-09-05 16:00:38 -07001826 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1827 mCallback.onFingerprintCapturingGesturesChanged(message.arg1 == 1);
1828 }
Phil Weaver27fcd9c2017-01-20 15:57:24 -08001829 } return;
1830 case DO_ON_FINGERPRINT_GESTURE: {
Phil Weaver6f2da202017-09-05 16:00:38 -07001831 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1832 mCallback.onFingerprintGesture(message.arg1);
1833 }
Phil Weaver27fcd9c2017-01-20 15:57:24 -08001834 } return;
Phil Weavera6b64f52015-12-04 15:21:35 -08001835
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001836 case (DO_ACCESSIBILITY_BUTTON_CLICKED): {
Phil Weaver6f2da202017-09-05 16:00:38 -07001837 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1838 mCallback.onAccessibilityButtonClicked();
1839 }
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001840 } return;
1841
1842 case (DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED): {
Phil Weaver6f2da202017-09-05 16:00:38 -07001843 if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1844 final boolean available = (message.arg1 != 0);
1845 mCallback.onAccessibilityButtonAvailabilityChanged(available);
1846 }
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001847 } return;
1848
svetoslavganov75986cf2009-05-14 22:28:01 -07001849 default :
1850 Log.w(LOG_TAG, "Unknown message type " + message.what);
1851 }
1852 }
1853 }
Phil Weavera6b64f52015-12-04 15:21:35 -08001854
1855 /**
1856 * Class used to report status of dispatched gestures
1857 */
1858 public static abstract class GestureResultCallback {
1859 /** Called when the gesture has completed successfully
1860 *
1861 * @param gestureDescription The description of the gesture that completed.
1862 */
1863 public void onCompleted(GestureDescription gestureDescription) {
1864 }
1865
1866 /** Called when the gesture was cancelled
1867 *
1868 * @param gestureDescription The description of the gesture that was cancelled.
1869 */
1870 public void onCancelled(GestureDescription gestureDescription) {
1871 }
1872 }
1873
1874 /* Object to keep track of gesture result callbacks */
1875 private static class GestureResultCallbackInfo {
1876 GestureDescription gestureDescription;
1877 GestureResultCallback callback;
1878 Handler handler;
1879
1880 GestureResultCallbackInfo(GestureDescription gestureDescription,
1881 GestureResultCallback callback, Handler handler) {
1882 this.gestureDescription = gestureDescription;
1883 this.callback = callback;
1884 this.handler = handler;
1885 }
1886 }
svetoslavganov75986cf2009-05-14 22:28:01 -07001887}