AccessibilityManager.java revision cc4053e031371456fe54d51bbad1db721db4ae38
1/* 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 19import android.accessibilityservice.AccessibilityServiceInfo; 20import android.content.Context; 21import android.content.pm.ServiceInfo; 22import android.os.Binder; 23import android.os.Handler; 24import android.os.IBinder; 25import android.os.Looper; 26import android.os.Message; 27import android.os.RemoteException; 28import android.os.ServiceManager; 29import android.os.SystemClock; 30import android.util.Log; 31 32import java.util.ArrayList; 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 { 49 private static final boolean DEBUG = false; 50 51 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) { 99 IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE); 100 IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder); 101 sInstance = new AccessibilityManager(context, service); 102 } 103 } 104 return sInstance; 105 } 106 107 /** 108 * Create an instance. 109 * 110 * @param context A {@link Context}. 111 * @param service An interface to the backing service. 112 * 113 * @hide 114 */ 115 public AccessibilityManager(Context context, IAccessibilityManager service) { 116 mHandler = new MyHandler(context.getMainLooper()); 117 mService = service; 118 119 try { 120 mIsEnabled = mService.addClient(mClient); 121 } 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 /** 138 * 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 /** 150 * 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); 171 if (DEBUG) { 172 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(); 192 if (DEBUG) { 193 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 * @deprecated Use {@link #getInstalledAccessibilityServiceList()} 206 */ 207 @Deprecated 208 public List<ServiceInfo> getAccessibilityServiceList() { 209 List<AccessibilityServiceInfo> infos = getInstalledAccessibilityServiceList(); 210 List<ServiceInfo> services = new ArrayList<ServiceInfo>(); 211 final int infoCount = infos.size(); 212 for (int i = 0; i < infoCount; i++) { 213 AccessibilityServiceInfo info = infos.get(i); 214 services.add(info.getResolveInfo().serviceInfo); 215 } 216 return Collections.unmodifiableList(services); 217 } 218 219 /** 220 * Returns the {@link AccessibilityServiceInfo}s of the installed accessibility services. 221 * 222 * @return An unmodifiable list with {@link AccessibilityServiceInfo}s. 223 */ 224 public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList() { 225 List<AccessibilityServiceInfo> services = null; 226 try { 227 services = mService.getInstalledAccessibilityServiceList(); 228 if (DEBUG) { 229 Log.i(LOG_TAG, "Installed AccessibilityServices " + services); 230 } 231 } catch (RemoteException re) { 232 Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re); 233 } 234 return Collections.unmodifiableList(services); 235 } 236 237 /** 238 * Returns the {@link AccessibilityServiceInfo}s of the enabled accessibility services 239 * for a given feedback type. 240 * 241 * @param feedbackType The feedback type (can be bitwise or of multiple types). 242 * @return An unmodifiable list with {@link AccessibilityServiceInfo}s. 243 */ 244 public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType) { 245 List<AccessibilityServiceInfo> services = null; 246 try { 247 services = mService.getEnabledAccessibilityServiceList(feedbackType); 248 if (DEBUG) { 249 Log.i(LOG_TAG, "Installed AccessibilityServices " + services); 250 } 251 } catch (RemoteException re) { 252 Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re); 253 } 254 return Collections.unmodifiableList(services); 255 } 256} 257