blob: dd7719364a318c904d05422d740b7d63189455b0 [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.view.accessibility;
18
Svetoslav Ganov736c2752011-04-22 18:30:36 -070019import android.accessibilityservice.AccessibilityService;
20import android.accessibilityservice.AccessibilityServiceInfo;
svetoslavganov75986cf2009-05-14 22:28:01 -070021import android.content.Context;
22import android.content.pm.ServiceInfo;
23import android.os.Binder;
24import android.os.Handler;
25import android.os.IBinder;
26import android.os.Looper;
27import android.os.Message;
28import android.os.RemoteException;
29import android.os.ServiceManager;
30import android.os.SystemClock;
31import android.util.Log;
32
33import java.util.Collections;
34import java.util.List;
35
36/**
37 * System level service that serves as an event dispatch for {@link AccessibilityEvent}s.
38 * Such events are generated when something notable happens in the user interface,
39 * for example an {@link android.app.Activity} starts, the focus or selection of a
40 * {@link android.view.View} changes etc. Parties interested in handling accessibility
41 * events implement and register an accessibility service which extends
42 * {@link android.accessibilityservice.AccessibilityService}.
43 *
44 * @see AccessibilityEvent
45 * @see android.accessibilityservice.AccessibilityService
46 * @see android.content.Context#getSystemService
47 */
48public final class AccessibilityManager {
Svetoslav Ganov736c2752011-04-22 18:30:36 -070049 private static final boolean DEBUG = false;
50
svetoslavganov75986cf2009-05-14 22:28:01 -070051 private static final String LOG_TAG = "AccessibilityManager";
52
53 static final Object sInstanceSync = new Object();
54
55 private static AccessibilityManager sInstance;
56
57 private static final int DO_SET_ENABLED = 10;
58
59 final IAccessibilityManager mService;
60
61 final Handler mHandler;
62
63 boolean mIsEnabled;
64
65 final IAccessibilityManagerClient.Stub mClient = new IAccessibilityManagerClient.Stub() {
66 public void setEnabled(boolean enabled) {
67 mHandler.obtainMessage(DO_SET_ENABLED, enabled ? 1 : 0, 0).sendToTarget();
68 }
69 };
70
71 class MyHandler extends Handler {
72
73 MyHandler(Looper mainLooper) {
74 super(mainLooper);
75 }
76
77 @Override
78 public void handleMessage(Message message) {
79 switch (message.what) {
80 case DO_SET_ENABLED :
81 synchronized (mHandler) {
82 mIsEnabled = (message.arg1 == 1);
83 }
84 return;
85 default :
86 Log.w(LOG_TAG, "Unknown message type: " + message.what);
87 }
88 }
89 }
90
91 /**
92 * Get an AccessibilityManager instance (create one if necessary).
93 *
94 * @hide
95 */
96 public static AccessibilityManager getInstance(Context context) {
97 synchronized (sInstanceSync) {
98 if (sInstance == null) {
Svetoslav Ganovaf7adab2010-04-16 18:07:48 -070099 IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
100 IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder);
101 sInstance = new AccessibilityManager(context, service);
svetoslavganov75986cf2009-05-14 22:28:01 -0700102 }
103 }
104 return sInstance;
105 }
106
107 /**
108 * Create an instance.
109 *
110 * @param context A {@link Context}.
Svetoslav Ganovaf7adab2010-04-16 18:07:48 -0700111 * @param service An interface to the backing service.
112 *
113 * @hide
svetoslavganov75986cf2009-05-14 22:28:01 -0700114 */
Svetoslav Ganovaf7adab2010-04-16 18:07:48 -0700115 public AccessibilityManager(Context context, IAccessibilityManager service) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700116 mHandler = new MyHandler(context.getMainLooper());
Svetoslav Ganovaf7adab2010-04-16 18:07:48 -0700117 mService = service;
118
svetoslavganov75986cf2009-05-14 22:28:01 -0700119 try {
Svetoslav Ganovdd64a9b2010-04-13 18:41:17 -0700120 mIsEnabled = mService.addClient(mClient);
svetoslavganov75986cf2009-05-14 22:28:01 -0700121 } catch (RemoteException re) {
122 Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
123 }
124 }
125
126 /**
127 * Returns if the {@link AccessibilityManager} is enabled.
128 *
129 * @return True if this {@link AccessibilityManager} is enabled, false otherwise.
130 */
131 public boolean isEnabled() {
132 synchronized (mHandler) {
133 return mIsEnabled;
134 }
135 }
136
137 /**
Svetoslav Ganovaf7adab2010-04-16 18:07:48 -0700138 * Returns the client interface this instance registers in
139 * the centralized accessibility manager service.
140 *
141 * @return The client.
142 *
143 * @hide
144 */
145 public IAccessibilityManagerClient getClient() {
146 return (IAccessibilityManagerClient) mClient.asBinder();
147 }
148
149 /**
svetoslavganov75986cf2009-05-14 22:28:01 -0700150 * Sends an {@link AccessibilityEvent}. If this {@link AccessibilityManager} is not
151 * enabled the call is a NOOP.
152 *
153 * @param event The {@link AccessibilityEvent}.
154 *
155 * @throws IllegalStateException if a client tries to send an {@link AccessibilityEvent}
156 * while accessibility is not enabled.
157 */
158 public void sendAccessibilityEvent(AccessibilityEvent event) {
159 if (!mIsEnabled) {
160 throw new IllegalStateException("Accessibility off. Did you forget to check that?");
161 }
162 boolean doRecycle = false;
163 try {
164 event.setEventTime(SystemClock.uptimeMillis());
165 // it is possible that this manager is in the same process as the service but
166 // client using it is called through Binder from another process. Example: MMS
167 // app adds a SMS notification and the NotificationManagerService calls this method
168 long identityToken = Binder.clearCallingIdentity();
169 doRecycle = mService.sendAccessibilityEvent(event);
170 Binder.restoreCallingIdentity(identityToken);
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700171 if (DEBUG) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700172 Log.i(LOG_TAG, event + " sent");
173 }
174 } catch (RemoteException re) {
175 Log.e(LOG_TAG, "Error during sending " + event + " ", re);
176 } finally {
177 if (doRecycle) {
178 event.recycle();
179 }
180 }
181 }
182
183 /**
184 * Requests interruption of the accessibility feedback from all accessibility services.
185 */
186 public void interrupt() {
187 if (!mIsEnabled) {
188 throw new IllegalStateException("Accessibility off. Did you forget to check that?");
189 }
190 try {
191 mService.interrupt();
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700192 if (DEBUG) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700193 Log.i(LOG_TAG, "Requested interrupt from all services");
194 }
195 } catch (RemoteException re) {
196 Log.e(LOG_TAG, "Error while requesting interrupt from all services. ", re);
197 }
198 }
199
200 /**
201 * Returns the {@link ServiceInfo}s of the installed accessibility services.
202 *
203 * @return An unmodifiable list with {@link ServiceInfo}s.
204 */
205 public List<ServiceInfo> getAccessibilityServiceList() {
206 List<ServiceInfo> services = null;
207 try {
208 services = mService.getAccessibilityServiceList();
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700209 if (DEBUG) {
210 Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
211 }
212 } catch (RemoteException re) {
213 Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re);
214 }
215 return Collections.unmodifiableList(services);
216 }
217
218 /**
219 * Returns the {@link ServiceInfo}s of the enabled accessibility services
220 * for a given feedback type.
221 *
222 * @param feedbackType The type of feedback.
223 * @return An unmodifiable list with {@link ServiceInfo}s.
224 *
225 * @see AccessibilityServiceInfo#FEEDBACK_AUDIBLE
226 * @see AccessibilityServiceInfo#FEEDBACK_HAPTIC
227 * @see AccessibilityServiceInfo#FEEDBACK_SPOKEN
228 * @see AccessibilityServiceInfo#FEEDBACK_VISUAL
229 * @see AccessibilityServiceInfo#FEEDBACK_GENERIC
230 */
231 public List<ServiceInfo> getEnabledAccessibilityServiceList(int feedbackType) {
232 List<ServiceInfo> services = null;
233 try {
234 services = mService.getEnabledAccessibilityServiceList(feedbackType);
235 if (DEBUG) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700236 Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
237 }
238 } catch (RemoteException re) {
239 Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re);
240 }
241 return Collections.unmodifiableList(services);
242 }
243}