blob: 2620c4472ede76ea6fbddd525004314b8399e8dc [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
svetoslavganov75986cf2009-05-14 22:28:01 -070019import android.app.Service;
Svetoslav Ganov79311c42012-01-17 20:24:26 -080020import android.content.Context;
svetoslavganov75986cf2009-05-14 22:28:01 -070021import android.content.Intent;
22import android.os.IBinder;
Svetoslav Ganov79311c42012-01-17 20:24:26 -080023import android.os.Looper;
svetoslavganov75986cf2009-05-14 22:28:01 -070024import android.os.Message;
25import android.os.RemoteException;
Svetoslav8e3feb12014-02-24 13:46:47 -080026import android.os.SystemClock;
svetoslavganov75986cf2009-05-14 22:28:01 -070027import android.util.Log;
Svetoslavc4fccd12013-04-09 12:58:41 -070028import android.view.KeyEvent;
svetoslavganov75986cf2009-05-14 22:28:01 -070029import android.view.accessibility.AccessibilityEvent;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -080030import android.view.accessibility.AccessibilityInteractionClient;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070031import android.view.accessibility.AccessibilityNodeInfo;
Svetoslav8e3feb12014-02-24 13:46:47 -080032import android.view.accessibility.AccessibilityWindowInfo;
svetoslavganov75986cf2009-05-14 22:28:01 -070033
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -080034import com.android.internal.os.HandlerCaller;
35
Svetoslav8e3feb12014-02-24 13:46:47 -080036import java.util.List;
37
svetoslavganov75986cf2009-05-14 22:28:01 -070038/**
39 * An accessibility service runs in the background and receives callbacks by the system
40 * when {@link AccessibilityEvent}s are fired. Such events denote some state transition
41 * in the user interface, for example, the focus has changed, a button has been clicked,
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070042 * etc. Such a service can optionally request the capability for querying the content
Scott Mainb303d832011-10-12 16:45:18 -070043 * of the active window. Development of an accessibility service requires extending this
44 * class and implementing its abstract methods.
Joe Fernandeze1302ed2012-02-06 14:30:15 -080045 *
46 * <div class="special reference">
47 * <h3>Developer Guides</h3>
48 * <p>For more information about creating AccessibilityServices, read the
49 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
50 * developer guide.</p>
51 * </div>
52 *
Scott Mainb303d832011-10-12 16:45:18 -070053 * <h3>Lifecycle</h3>
svetoslavganov75986cf2009-05-14 22:28:01 -070054 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070055 * The lifecycle of an accessibility service is managed exclusively by the system and
56 * follows the established service life cycle. Additionally, starting or stopping an
57 * accessibility service is triggered exclusively by an explicit user action through
svetoslavganov75986cf2009-05-14 22:28:01 -070058 * enabling or disabling it in the device settings. After the system binds to a service it
59 * calls {@link AccessibilityService#onServiceConnected()}. This method can be
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -070060 * overriden by clients that want to perform post binding setup.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070061 * </p>
Scott Mainb303d832011-10-12 16:45:18 -070062 * <h3>Declaration</h3>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070063 * <p>
64 * An accessibility is declared as any other service in an AndroidManifest.xml but it
65 * must also specify that it handles the "android.accessibilityservice.AccessibilityService"
66 * {@link android.content.Intent}. Failure to declare this intent will cause the system to
Dianne Hackborn636fd522012-06-05 17:38:50 -070067 * ignore the accessibility service. Additionally an accessibility service must request the
68 * {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to ensure
69 * that only the system
Svetoslav Ganov53e184d2012-05-16 15:57:10 -070070 * can bind to it. Failure to declare this intent will cause the system to ignore the
71 * accessibility service. Following is an example declaration:
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070072 * </p>
Svetoslav Ganov53e184d2012-05-16 15:57:10 -070073 * <pre> &lt;service android:name=".MyAccessibilityService"
Scott Main53b0fda2012-08-06 12:50:48 -070074 * android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"&gt;
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070075 * &lt;intent-filter&gt;
Scott Mainb303d832011-10-12 16:45:18 -070076 * &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070077 * &lt;/intent-filter&gt;
78 * . . .
Scott Mainb303d832011-10-12 16:45:18 -070079 * &lt;/service&gt;</pre>
80 * <h3>Configuration</h3>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070081 * <p>
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070082 * An accessibility service can be configured to receive specific types of accessibility events,
83 * listen only to specific packages, get events from each type only once in a given time frame,
84 * retrieve window content, specify a settings activity, etc.
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -070085 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070086 * <p>
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -070087 * There are two approaches for configuring an accessibility service:
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070088 * </p>
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -070089 * <ul>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070090 * <li>
91 * Providing a {@link #SERVICE_META_DATA meta-data} entry in the manifest when declaring
92 * the service. A service declaration with a meta-data tag is presented below:
Scott Mainb303d832011-10-12 16:45:18 -070093 * <pre> &lt;service android:name=".MyAccessibilityService"&gt;
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070094 * &lt;intent-filter&gt;
Scott Mainb303d832011-10-12 16:45:18 -070095 * &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070096 * &lt;/intent-filter&gt;
97 * &lt;meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice" /&gt;
Scott Mainb303d832011-10-12 16:45:18 -070098 * &lt;/service&gt;</pre>
99 * <p class="note">
100 * <strong>Note:</strong> This approach enables setting all properties.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700101 * </p>
102 * <p>
103 * For more details refer to {@link #SERVICE_META_DATA} and
Scott Mainb303d832011-10-12 16:45:18 -0700104 * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700105 * </p>
106 * </li>
107 * <li>
108 * Calling {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}. Note
109 * that this method can be called any time to dynamically change the service configuration.
Scott Mainb303d832011-10-12 16:45:18 -0700110 * <p class="note">
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700111 * <strong>Note:</strong> This approach enables setting only dynamically configurable properties:
112 * {@link AccessibilityServiceInfo#eventTypes},
113 * {@link AccessibilityServiceInfo#feedbackType},
114 * {@link AccessibilityServiceInfo#flags},
115 * {@link AccessibilityServiceInfo#notificationTimeout},
116 * {@link AccessibilityServiceInfo#packageNames}
117 * </p>
118 * <p>
119 * For more details refer to {@link AccessibilityServiceInfo}.
120 * </p>
121 * </li>
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700122 * </ul>
Scott Mainb303d832011-10-12 16:45:18 -0700123 * <h3>Retrieving window content</h3>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700124 * <p>
Ken Wakasaf76a50c2012-03-09 19:56:35 +0900125 * A service can specify in its declaration that it can retrieve the active window
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700126 * content which is represented as a tree of {@link AccessibilityNodeInfo}. Note that
127 * declaring this capability requires that the service declares its configuration via
128 * an XML resource referenced by {@link #SERVICE_META_DATA}.
129 * </p>
130 * <p>
131 * For security purposes an accessibility service can retrieve only the content of the
132 * currently active window. The currently active window is defined as the window from
133 * which was fired the last event of the following types:
Svetoslav Ganov4e2a7622011-07-26 20:08:46 -0700134 * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700135 * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
136 * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT},
Svetoslav Ganov4e2a7622011-07-26 20:08:46 -0700137 * In other words, the last window that was shown or the last window that the user has touched
138 * during touch exploration.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700139 * </p>
140 * <p>
141 * The entry point for retrieving window content is through calling
142 * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()} of the last received
143 * event of the above types or a previous event from the same window
144 * (see {@link AccessibilityEvent#getWindowId() AccessibilityEvent.getWindowId()}). Invoking
145 * this method will return an {@link AccessibilityNodeInfo} that can be used to traverse the
146 * window content which represented as a tree of such objects.
147 * </p>
Scott Mainb303d832011-10-12 16:45:18 -0700148 * <p class="note">
149 * <strong>Note</strong> An accessibility service may have requested to be notified for
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700150 * a subset of the event types, thus be unaware that the active window has changed. Therefore
151 * accessibility service that would like to retrieve window content should:
152 * <ul>
153 * <li>
154 * Register for all event types with no notification timeout and keep track for the active
155 * window by calling {@link AccessibilityEvent#getWindowId()} of the last received event and
156 * compare this with the {@link AccessibilityNodeInfo#getWindowId()} before calling retrieval
157 * methods on the latter.
158 * </li>
159 * <li>
160 * Prepare that a retrieval method on {@link AccessibilityNodeInfo} may fail since the
161 * active window has changed and the service did not get the accessibility event yet. Note
Scott Mainb303d832011-10-12 16:45:18 -0700162 * that it is possible to have a retrieval method failing even adopting the strategy
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700163 * specified in the previous bullet because the accessibility event dispatch is asynchronous
164 * and crosses process boundaries.
165 * </li>
166 * </ul>
167 * </p>
Scott Mainb303d832011-10-12 16:45:18 -0700168 * <h3>Notification strategy</h3>
svetoslavganov75986cf2009-05-14 22:28:01 -0700169 * <p>
170 * For each feedback type only one accessibility service is notified. Services are notified
171 * in the order of registration. Hence, if two services are registered for the same
172 * feedback type in the same package the first one wins. It is possible however, to
173 * register a service as the default one for a given feedback type. In such a case this
174 * service is invoked if no other service was interested in the event. In other words, default
175 * services do not compete with other services and are notified last regardless of the
176 * registration order. This enables "generic" accessibility services that work reasonably
177 * well with most applications to coexist with "polished" ones that are targeted for
178 * specific applications.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700179 * </p>
Scott Mainb303d832011-10-12 16:45:18 -0700180 * <p class="note">
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700181 * <strong>Note:</strong> The event notification timeout is useful to avoid propagating
182 * events to the client too frequently since this is accomplished via an expensive
183 * interprocess call. One can think of the timeout as a criteria to determine when
Scott Mainb303d832011-10-12 16:45:18 -0700184 * event generation has settled down.</p>
185 * <h3>Event types</h3>
186 * <ul>
Svetoslav8e3feb12014-02-24 13:46:47 -0800187 * <li>{@link AccessibilityEvent#TYPE_VIEW_CLICKED}</li>
188 * <li>{@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}</li>
189 * <li>{@link AccessibilityEvent#TYPE_VIEW_FOCUSED}</li>
190 * <li>{@link AccessibilityEvent#TYPE_VIEW_SELECTED}</li>
191 * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}</li>
192 * <li>{@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}</li>
193 * <li>{@link AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED}</li>
194 * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START}</li>
195 * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END}</li>
196 * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}</li>
197 * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}</li>
198 * <li>{@link AccessibilityEvent#TYPE_VIEW_SCROLLED}</li>
199 * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED}</li>
200 * <li>{@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}</li>
201 * <li>{@link AccessibilityEvent#TYPE_ANNOUNCEMENT}</li>
202 * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_START}</li>
203 * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_END}</li>
204 * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_START}</li>
205 * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_END}</li>
206 * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED}</li>
207 * <li>{@link AccessibilityEvent#TYPE_WINDOWS_CHANGED}</li>
208 * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED}</li>
Scott Mainb303d832011-10-12 16:45:18 -0700209 * </ul>
210 * <h3>Feedback types</h3>
211 * <ul>
Svetoslav8e3feb12014-02-24 13:46:47 -0800212 * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li>
213 * <li>{@link AccessibilityServiceInfo#FEEDBACK_HAPTIC}</li>
214 * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li>
215 * <li>{@link AccessibilityServiceInfo#FEEDBACK_VISUAL}</li>
216 * <li>{@link AccessibilityServiceInfo#FEEDBACK_GENERIC}</li>
217 * <li>{@link AccessibilityServiceInfo#FEEDBACK_BRAILLE}</li>
Scott Mainb303d832011-10-12 16:45:18 -0700218 * </ul>
219 * @see AccessibilityEvent
220 * @see AccessibilityServiceInfo
221 * @see android.view.accessibility.AccessibilityManager
svetoslavganov75986cf2009-05-14 22:28:01 -0700222 */
223public abstract class AccessibilityService extends Service {
Svetoslav Ganov42138042012-03-20 11:51:39 -0700224
225 /**
226 * The user has performed a swipe up gesture on the touch screen.
227 */
228 public static final int GESTURE_SWIPE_UP = 1;
229
230 /**
231 * The user has performed a swipe down gesture on the touch screen.
232 */
233 public static final int GESTURE_SWIPE_DOWN = 2;
234
235 /**
236 * The user has performed a swipe left gesture on the touch screen.
237 */
238 public static final int GESTURE_SWIPE_LEFT = 3;
239
240 /**
241 * The user has performed a swipe right gesture on the touch screen.
242 */
243 public static final int GESTURE_SWIPE_RIGHT = 4;
244
245 /**
246 * The user has performed a swipe left and right gesture on the touch screen.
247 */
248 public static final int GESTURE_SWIPE_LEFT_AND_RIGHT = 5;
249
250 /**
251 * The user has performed a swipe right and left gesture on the touch screen.
252 */
253 public static final int GESTURE_SWIPE_RIGHT_AND_LEFT = 6;
254
255 /**
256 * The user has performed a swipe up and down gesture on the touch screen.
257 */
258 public static final int GESTURE_SWIPE_UP_AND_DOWN = 7;
259
260 /**
261 * The user has performed a swipe down and up gesture on the touch screen.
262 */
263 public static final int GESTURE_SWIPE_DOWN_AND_UP = 8;
264
265 /**
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700266 * The user has performed a left and up gesture on the touch screen.
267 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700268 public static final int GESTURE_SWIPE_LEFT_AND_UP = 9;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700269
270 /**
271 * The user has performed a left and down gesture on the touch screen.
272 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700273 public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 10;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700274
275 /**
276 * The user has performed a right and up gesture on the touch screen.
277 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700278 public static final int GESTURE_SWIPE_RIGHT_AND_UP = 11;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700279
280 /**
281 * The user has performed a right and down gesture on the touch screen.
282 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700283 public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 12;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700284
285 /**
286 * The user has performed an up and left gesture on the touch screen.
287 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700288 public static final int GESTURE_SWIPE_UP_AND_LEFT = 13;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700289
290 /**
291 * The user has performed an up and right gesture on the touch screen.
292 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700293 public static final int GESTURE_SWIPE_UP_AND_RIGHT = 14;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700294
295 /**
296 * The user has performed an down and left gesture on the touch screen.
297 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700298 public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 15;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700299
300 /**
301 * The user has performed an down and right gesture on the touch screen.
302 */
Svetoslav Ganov65d98ad2012-05-02 17:57:06 -0700303 public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 16;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700304
305 /**
svetoslavganov75986cf2009-05-14 22:28:01 -0700306 * The {@link Intent} that must be declared as handled by the service.
307 */
308 public static final String SERVICE_INTERFACE =
309 "android.accessibilityservice.AccessibilityService";
310
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700311 /**
312 * Name under which an AccessibilityService component publishes information
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700313 * about itself. This meta-data must reference an XML resource containing an
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700314 * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>
315 * tag. This is a a sample XML file configuring an accessibility service:
Scott Mainb303d832011-10-12 16:45:18 -0700316 * <pre> &lt;accessibility-service
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700317 * android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
318 * android:packageNames="foo.bar, foo.baz"
319 * android:accessibilityFeedbackType="feedbackSpoken"
320 * android:notificationTimeout="100"
321 * android:accessibilityFlags="flagDefault"
322 * android:settingsActivity="foo.bar.TestBackActivity"
323 * android:canRetrieveWindowContent="true"
Svetoslav688a6972013-04-16 18:55:38 -0700324 * android:canRequestTouchExplorationMode="true"
325 * android:canRequestEnhancedWebAccessibility="true"
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700326 * . . .
Scott Mainb303d832011-10-12 16:45:18 -0700327 * /&gt;</pre>
Svetoslav Ganovcc4053e2011-05-23 13:37:44 -0700328 */
329 public static final String SERVICE_META_DATA = "android.accessibilityservice";
330
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700331 /**
332 * Action to go back.
333 */
334 public static final int GLOBAL_ACTION_BACK = 1;
335
336 /**
337 * Action to go home.
338 */
339 public static final int GLOBAL_ACTION_HOME = 2;
340
341 /**
Svetoslav Ganove20a1772012-09-25 16:07:46 -0700342 * Action to open the recent apps.
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700343 */
344 public static final int GLOBAL_ACTION_RECENTS = 3;
345
346 /**
347 * Action to open the notifications.
348 */
349 public static final int GLOBAL_ACTION_NOTIFICATIONS = 4;
350
Svetoslav Ganove20a1772012-09-25 16:07:46 -0700351 /**
352 * Action to open the quick settings.
353 */
354 public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5;
355
svetoslavganov75986cf2009-05-14 22:28:01 -0700356 private static final String LOG_TAG = "AccessibilityService";
357
Svetoslav Ganov80943d82013-01-02 10:25:37 -0800358 /**
359 * @hide
360 */
361 public interface Callbacks {
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800362 public void onAccessibilityEvent(AccessibilityEvent event);
363 public void onInterrupt();
364 public void onServiceConnected();
365 public void onSetConnectionId(int connectionId);
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700366 public boolean onGesture(int gestureId);
Svetoslavc4fccd12013-04-09 12:58:41 -0700367 public boolean onKeyEvent(KeyEvent event);
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800368 }
svetoslavganov75986cf2009-05-14 22:28:01 -0700369
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800370 private int mConnectionId;
svetoslavganov75986cf2009-05-14 22:28:01 -0700371
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800372 private AccessibilityServiceInfo mInfo;
373
svetoslavganov75986cf2009-05-14 22:28:01 -0700374 /**
375 * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
376 *
377 * @param event An event.
378 */
379 public abstract void onAccessibilityEvent(AccessibilityEvent event);
380
381 /**
382 * Callback for interrupting the accessibility feedback.
383 */
384 public abstract void onInterrupt();
385
386 /**
387 * This method is a part of the {@link AccessibilityService} lifecycle and is
388 * called after the system has successfully bound to the service. If is
389 * convenient to use this method for setting the {@link AccessibilityServiceInfo}.
390 *
391 * @see AccessibilityServiceInfo
392 * @see #setServiceInfo(AccessibilityServiceInfo)
393 */
394 protected void onServiceConnected() {
395
396 }
397
398 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700399 * Called by the system when the user performs a specific gesture on the
Svetoslav Ganove4abc512012-05-09 11:02:38 -0700400 * touch screen.
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700401 *
Svetoslav Ganove4abc512012-05-09 11:02:38 -0700402 * <strong>Note:</strong> To receive gestures an accessibility service must
403 * request that the device is in touch exploration mode by setting the
Svetoslav Ganov7b1e0c72012-05-13 11:57:29 -0700404 * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}
Svetoslav Ganove4abc512012-05-09 11:02:38 -0700405 * flag.
Svetoslav Ganov42138042012-03-20 11:51:39 -0700406 *
407 * @param gestureId The unique id of the performed gesture.
408 *
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700409 * @return Whether the gesture was handled.
410 *
Svetoslav Ganov42138042012-03-20 11:51:39 -0700411 * @see #GESTURE_SWIPE_UP
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700412 * @see #GESTURE_SWIPE_UP_AND_LEFT
Svetoslav Ganov42138042012-03-20 11:51:39 -0700413 * @see #GESTURE_SWIPE_UP_AND_DOWN
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700414 * @see #GESTURE_SWIPE_UP_AND_RIGHT
415 * @see #GESTURE_SWIPE_DOWN
416 * @see #GESTURE_SWIPE_DOWN_AND_LEFT
Svetoslav Ganov42138042012-03-20 11:51:39 -0700417 * @see #GESTURE_SWIPE_DOWN_AND_UP
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700418 * @see #GESTURE_SWIPE_DOWN_AND_RIGHT
419 * @see #GESTURE_SWIPE_LEFT
420 * @see #GESTURE_SWIPE_LEFT_AND_UP
Svetoslav Ganov42138042012-03-20 11:51:39 -0700421 * @see #GESTURE_SWIPE_LEFT_AND_RIGHT
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700422 * @see #GESTURE_SWIPE_LEFT_AND_DOWN
423 * @see #GESTURE_SWIPE_RIGHT
424 * @see #GESTURE_SWIPE_RIGHT_AND_UP
Svetoslav Ganov42138042012-03-20 11:51:39 -0700425 * @see #GESTURE_SWIPE_RIGHT_AND_LEFT
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700426 * @see #GESTURE_SWIPE_RIGHT_AND_DOWN
Svetoslav Ganov42138042012-03-20 11:51:39 -0700427 */
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700428 protected boolean onGesture(int gestureId) {
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700429 return false;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700430 }
431
432 /**
Svetoslavc4fccd12013-04-09 12:58:41 -0700433 * Callback that allows an accessibility service to observe the key events
434 * before they are passed to the rest of the system. This means that the events
435 * are first delivered here before they are passed to the device policy, the
436 * input method, or applications.
437 * <p>
438 * <strong>Note:</strong> It is important that key events are handled in such
439 * a way that the event stream that would be passed to the rest of the system
440 * is well-formed. For example, handling the down event but not the up event
441 * and vice versa would generate an inconsistent event stream.
442 * </p>
443 * <p>
444 * <strong>Note:</strong> The key events delivered in this method are copies
445 * and modifying them will have no effect on the events that will be passed
446 * to the system. This method is intended to perform purely filtering
447 * functionality.
448 * <p>
449 *
450 * @param event The event to be processed.
451 * @return If true then the event will be consumed and not delivered to
452 * applications, otherwise it will be delivered as usual.
453 */
454 protected boolean onKeyEvent(KeyEvent event) {
455 return false;
456 }
457
458 /**
Svetoslav8e3feb12014-02-24 13:46:47 -0800459 * Gets the windows on the screen. This method returns only the windows
460 * that a sighted user can interact with, as opposed to all windows.
461 * For example, if there is a modal dialog shown and the user cannot touch
462 * anything behind it, then only the modal window will be reported
463 * (assuming it is the top one). For convenience the returned windows
464 * are ordered in a descending layer order, which is the windows that
465 * are higher in the Z-order are reported first.
466 * <p>
467 * <strong>Note:</strong> In order to access the windows your service has
468 * to declare the capability to retrieve window content by setting the
469 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
470 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
471 * Also the service has to opt-in to retrieve the interactive windows by
472 * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
473 * flag.
474 * </p>
475 *
476 * @return The windows if there are windows and the service is can retrieve
477 * them, otherwise an empty list.
478 */
479 public List<AccessibilityWindowInfo> getWindows() {
480 return AccessibilityInteractionClient.getInstance().getWindows(mConnectionId);
481 }
482
483 /**
Svetoslav Ganov0846e292012-04-18 18:47:13 -0700484 * Gets the root node in the currently active window if this service
Svetoslav8e3feb12014-02-24 13:46:47 -0800485 * can retrieve window content. The active window is the one that the user
486 * is currently touching or the window with input focus, if the user is not
487 * touching any window.
488 * <p>
489 * <strong>Note:</strong> In order to access the root node your service has
490 * to declare the capability to retrieve window content by setting the
491 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
492 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
493 * </p>
Svetoslav Ganov0846e292012-04-18 18:47:13 -0700494 *
495 * @return The root node if this service can retrieve window content.
496 */
497 public AccessibilityNodeInfo getRootInActiveWindow() {
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700498 return AccessibilityInteractionClient.getInstance().getRootInActiveWindow(mConnectionId);
Svetoslav Ganov0846e292012-04-18 18:47:13 -0700499 }
500
501 /**
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700502 * Performs a global action. Such an action can be performed
503 * at any moment regardless of the current application or user
504 * location in that application. For example going back, going
505 * home, opening recents, etc.
506 *
507 * @param action The action to perform.
508 * @return Whether the action was successfully performed.
509 *
510 * @see #GLOBAL_ACTION_BACK
511 * @see #GLOBAL_ACTION_HOME
512 * @see #GLOBAL_ACTION_NOTIFICATIONS
513 * @see #GLOBAL_ACTION_RECENTS
514 */
515 public final boolean performGlobalAction(int action) {
516 IAccessibilityServiceConnection connection =
517 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
518 if (connection != null) {
519 try {
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700520 return connection.performGlobalAction(action);
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700521 } catch (RemoteException re) {
522 Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
523 }
524 }
525 return false;
526 }
527
528 /**
Svetoslav1e0d4af2014-04-10 17:41:29 -0700529 * Find the view that has the specified focus type. The search is performed
530 * across all windows.
531 * <p>
532 * <strong>Note:</strong> In order to access the windows your service has
533 * to declare the capability to retrieve window content by setting the
534 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
535 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
536 * Also the service has to opt-in to retrieve the interactive windows by
537 * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
538 * flag.Otherwise, the search will be performed only in the active window.
539 * </p>
540 *
541 * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
542 * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
543 * @return The node info of the focused view or null.
544 *
545 * @see AccessibilityNodeInfo#FOCUS_INPUT
546 * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
547 */
548 public AccessibilityNodeInfo findFocus(int focus) {
549 return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
550 AccessibilityNodeInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
551 }
552
553 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700554 * Gets the an {@link AccessibilityServiceInfo} describing this
555 * {@link AccessibilityService}. This method is useful if one wants
556 * to change some of the dynamically configurable properties at
557 * runtime.
558 *
559 * @return The accessibility service info.
560 *
Svetoslavbbfa5852013-02-11 19:38:12 -0800561 * @see AccessibilityServiceInfo
Svetoslav Ganov42138042012-03-20 11:51:39 -0700562 */
563 public final AccessibilityServiceInfo getServiceInfo() {
564 IAccessibilityServiceConnection connection =
565 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
566 if (connection != null) {
567 try {
568 return connection.getServiceInfo();
569 } catch (RemoteException re) {
570 Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
571 }
572 }
573 return null;
574 }
575
576 /**
svetoslavganov75986cf2009-05-14 22:28:01 -0700577 * Sets the {@link AccessibilityServiceInfo} that describes this service.
578 * <p>
579 * Note: You can call this method any time but the info will be picked up after
580 * the system has bound to this service and when this method is called thereafter.
581 *
582 * @param info The info.
583 */
584 public final void setServiceInfo(AccessibilityServiceInfo info) {
585 mInfo = info;
586 sendServiceInfo();
587 }
588
589 /**
590 * Sets the {@link AccessibilityServiceInfo} for this service if the latter is
591 * properly set and there is an {@link IAccessibilityServiceConnection} to the
592 * AccessibilityManagerService.
593 */
594 private void sendServiceInfo() {
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800595 IAccessibilityServiceConnection connection =
596 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
597 if (mInfo != null && connection != null) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700598 try {
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800599 connection.setServiceInfo(mInfo);
Svetoslav Ganov42138042012-03-20 11:51:39 -0700600 mInfo = null;
601 AccessibilityInteractionClient.getInstance().clearCache();
svetoslavganov75986cf2009-05-14 22:28:01 -0700602 } catch (RemoteException re) {
603 Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
604 }
605 }
606 }
607
Dianne Hackborn7f205432009-07-28 00:13:47 -0700608 /**
609 * Implement to return the implementation of the internal accessibility
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700610 * service interface.
Dianne Hackborn7f205432009-07-28 00:13:47 -0700611 */
svetoslavganov75986cf2009-05-14 22:28:01 -0700612 @Override
613 public final IBinder onBind(Intent intent) {
Svetoslav Ganov42138042012-03-20 11:51:39 -0700614 return new IAccessibilityServiceClientWrapper(this, getMainLooper(), new Callbacks() {
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800615 @Override
616 public void onServiceConnected() {
617 AccessibilityService.this.onServiceConnected();
618 }
619
620 @Override
621 public void onInterrupt() {
622 AccessibilityService.this.onInterrupt();
623 }
624
625 @Override
626 public void onAccessibilityEvent(AccessibilityEvent event) {
627 AccessibilityService.this.onAccessibilityEvent(event);
628 }
629
630 @Override
631 public void onSetConnectionId( int connectionId) {
632 mConnectionId = connectionId;
633 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700634
635 @Override
Svetoslav Ganovfefd20e2012-04-19 21:44:35 -0700636 public boolean onGesture(int gestureId) {
637 return AccessibilityService.this.onGesture(gestureId);
Svetoslav Ganov42138042012-03-20 11:51:39 -0700638 }
Svetoslavc4fccd12013-04-09 12:58:41 -0700639
640 @Override
641 public boolean onKeyEvent(KeyEvent event) {
642 return AccessibilityService.this.onKeyEvent(event);
643 }
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800644 });
svetoslavganov75986cf2009-05-14 22:28:01 -0700645 }
646
647 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700648 * Implements the internal {@link IAccessibilityServiceClient} interface to convert
svetoslavganov75986cf2009-05-14 22:28:01 -0700649 * incoming calls to it back to calls on an {@link AccessibilityService}.
Svetoslav Ganov80943d82013-01-02 10:25:37 -0800650 *
651 * @hide
svetoslavganov75986cf2009-05-14 22:28:01 -0700652 */
Svetoslav Ganov80943d82013-01-02 10:25:37 -0800653 public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
svetoslavganov75986cf2009-05-14 22:28:01 -0700654 implements HandlerCaller.Callback {
655
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800656 static final int NO_ID = -1;
657
Svetoslav8e3feb12014-02-24 13:46:47 -0800658 private static final int DO_SET_SET_CONNECTION = 1;
659 private static final int DO_ON_INTERRUPT = 2;
660 private static final int DO_ON_ACCESSIBILITY_EVENT = 3;
661 private static final int DO_ON_GESTURE = 4;
662 private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5;
663 private static final int DO_ON_KEY_EVENT = 6;
664 private static final int DO_ON_WINDOWS_CHANGED = 7;
svetoslavganov75986cf2009-05-14 22:28:01 -0700665
666 private final HandlerCaller mCaller;
667
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800668 private final Callbacks mCallback;
svetoslavganov75986cf2009-05-14 22:28:01 -0700669
Svetoslavc4fccd12013-04-09 12:58:41 -0700670 private int mConnectionId;
671
Svetoslav Ganov42138042012-03-20 11:51:39 -0700672 public IAccessibilityServiceClientWrapper(Context context, Looper looper,
673 Callbacks callback) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800674 mCallback = callback;
Mita Yuned218c72012-12-06 17:18:25 -0800675 mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/);
svetoslavganov75986cf2009-05-14 22:28:01 -0700676 }
677
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800678 public void setConnection(IAccessibilityServiceConnection connection, int connectionId) {
679 Message message = mCaller.obtainMessageIO(DO_SET_SET_CONNECTION, connectionId,
680 connection);
svetoslavganov75986cf2009-05-14 22:28:01 -0700681 mCaller.sendMessage(message);
682 }
683
684 public void onInterrupt() {
685 Message message = mCaller.obtainMessage(DO_ON_INTERRUPT);
686 mCaller.sendMessage(message);
687 }
688
689 public void onAccessibilityEvent(AccessibilityEvent event) {
690 Message message = mCaller.obtainMessageO(DO_ON_ACCESSIBILITY_EVENT, event);
691 mCaller.sendMessage(message);
692 }
693
Svetoslav Ganov7b1e0c72012-05-13 11:57:29 -0700694 public void onGesture(int gestureId) {
695 Message message = mCaller.obtainMessageI(DO_ON_GESTURE, gestureId);
Svetoslav Ganov42138042012-03-20 11:51:39 -0700696 mCaller.sendMessage(message);
697 }
698
Svetoslav8e3feb12014-02-24 13:46:47 -0800699 public void clearAccessibilityCache() {
700 Message message = mCaller.obtainMessage(DO_CLEAR_ACCESSIBILITY_CACHE);
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -0700701 mCaller.sendMessage(message);
702 }
703
Svetoslavc4fccd12013-04-09 12:58:41 -0700704 @Override
705 public void onKeyEvent(KeyEvent event, int sequence) {
706 Message message = mCaller.obtainMessageIO(DO_ON_KEY_EVENT, sequence, event);
707 mCaller.sendMessage(message);
708 }
709
Svetoslav8e3feb12014-02-24 13:46:47 -0800710 @Override
711 public void onWindowsChanged(int[] windowIds) {
712 Message message = mCaller.obtainMessageO(DO_ON_WINDOWS_CHANGED, windowIds);
713 mCaller.sendMessage(message);
714 }
715
716 @Override
svetoslavganov75986cf2009-05-14 22:28:01 -0700717 public void executeMessage(Message message) {
718 switch (message.what) {
Svetoslavc4fccd12013-04-09 12:58:41 -0700719 case DO_ON_ACCESSIBILITY_EVENT: {
svetoslavganov75986cf2009-05-14 22:28:01 -0700720 AccessibilityEvent event = (AccessibilityEvent) message.obj;
Dianne Hackborn7ed6ee52009-09-10 18:41:28 -0700721 if (event != null) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800722 AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event);
723 mCallback.onAccessibilityEvent(event);
Svetoslav8e3feb12014-02-24 13:46:47 -0800724 // Make sure the event is recycled.
725 try {
726 event.recycle();
727 } catch (IllegalStateException ise) {
728 /* ignore - best effort */
729 }
Charles Chen85f6fb72009-08-28 11:32:23 -0700730 }
Svetoslavc4fccd12013-04-09 12:58:41 -0700731 } return;
Svetoslav8e3feb12014-02-24 13:46:47 -0800732
Svetoslavc4fccd12013-04-09 12:58:41 -0700733 case DO_ON_INTERRUPT: {
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800734 mCallback.onInterrupt();
Svetoslavc4fccd12013-04-09 12:58:41 -0700735 } return;
Svetoslav8e3feb12014-02-24 13:46:47 -0800736
Svetoslavc4fccd12013-04-09 12:58:41 -0700737 case DO_SET_SET_CONNECTION: {
738 mConnectionId = message.arg1;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800739 IAccessibilityServiceConnection connection =
740 (IAccessibilityServiceConnection) message.obj;
741 if (connection != null) {
Svetoslavc4fccd12013-04-09 12:58:41 -0700742 AccessibilityInteractionClient.getInstance().addConnection(mConnectionId,
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800743 connection);
Svetoslavc4fccd12013-04-09 12:58:41 -0700744 mCallback.onSetConnectionId(mConnectionId);
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800745 mCallback.onServiceConnected();
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800746 } else {
Svetoslav8e3feb12014-02-24 13:46:47 -0800747 AccessibilityInteractionClient.getInstance().removeConnection(
748 mConnectionId);
Svetoslavf7e50992013-01-22 18:15:40 -0800749 AccessibilityInteractionClient.getInstance().clearCache();
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800750 mCallback.onSetConnectionId(AccessibilityInteractionClient.NO_ID);
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800751 }
Svetoslavc4fccd12013-04-09 12:58:41 -0700752 } return;
Svetoslav8e3feb12014-02-24 13:46:47 -0800753
Svetoslavc4fccd12013-04-09 12:58:41 -0700754 case DO_ON_GESTURE: {
Svetoslav Ganov42138042012-03-20 11:51:39 -0700755 final int gestureId = message.arg1;
Svetoslav Ganov7b1e0c72012-05-13 11:57:29 -0700756 mCallback.onGesture(gestureId);
Svetoslavc4fccd12013-04-09 12:58:41 -0700757 } return;
Svetoslav8e3feb12014-02-24 13:46:47 -0800758
759 case DO_CLEAR_ACCESSIBILITY_CACHE: {
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -0700760 AccessibilityInteractionClient.getInstance().clearCache();
Svetoslavc4fccd12013-04-09 12:58:41 -0700761 } return;
Svetoslav8e3feb12014-02-24 13:46:47 -0800762
Svetoslavc4fccd12013-04-09 12:58:41 -0700763 case DO_ON_KEY_EVENT: {
764 KeyEvent event = (KeyEvent) message.obj;
765 try {
766 IAccessibilityServiceConnection connection = AccessibilityInteractionClient
767 .getInstance().getConnection(mConnectionId);
768 if (connection != null) {
769 final boolean result = mCallback.onKeyEvent(event);
770 final int sequence = message.arg1;
771 try {
772 connection.setOnKeyEventResult(result, sequence);
773 } catch (RemoteException re) {
774 /* ignore */
775 }
776 }
777 } finally {
Svetoslav8e3feb12014-02-24 13:46:47 -0800778 // Make sure the event is recycled.
779 try {
780 event.recycle();
781 } catch (IllegalStateException ise) {
782 /* ignore - best effort */
783 }
Svetoslavc4fccd12013-04-09 12:58:41 -0700784 }
785 } return;
Svetoslav8e3feb12014-02-24 13:46:47 -0800786
787 case DO_ON_WINDOWS_CHANGED: {
788 final int[] windowIds = (int[]) message.obj;
789
790 // Update the cached windows first.
791 // NOTE: The cache will hold on to the windows so do not recycle.
792 if (windowIds != null) {
793 AccessibilityInteractionClient.getInstance().removeWindows(windowIds);
794 }
795
796 // Let the client know the windows changed.
797 AccessibilityEvent event = AccessibilityEvent.obtain(
798 AccessibilityEvent.TYPE_WINDOWS_CHANGED);
799 event.setEventTime(SystemClock.uptimeMillis());
800 event.setSealed(true);
801
802 mCallback.onAccessibilityEvent(event);
803
804 // Make sure the event is recycled.
805 try {
806 event.recycle();
807 } catch (IllegalStateException ise) {
808 /* ignore - best effort */
809 }
810 } break;
811
svetoslavganov75986cf2009-05-14 22:28:01 -0700812 default :
813 Log.w(LOG_TAG, "Unknown message type " + message.what);
814 }
815 }
816 }
817}