AccessibilityManagerService.java revision e20a177d3f147f3011647c3bdab401f90b2c5d1d
1/*
2 ** Copyright 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 com.android.server.accessibility;
18
19import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT;
20import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
21
22import android.Manifest;
23import android.accessibilityservice.AccessibilityService;
24import android.accessibilityservice.AccessibilityServiceInfo;
25import android.accessibilityservice.IAccessibilityServiceClient;
26import android.accessibilityservice.IAccessibilityServiceConnection;
27import android.app.AlertDialog;
28import android.app.PendingIntent;
29import android.app.StatusBarManager;
30import android.content.BroadcastReceiver;
31import android.content.ComponentName;
32import android.content.ContentResolver;
33import android.content.Context;
34import android.content.DialogInterface;
35import android.content.DialogInterface.OnClickListener;
36import android.content.Intent;
37import android.content.IntentFilter;
38import android.content.ServiceConnection;
39import android.content.pm.PackageManager;
40import android.content.pm.ResolveInfo;
41import android.content.pm.ServiceInfo;
42import android.database.ContentObserver;
43import android.graphics.Rect;
44import android.hardware.input.InputManager;
45import android.net.Uri;
46import android.os.Binder;
47import android.os.Build;
48import android.os.Bundle;
49import android.os.Handler;
50import android.os.IBinder;
51import android.os.Looper;
52import android.os.Message;
53import android.os.Process;
54import android.os.RemoteCallbackList;
55import android.os.RemoteException;
56import android.os.ServiceManager;
57import android.os.SystemClock;
58import android.os.UserHandle;
59import android.provider.Settings;
60import android.text.TextUtils;
61import android.text.TextUtils.SimpleStringSplitter;
62import android.util.Slog;
63import android.util.SparseArray;
64import android.view.IWindow;
65import android.view.IWindowManager;
66import android.view.InputDevice;
67import android.view.KeyCharacterMap;
68import android.view.KeyEvent;
69import android.view.WindowInfo;
70import android.view.WindowManager;
71import android.view.accessibility.AccessibilityEvent;
72import android.view.accessibility.AccessibilityInteractionClient;
73import android.view.accessibility.AccessibilityManager;
74import android.view.accessibility.AccessibilityNodeInfo;
75import android.view.accessibility.IAccessibilityInteractionConnection;
76import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
77import android.view.accessibility.IAccessibilityManager;
78import android.view.accessibility.IAccessibilityManagerClient;
79
80import com.android.internal.R;
81import com.android.internal.content.PackageMonitor;
82import com.android.internal.statusbar.IStatusBarService;
83
84import org.xmlpull.v1.XmlPullParserException;
85
86import java.io.IOException;
87import java.util.ArrayList;
88import java.util.Arrays;
89import java.util.HashMap;
90import java.util.HashSet;
91import java.util.Iterator;
92import java.util.List;
93import java.util.Map;
94import java.util.Set;
95import java.util.concurrent.CopyOnWriteArrayList;
96
97/**
98 * This class is instantiated by the system as a system level service and can be
99 * accessed only by the system. The task of this service is to be a centralized
100 * event dispatch for {@link AccessibilityEvent}s generated across all processes
101 * on the device. Events are dispatched to {@link AccessibilityService}s.
102 *
103 * @hide
104 */
105public class AccessibilityManagerService extends IAccessibilityManager.Stub {
106
107    private static final boolean DEBUG = false;
108
109    private static final String LOG_TAG = "AccessibilityManagerService";
110
111    private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE =
112        "registerUiTestAutomationService";
113
114    private static final char COMPONENT_NAME_SEPARATOR = ':';
115
116    private static final int OWN_PROCESS_ID = android.os.Process.myPid();
117
118    private static int sIdCounter = 0;
119
120    private static int sNextWindowId;
121
122    private final Context mContext;
123
124    private final Object mLock = new Object();
125
126    private final SimpleStringSplitter mStringColonSplitter =
127            new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
128
129    private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList =
130            new ArrayList<AccessibilityServiceInfo>();
131
132    private final PackageManager mPackageManager;
133
134    private final IWindowManager mWindowManagerService;
135
136    private final SecurityPolicy mSecurityPolicy;
137
138    private final MainHandler mMainHandler;
139
140    private Service mUiAutomationService;
141
142    private Service mQueryBridge;
143
144    private AlertDialog mEnableTouchExplorationDialog;
145
146    private AccessibilityInputFilter mInputFilter;
147
148    private boolean mHasInputFilter;
149
150    private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
151            new RemoteCallbackList<IAccessibilityManagerClient>();
152
153    private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections =
154            new SparseArray<AccessibilityConnectionWrapper>();
155
156    private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<IBinder>();
157
158    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
159
160    private int mCurrentUserId = UserHandle.USER_NULL;
161
162    private UserState getCurrentUserStateLocked() {
163        return getUserStateLocked(mCurrentUserId);
164    }
165
166    private UserState getUserStateLocked(int userId) {
167        UserState state = mUserStates.get(userId);
168        if (state == null) {
169            state = new UserState(userId);
170            mUserStates.put(userId, state);
171        }
172        return state;
173    }
174
175    /**
176     * Creates a new instance.
177     *
178     * @param context A {@link Context} instance.
179     */
180    public AccessibilityManagerService(Context context) {
181        mContext = context;
182        mPackageManager = mContext.getPackageManager();
183        mWindowManagerService = (IWindowManager) ServiceManager.getService(Context.WINDOW_SERVICE);
184        mSecurityPolicy = new SecurityPolicy();
185        mMainHandler = new MainHandler(mContext.getMainLooper());
186        registerBroadcastReceivers();
187        new AccessibilityContentObserver(mMainHandler).register(
188                context.getContentResolver());
189    }
190
191    private void registerBroadcastReceivers() {
192        PackageMonitor monitor = new PackageMonitor() {
193            @Override
194            public void onSomePackagesChanged() {
195                synchronized (mLock) {
196                    if (getChangingUserId() != mCurrentUserId) {
197                        return;
198                    }
199                    // We will update when the automation service dies.
200                    if (mUiAutomationService == null) {
201                        UserState userState = getCurrentUserStateLocked();
202                        populateInstalledAccessibilityServiceLocked(userState);
203                        manageServicesLocked(userState);
204                    }
205                }
206            }
207
208            @Override
209            public void onPackageRemoved(String packageName, int uid) {
210                synchronized (mLock) {
211                    final int userId = getChangingUserId();
212                    if (userId != mCurrentUserId) {
213                        return;
214                    }
215                    UserState state = getUserStateLocked(userId);
216                    Iterator<ComponentName> it = state.mEnabledServices.iterator();
217                    while (it.hasNext()) {
218                        ComponentName comp = it.next();
219                        String compPkg = comp.getPackageName();
220                        if (compPkg.equals(packageName)) {
221                            it.remove();
222                            // Update the enabled services setting.
223                            persistComponentNamesToSettingLocked(
224                                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
225                                    state.mEnabledServices, userId);
226                            // Update the touch exploration granted services setting.
227                            state.mTouchExplorationGrantedServices.remove(comp);
228                            persistComponentNamesToSettingLocked(
229                                    Settings.Secure.
230                                            TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
231                                    state.mEnabledServices, userId);
232                            return;
233                        }
234                    }
235                }
236            }
237
238            @Override
239            public boolean onHandleForceStop(Intent intent, String[] packages,
240                    int uid, boolean doit) {
241                synchronized (mLock) {
242                    final int userId = getChangingUserId();
243                    if (userId != mCurrentUserId) {
244                        return false;
245                    }
246                    UserState state = getUserStateLocked(userId);
247                    Iterator<ComponentName> it = state.mEnabledServices.iterator();
248                    while (it.hasNext()) {
249                        ComponentName comp = it.next();
250                        String compPkg = comp.getPackageName();
251                        for (String pkg : packages) {
252                            if (compPkg.equals(pkg)) {
253                                if (!doit) {
254                                    return true;
255                                }
256                                it.remove();
257                                persistComponentNamesToSettingLocked(
258                                        Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
259                                        state.mEnabledServices, userId);
260                            }
261                        }
262                    }
263                    return false;
264                }
265            }
266        };
267
268        // package changes
269        monitor.register(mContext, null,  UserHandle.ALL, true);
270
271        // user change
272        IntentFilter userFilter = new IntentFilter();
273        userFilter.addAction(Intent.ACTION_USER_SWITCHED);
274        userFilter.addAction(Intent.ACTION_USER_REMOVED);
275
276        mContext.registerReceiver(new BroadcastReceiver() {
277            @Override
278            public void onReceive(Context context, Intent intent) {
279                String action = intent.getAction();
280                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
281                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
282                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
283                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
284                }
285            }
286        }, userFilter);
287    }
288
289    public int addClient(IAccessibilityManagerClient client, int userId) {
290        synchronized (mLock) {
291            final int resolvedUserId = mSecurityPolicy
292                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
293            // If the client is from a process that runs across users such as
294            // the system UI or the system we add it to the global state that
295            // is shared across users.
296            UserState userState = getUserStateLocked(resolvedUserId);
297            if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
298                mGlobalClients.register(client);
299                return getClientState(userState);
300            } else {
301                userState.mClients.register(client);
302                // If this client is not for the current user we do not
303                // return a state since it is not for the foreground user.
304                // We will send the state to the client on a user switch.
305                return (resolvedUserId == mCurrentUserId) ? getClientState(userState) : 0;
306            }
307        }
308    }
309
310    public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) {
311        synchronized (mLock) {
312            final int resolvedUserId = mSecurityPolicy
313                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
314            // This method does nothing for a background user.
315            if (resolvedUserId != mCurrentUserId) {
316                return true; // yes, recycle the event
317            }
318            if (mSecurityPolicy.canDispatchAccessibilityEvent(event)) {
319                mSecurityPolicy.updateActiveWindowAndEventSourceLocked(event);
320                notifyAccessibilityServicesDelayedLocked(event, false);
321                notifyAccessibilityServicesDelayedLocked(event, true);
322            }
323            if (mHasInputFilter && mInputFilter != null) {
324                mMainHandler.obtainMessage(MainHandler.MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER,
325                        AccessibilityEvent.obtain(event)).sendToTarget();
326            }
327            event.recycle();
328            getUserStateLocked(resolvedUserId).mHandledFeedbackTypes = 0;
329        }
330        return (OWN_PROCESS_ID != Binder.getCallingPid());
331    }
332
333    public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
334        synchronized (mLock) {
335            final int resolvedUserId = mSecurityPolicy
336                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
337            return getUserStateLocked(resolvedUserId).mInstalledServices;
338        }
339    }
340
341    public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,
342            int userId) {
343        List<AccessibilityServiceInfo> result = null;
344        synchronized (mLock) {
345            final int resolvedUserId = mSecurityPolicy
346                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
347            result = mEnabledServicesForFeedbackTempList;
348            result.clear();
349            List<Service> services = getUserStateLocked(resolvedUserId).mServices;
350            while (feedbackType != 0) {
351                final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType));
352                feedbackType &= ~feedbackTypeBit;
353                final int serviceCount = services.size();
354                for (int i = 0; i < serviceCount; i++) {
355                    Service service = services.get(i);
356                    if ((service.mFeedbackType & feedbackTypeBit) != 0) {
357                        result.add(service.mAccessibilityServiceInfo);
358                    }
359                }
360            }
361        }
362        return result;
363    }
364
365    public void interrupt(int userId) {
366        CopyOnWriteArrayList<Service> services;
367        synchronized (mLock) {
368            final int resolvedUserId = mSecurityPolicy
369                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
370            // This method does nothing for a background user.
371            if (resolvedUserId != mCurrentUserId) {
372                return;
373            }
374            services = getUserStateLocked(resolvedUserId).mServices;
375        }
376        for (int i = 0, count = services.size(); i < count; i++) {
377            Service service = services.get(i);
378            try {
379                service.mServiceInterface.onInterrupt();
380            } catch (RemoteException re) {
381                Slog.e(LOG_TAG, "Error during sending interrupt request to "
382                    + service.mService, re);
383            }
384        }
385    }
386
387    public int addAccessibilityInteractionConnection(IWindow windowToken,
388            IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
389        synchronized (mLock) {
390            final int resolvedUserId = mSecurityPolicy
391                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
392            final int windowId = sNextWindowId++;
393            // If the window is from a process that runs across users such as
394            // the system UI or the system we add it to the global state that
395            // is shared across users.
396            if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
397                AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
398                        windowId, connection, UserHandle.USER_ALL);
399                wrapper.linkToDeath();
400                mGlobalInteractionConnections.put(windowId, wrapper);
401                mGlobalWindowTokens.put(windowId, windowToken.asBinder());
402            } else {
403                AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
404                        windowId, connection, resolvedUserId);
405                wrapper.linkToDeath();
406                UserState userState = getUserStateLocked(resolvedUserId);
407                userState.mInteractionConnections.put(windowId, wrapper);
408                userState.mWindowTokens.put(windowId, windowToken.asBinder());
409            }
410            if (DEBUG) {
411                Slog.i(LOG_TAG, "Adding interaction connection to windowId: " + windowId);
412            }
413            return windowId;
414        }
415    }
416
417    public void removeAccessibilityInteractionConnection(IWindow window) {
418        synchronized (mLock) {
419            mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
420                    UserHandle.getCallingUserId());
421            IBinder token = window.asBinder();
422            final boolean removedGlobal =
423                    removeAccessibilityInteractionConnectionInternalLocked(
424                    token, mGlobalWindowTokens, mGlobalInteractionConnections);
425            if (removedGlobal) {
426                return;
427            }
428            final int userCount = mUserStates.size();
429            for (int i = 0; i < userCount; i++) {
430                UserState userState = mUserStates.valueAt(i);
431                final boolean removedForUser =
432                        removeAccessibilityInteractionConnectionInternalLocked(
433                        token, userState.mWindowTokens, userState.mInteractionConnections);
434                if (removedForUser) {
435                    return;
436                }
437            }
438        }
439    }
440
441    private boolean removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken,
442            SparseArray<IBinder> windowTokens,
443            SparseArray<AccessibilityConnectionWrapper> interactionConnections) {
444        final int count = windowTokens.size();
445        for (int i = 0; i < count; i++) {
446            if (windowTokens.valueAt(i) == windowToken) {
447                final int windowId = windowTokens.keyAt(i);
448                windowTokens.removeAt(i);
449                AccessibilityConnectionWrapper wrapper = interactionConnections.get(windowId);
450                wrapper.unlinkToDeath();
451                interactionConnections.remove(windowId);
452                return true;
453            }
454        }
455        return false;
456    }
457
458    public void registerUiTestAutomationService(IAccessibilityServiceClient serviceClient,
459            AccessibilityServiceInfo accessibilityServiceInfo) {
460        mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
461                FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
462        ComponentName componentName = new ComponentName("foo.bar",
463                "AutomationAccessibilityService");
464        synchronized (mLock) {
465            // If an automation services is connected to the system all services are stopped
466            // so the automation one is the only one running. Settings are not changed so when
467            // the automation service goes away the state is restored from the settings.
468            UserState userState = getCurrentUserStateLocked();
469            unbindAllServicesLocked(userState);
470
471            // If necessary enable accessibility and announce that.
472            if (!userState.mIsAccessibilityEnabled) {
473                userState.mIsAccessibilityEnabled = true;
474            }
475            // No touch exploration.
476            userState.mIsTouchExplorationEnabled = false;
477
478            // Hook the automation service up.
479            mUiAutomationService = new Service(mCurrentUserId, componentName,
480                    accessibilityServiceInfo, true);
481            mUiAutomationService.onServiceConnected(componentName, serviceClient.asBinder());
482
483            updateInputFilterLocked(userState);
484            scheduleSendStateToClientsLocked(userState);
485        }
486    }
487
488    public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
489        synchronized (mLock) {
490            // Automation service is not bound, so pretend it died to perform clean up.
491            if (mUiAutomationService != null
492                    && mUiAutomationService.mServiceInterface == serviceClient) {
493                mUiAutomationService.binderDied();
494            }
495        }
496    }
497
498    boolean onGesture(int gestureId) {
499        synchronized (mLock) {
500            boolean handled = notifyGestureLocked(gestureId, false);
501            if (!handled) {
502                handled = notifyGestureLocked(gestureId, true);
503            }
504            return handled;
505        }
506    }
507
508    /**
509     * Gets the bounds of the accessibility focus in the active window.
510     *
511     * @param outBounds The output to which to write the focus bounds.
512     * @return Whether accessibility focus was found and the bounds are populated.
513     */
514    boolean getAccessibilityFocusBoundsInActiveWindow(Rect outBounds) {
515        // Instead of keeping track of accessibility focus events per
516        // window to be able to find the focus in the active window,
517        // we take a stateless approach and look it up. This is fine
518        // since we do this only when the user clicks/long presses.
519        Service service = getQueryBridge();
520        final int connectionId = service.mId;
521        AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
522        client.addConnection(connectionId, service);
523        try {
524            AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance()
525                    .getRootInActiveWindow(connectionId);
526            if (root == null) {
527                return false;
528            }
529            AccessibilityNodeInfo focus = root.findFocus(
530                    AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
531            if (focus == null) {
532                return false;
533            }
534            focus.getBoundsInScreen(outBounds);
535            return true;
536        } finally {
537            client.removeConnection(connectionId);
538        }
539    }
540
541    /**
542     * Gets the bounds of the active window.
543     *
544     * @param outBounds The output to which to write the bounds.
545     */
546    boolean getActiveWindowBounds(Rect outBounds) {
547        IBinder token;
548        synchronized (mLock) {
549            final int windowId = mSecurityPolicy.mActiveWindowId;
550            token = mGlobalWindowTokens.get(windowId);
551            if (token == null) {
552                token = getCurrentUserStateLocked().mWindowTokens.get(windowId);
553            }
554        }
555        WindowInfo info = null;
556        try {
557            info = mWindowManagerService.getWindowInfo(token);
558            if (info != null) {
559                outBounds.set(info.frame);
560                return true;
561            }
562        } catch (RemoteException re) {
563            /* ignore */
564        } finally {
565            if (info != null) {
566                info.recycle();
567            }
568        }
569        return false;
570    }
571
572    int getActiveWindowId() {
573        return mSecurityPolicy.mActiveWindowId;
574    }
575
576    private void switchUser(int userId) {
577        synchronized (mLock) {
578            if (userId == mCurrentUserId) {
579                return;
580            }
581
582            // Disconnect from services for the old user.
583            UserState oldUserState = getUserStateLocked(mCurrentUserId);
584            unbindAllServicesLocked(oldUserState);
585
586            // Disable the local managers for the old user.
587            if (oldUserState.mClients.getRegisteredCallbackCount() > 0) {
588                mMainHandler.obtainMessage(MainHandler.MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER,
589                        oldUserState.mUserId, 0).sendToTarget();
590            }
591
592            // The user changed.
593            mCurrentUserId = userId;
594
595            // Recreate the internal state for the new user.
596            mMainHandler.obtainMessage(MainHandler.MSG_SEND_RECREATE_INTERNAL_STATE,
597                    mCurrentUserId, 0).sendToTarget();
598        }
599    }
600
601    private void removeUser(int userId) {
602        synchronized (mLock) {
603            mUserStates.remove(userId);
604        }
605    }
606
607    private Service getQueryBridge() {
608        if (mQueryBridge == null) {
609            AccessibilityServiceInfo info = new AccessibilityServiceInfo();
610            mQueryBridge = new Service(UserHandle.USER_NULL, null, info, true);
611        }
612        return mQueryBridge;
613    }
614
615    private boolean notifyGestureLocked(int gestureId, boolean isDefault) {
616        // TODO: Now we are giving the gestures to the last enabled
617        //       service that can handle them which is the last one
618        //       in our list since we write the last enabled as the
619        //       last record in the enabled services setting. Ideally,
620        //       the user should make the call which service handles
621        //       gestures. However, only one service should handle
622        //       gestures to avoid user frustration when different
623        //       behavior is observed from different combinations of
624        //       enabled accessibility services.
625        UserState state = getCurrentUserStateLocked();
626        for (int i = state.mServices.size() - 1; i >= 0; i--) {
627            Service service = state.mServices.get(i);
628            if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) {
629                service.notifyGesture(gestureId);
630                return true;
631            }
632        }
633        return false;
634    }
635
636    /**
637     * Removes an AccessibilityInteractionConnection.
638     *
639     * @param windowId The id of the window to which the connection is targeted.
640     * @param userId The id of the user owning the connection. UserHandle.USER_ALL
641     *     if global.
642     */
643    private void removeAccessibilityInteractionConnectionLocked(int windowId, int userId) {
644        if (userId == UserHandle.USER_ALL) {
645            mGlobalWindowTokens.remove(windowId);
646            mGlobalInteractionConnections.remove(windowId);
647        } else {
648            UserState userState = getCurrentUserStateLocked();
649            userState.mWindowTokens.remove(windowId);
650            userState.mInteractionConnections.remove(windowId);
651        }
652        if (DEBUG) {
653            Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId);
654        }
655    }
656
657    private void populateInstalledAccessibilityServiceLocked(UserState userState) {
658        userState.mInstalledServices.clear();
659
660        List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
661                new Intent(AccessibilityService.SERVICE_INTERFACE),
662                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
663                mCurrentUserId);
664
665        for (int i = 0, count = installedServices.size(); i < count; i++) {
666            ResolveInfo resolveInfo = installedServices.get(i);
667            ServiceInfo serviceInfo = resolveInfo.serviceInfo;
668            if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals(
669                    serviceInfo.permission)) {
670                Slog.w(LOG_TAG, "Skipping accessibilty service " + new ComponentName(
671                        serviceInfo.packageName, serviceInfo.name).flattenToShortString()
672                        + ": it does not require the permission "
673                        + android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE);
674                continue;
675            }
676            AccessibilityServiceInfo accessibilityServiceInfo;
677            try {
678                accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
679                userState.mInstalledServices.add(accessibilityServiceInfo);
680            } catch (XmlPullParserException xppe) {
681                Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe);
682            } catch (IOException ioe) {
683                Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", ioe);
684            }
685        }
686    }
687
688    private void populateEnabledAccessibilityServicesLocked(UserState userState) {
689        populateComponentNamesFromSettingLocked(
690                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
691                userState.mUserId,
692                userState.mEnabledServices);
693    }
694
695    private void populateTouchExplorationGrantedAccessibilityServicesLocked(
696            UserState userState) {
697        populateComponentNamesFromSettingLocked(
698                Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
699                userState.mUserId,
700                userState.mTouchExplorationGrantedServices);
701    }
702
703    /**
704     * Performs {@link AccessibilityService}s delayed notification. The delay is configurable
705     * and denotes the period after the last event before notifying the service.
706     *
707     * @param event The event.
708     * @param isDefault True to notify default listeners, not default services.
709     */
710    private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event,
711            boolean isDefault) {
712        try {
713            UserState state = getCurrentUserStateLocked();
714            for (int i = 0, count = state.mServices.size(); i < count; i++) {
715                Service service = state.mServices.get(i);
716
717                if (service.mIsDefault == isDefault) {
718                    if (canDispathEventLocked(service, event, state.mHandledFeedbackTypes)) {
719                        state.mHandledFeedbackTypes |= service.mFeedbackType;
720                        service.notifyAccessibilityEvent(event);
721                    }
722                }
723            }
724        } catch (IndexOutOfBoundsException oobe) {
725            // An out of bounds exception can happen if services are going away
726            // as the for loop is running. If that happens, just bail because
727            // there are no more services to notify.
728            return;
729        }
730    }
731
732    /**
733     * Adds a service for a user.
734     *
735     * @param service The service to add.
736     * @param userId The user id.
737     */
738    private void tryAddServiceLocked(Service service, int userId) {
739        try {
740            UserState userState = getUserStateLocked(userId);
741            if (userState.mServices.contains(service) || !service.isConfigured()) {
742                return;
743            }
744            service.linkToOwnDeath();
745            userState.mServices.add(service);
746            userState.mComponentNameToServiceMap.put(service.mComponentName, service);
747            updateInputFilterLocked(userState);
748            tryEnableTouchExplorationLocked(service);
749        } catch (RemoteException e) {
750            /* do nothing */
751        }
752    }
753
754    /**
755     * Removes a service.
756     *
757     * @param service The service.
758     * @return True if the service was removed, false otherwise.
759     */
760    private boolean tryRemoveServiceLocked(Service service) {
761        UserState userState = getUserStateLocked(service.mUserId);
762        final boolean removed = userState.mServices.remove(service);
763        if (!removed) {
764            return false;
765        }
766        userState.mComponentNameToServiceMap.remove(service.mComponentName);
767        service.unlinkToOwnDeath();
768        service.dispose();
769        updateInputFilterLocked(userState);
770        tryDisableTouchExplorationLocked(service);
771        return removed;
772    }
773
774    /**
775     * Determines if given event can be dispatched to a service based on the package of the
776     * event source and already notified services for that event type. Specifically, a
777     * service is notified if it is interested in events from the package and no other service
778     * providing the same feedback type has been notified. Exception are services the
779     * provide generic feedback (feedback type left as a safety net for unforeseen feedback
780     * types) which are always notified.
781     *
782     * @param service The potential receiver.
783     * @param event The event.
784     * @param handledFeedbackTypes The feedback types for which services have been notified.
785     * @return True if the listener should be notified, false otherwise.
786     */
787    private boolean canDispathEventLocked(Service service, AccessibilityEvent event,
788            int handledFeedbackTypes) {
789
790        if (!service.isConfigured()) {
791            return false;
792        }
793
794        if (!event.isImportantForAccessibility()
795                && !service.mIncludeNotImportantViews) {
796            return false;
797        }
798
799        int eventType = event.getEventType();
800        if ((service.mEventTypes & eventType) != eventType) {
801            return false;
802        }
803
804        Set<String> packageNames = service.mPackageNames;
805        CharSequence packageName = event.getPackageName();
806
807        if (packageNames.isEmpty() || packageNames.contains(packageName)) {
808            int feedbackType = service.mFeedbackType;
809            if ((handledFeedbackTypes & feedbackType) != feedbackType
810                    || feedbackType == AccessibilityServiceInfo.FEEDBACK_GENERIC) {
811                return true;
812            }
813        }
814
815        return false;
816    }
817
818    /**
819     * Manages services by starting enabled ones and stopping disabled ones.
820     */
821    private void manageServicesLocked(UserState userState) {
822        final int enabledInstalledServicesCount = updateServicesStateLocked(userState);
823        // No enabled installed services => disable accessibility to avoid
824        // sending accessibility events with no recipient across processes.
825        if (userState.mIsAccessibilityEnabled && enabledInstalledServicesCount == 0) {
826            Settings.Secure.putIntForUser(mContext.getContentResolver(),
827                    Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
828        }
829    }
830
831    /**
832     * Unbinds all bound services for a user.
833     *
834     * @param userState The user state.
835     */
836    private void unbindAllServicesLocked(UserState userState) {
837        List<Service> services = userState.mServices;
838        for (int i = 0, count = services.size(); i < count; i++) {
839            Service service = services.get(i);
840            if (service.unbind()) {
841                i--;
842                count--;
843            }
844        }
845    }
846
847    /**
848     * Populates a set with the {@link ComponentName}s stored in a colon
849     * separated value setting for a given user.
850     *
851     * @param settingName The setting to parse.
852     * @param userId The user id.
853     * @param outComponentNames The output component names.
854     */
855    private void populateComponentNamesFromSettingLocked(String settingName, int userId,
856            Set<ComponentName> outComponentNames) {
857        String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
858                settingName, userId);
859        outComponentNames.clear();
860        if (settingValue != null) {
861            TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
862            splitter.setString(settingValue);
863            while (splitter.hasNext()) {
864                String str = splitter.next();
865                if (str == null || str.length() <= 0) {
866                    continue;
867                }
868                ComponentName enabledService = ComponentName.unflattenFromString(str);
869                if (enabledService != null) {
870                    outComponentNames.add(enabledService);
871                }
872            }
873        }
874    }
875
876    /**
877     * Persists the component names in the specified setting in a
878     * colon separated fashion.
879     *
880     * @param settingName The setting name.
881     * @param componentNames The component names.
882     */
883    private void persistComponentNamesToSettingLocked(String settingName,
884            Set<ComponentName> componentNames, int userId) {
885        StringBuilder builder = new StringBuilder();
886        for (ComponentName componentName : componentNames) {
887            if (builder.length() > 0) {
888                builder.append(COMPONENT_NAME_SEPARATOR);
889            }
890            builder.append(componentName.flattenToShortString());
891        }
892        Settings.Secure.putStringForUser(mContext.getContentResolver(),
893                settingName, builder.toString(), userId);
894    }
895
896    /**
897     * Updates the state of each service by starting (or keeping running) enabled ones and
898     * stopping the rest.
899     *
900     * @param userState The user state for which to do that.
901     * @return The number of enabled installed services.
902     */
903    private int updateServicesStateLocked(UserState userState) {
904        Map<ComponentName, Service> componentNameToServiceMap =
905                userState.mComponentNameToServiceMap;
906        boolean isEnabled = userState.mIsAccessibilityEnabled;
907
908        int enabledInstalledServices = 0;
909        for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
910            AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
911            ComponentName componentName = ComponentName.unflattenFromString(
912                    installedService.getId());
913            Service service = componentNameToServiceMap.get(componentName);
914
915            if (isEnabled) {
916                if (userState.mEnabledServices.contains(componentName)) {
917                    if (service == null) {
918                        service = new Service(userState.mUserId, componentName,
919                                installedService, false);
920                    }
921                    service.bind();
922                    enabledInstalledServices++;
923                } else {
924                    if (service != null) {
925                        service.unbind();
926                    }
927                }
928            } else {
929                if (service != null) {
930                    service.unbind();
931                }
932            }
933        }
934
935        return enabledInstalledServices;
936    }
937
938    private void scheduleSendStateToClientsLocked(UserState userState) {
939        if (mGlobalClients.getRegisteredCallbackCount() > 0
940                || userState.mClients.getRegisteredCallbackCount() > 0) {
941            final int clientState = getClientState(userState);
942            mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS,
943                    clientState, userState.mUserId) .sendToTarget();
944        }
945    }
946
947    private void updateInputFilterLocked(UserState userState) {
948        boolean setInputFilter = false;
949        AccessibilityInputFilter inputFilter = null;
950        synchronized (mLock) {
951            if ((userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled)
952                    || userState.mIsDisplayMagnificationEnabled) {
953                if (!mHasInputFilter) {
954                    mHasInputFilter = true;
955                    if (mInputFilter == null) {
956                        mInputFilter = new AccessibilityInputFilter(mContext,
957                                AccessibilityManagerService.this);
958                    }
959                    inputFilter = mInputFilter;
960                    setInputFilter = true;
961                }
962                int flags = 0;
963                if (userState.mIsDisplayMagnificationEnabled) {
964                    flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
965                }
966                if (userState.mIsTouchExplorationEnabled) {
967                    flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
968                }
969                mInputFilter.setEnabledFeatures(flags);
970            } else {
971                if (mHasInputFilter) {
972                    mHasInputFilter = false;
973                    mInputFilter.setEnabledFeatures(0);
974                    inputFilter = null;
975                    setInputFilter = true;
976                }
977            }
978        }
979        if (setInputFilter) {
980            try {
981                mWindowManagerService.setInputFilter(inputFilter);
982            } catch (RemoteException re) {
983                /* ignore */
984            }
985        }
986    }
987
988    private void showEnableTouchExplorationDialog(final Service service) {
989        String label = service.mResolveInfo.loadLabel(
990                mContext.getPackageManager()).toString();
991        synchronized (mLock) {
992            final UserState state = getCurrentUserStateLocked();
993            if (state.mIsTouchExplorationEnabled) {
994                return;
995            }
996            if (mEnableTouchExplorationDialog != null
997                    && mEnableTouchExplorationDialog.isShowing()) {
998                return;
999            }
1000            mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext)
1001                .setIcon(android.R.drawable.ic_dialog_alert)
1002                .setPositiveButton(android.R.string.ok, new OnClickListener() {
1003                    @Override
1004                    public void onClick(DialogInterface dialog, int which) {
1005                        // The user allowed the service to toggle touch exploration.
1006                        state.mTouchExplorationGrantedServices.add(service.mComponentName);
1007                        persistComponentNamesToSettingLocked(
1008                                Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
1009                                       state.mTouchExplorationGrantedServices, state.mUserId);
1010                        // Enable touch exploration.
1011                        Settings.Secure.putIntForUser(mContext.getContentResolver(),
1012                                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1,
1013                                service.mUserId);
1014                    }
1015                })
1016                .setNegativeButton(android.R.string.cancel, new OnClickListener() {
1017                    @Override
1018                    public void onClick(DialogInterface dialog, int which) {
1019                        dialog.dismiss();
1020                    }
1021                })
1022                .setTitle(R.string.enable_explore_by_touch_warning_title)
1023                .setMessage(mContext.getString(
1024                        R.string.enable_explore_by_touch_warning_message, label))
1025                .create();
1026            mEnableTouchExplorationDialog.getWindow().setType(
1027                    WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
1028            mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true);
1029            mEnableTouchExplorationDialog.show();
1030        }
1031    }
1032
1033    private int getClientState(UserState userState) {
1034        int clientState = 0;
1035        if (userState.mIsAccessibilityEnabled) {
1036            clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
1037        }
1038        // Touch exploration relies on enabled accessibility.
1039        if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) {
1040            clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
1041        }
1042        return clientState;
1043    }
1044
1045    private void recreateInternalStateLocked(UserState userState) {
1046        populateInstalledAccessibilityServiceLocked(userState);
1047        populateEnabledAccessibilityServicesLocked(userState);
1048        populateTouchExplorationGrantedAccessibilityServicesLocked(userState);
1049
1050        handleTouchExplorationEnabledSettingChangedLocked(userState);
1051        handleDisplayMagnificationEnabledSettingChangedLocked(userState);
1052        handleAccessibilityEnabledSettingChangedLocked(userState);
1053
1054        updateInputFilterLocked(userState);
1055        scheduleSendStateToClientsLocked(userState);
1056    }
1057
1058    private void handleAccessibilityEnabledSettingChangedLocked(UserState userState) {
1059        userState.mIsAccessibilityEnabled = Settings.Secure.getIntForUser(
1060               mContext.getContentResolver(),
1061               Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1;
1062        if (userState.mIsAccessibilityEnabled ) {
1063            manageServicesLocked(userState);
1064        } else {
1065            unbindAllServicesLocked(userState);
1066        }
1067    }
1068
1069    private void handleTouchExplorationEnabledSettingChangedLocked(UserState userState) {
1070        userState.mIsTouchExplorationEnabled = Settings.Secure.getIntForUser(
1071                mContext.getContentResolver(),
1072                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1;
1073    }
1074
1075    private void handleDisplayMagnificationEnabledSettingChangedLocked(UserState userState) {
1076        userState.mIsDisplayMagnificationEnabled = Settings.Secure.getIntForUser(
1077                mContext.getContentResolver(),
1078                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
1079                0, userState.mUserId) == 1;
1080    }
1081
1082    private void handleTouchExplorationGrantedAccessibilityServicesChangedLocked(
1083            UserState userState) {
1084        final int serviceCount = userState.mServices.size();
1085        for (int i = 0; i < serviceCount; i++) {
1086            Service service = userState.mServices.get(i);
1087            if (service.mRequestTouchExplorationMode
1088                    && userState.mTouchExplorationGrantedServices.contains(
1089                            service.mComponentName)) {
1090                tryEnableTouchExplorationLocked(service);
1091                return;
1092            }
1093        }
1094        if (userState.mIsTouchExplorationEnabled) {
1095            Settings.Secure.putIntForUser(mContext.getContentResolver(),
1096                    Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId);
1097        }
1098    }
1099
1100    private void tryEnableTouchExplorationLocked(final Service service) {
1101        UserState userState = getUserStateLocked(service.mUserId);
1102        if (!userState.mIsTouchExplorationEnabled && service.mRequestTouchExplorationMode) {
1103            final boolean canToggleTouchExploration =
1104                    userState.mTouchExplorationGrantedServices.contains(service.mComponentName);
1105            if (!service.mIsAutomation && !canToggleTouchExploration) {
1106                showEnableTouchExplorationDialog(service);
1107            } else {
1108                Settings.Secure.putIntForUser(mContext.getContentResolver(),
1109                        Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, userState.mUserId);
1110            }
1111        }
1112    }
1113
1114    private void tryDisableTouchExplorationLocked(Service service) {
1115        UserState userState = getUserStateLocked(service.mUserId);
1116        if (userState.mIsTouchExplorationEnabled) {
1117            final int serviceCount = userState.mServices.size();
1118            for (int i = 0; i < serviceCount; i++) {
1119                Service other = userState.mServices.get(i);
1120                if (other != service && other.mRequestTouchExplorationMode) {
1121                    return;
1122                }
1123            }
1124            Settings.Secure.putIntForUser(mContext.getContentResolver(),
1125                    Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId);
1126        }
1127    }
1128
1129    private class AccessibilityConnectionWrapper implements DeathRecipient {
1130        private final int mWindowId;
1131        private final int mUserId;
1132        private final IAccessibilityInteractionConnection mConnection;
1133
1134        public AccessibilityConnectionWrapper(int windowId,
1135                IAccessibilityInteractionConnection connection, int userId) {
1136            mWindowId = windowId;
1137            mUserId = userId;
1138            mConnection = connection;
1139        }
1140
1141        public void linkToDeath() throws RemoteException {
1142            mConnection.asBinder().linkToDeath(this, 0);
1143        }
1144
1145        public void unlinkToDeath() {
1146            mConnection.asBinder().unlinkToDeath(this, 0);
1147        }
1148
1149        @Override
1150        public void binderDied() {
1151            unlinkToDeath();
1152            synchronized (mLock) {
1153                removeAccessibilityInteractionConnectionLocked(mWindowId, mUserId);
1154            }
1155        }
1156    }
1157
1158    private final class MainHandler extends Handler {
1159        public static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 1;
1160        public static final int MSG_SEND_STATE_TO_CLIENTS = 2;
1161        public static final int MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER = 3;
1162        public static final int MSG_SEND_RECREATE_INTERNAL_STATE = 4;
1163
1164        public MainHandler(Looper looper) {
1165            super(looper);
1166        }
1167
1168        @Override
1169        public void handleMessage(Message msg) {
1170            final int type = msg.what;
1171            switch (type) {
1172                case MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER: {
1173                    AccessibilityEvent event = (AccessibilityEvent) msg.obj;
1174                    synchronized (mLock) {
1175                        if (mHasInputFilter && mInputFilter != null) {
1176                            mInputFilter.notifyAccessibilityEvent(event);
1177                        }
1178                    }
1179                    event.recycle();
1180                } break;
1181                case MSG_SEND_STATE_TO_CLIENTS: {
1182                    final int clientState = msg.arg1;
1183                    final int userId = msg.arg2;
1184                    sendStateToClients(clientState, mGlobalClients);
1185                    sendStateToClientsForUser(clientState, userId);
1186                } break;
1187                case MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER: {
1188                    final int userId = msg.arg1;
1189                    sendStateToClientsForUser(0, userId);
1190                } break;
1191                case MSG_SEND_RECREATE_INTERNAL_STATE: {
1192                    final int userId = msg.arg1;
1193                    synchronized (mLock) {
1194                        UserState userState = getUserStateLocked(userId);
1195                        recreateInternalStateLocked(userState);
1196                    }
1197                } break;
1198            }
1199        }
1200
1201        private void sendStateToClientsForUser(int clientState, int userId) {
1202            final UserState userState;
1203            synchronized (mLock) {
1204                userState = getUserStateLocked(userId);
1205            }
1206            sendStateToClients(clientState, userState.mClients);
1207        }
1208
1209        private void sendStateToClients(int clientState,
1210                RemoteCallbackList<IAccessibilityManagerClient> clients) {
1211            try {
1212                final int userClientCount = clients.beginBroadcast();
1213                for (int i = 0; i < userClientCount; i++) {
1214                    IAccessibilityManagerClient client = clients.getBroadcastItem(i);
1215                    try {
1216                        client.setState(clientState);
1217                    } catch (RemoteException re) {
1218                        /* ignore */
1219                    }
1220                }
1221            } finally {
1222                clients.finishBroadcast();
1223            }
1224        }
1225    }
1226
1227    /**
1228     * This class represents an accessibility service. It stores all per service
1229     * data required for the service management, provides API for starting/stopping the
1230     * service and is responsible for adding/removing the service in the data structures
1231     * for service management. The class also exposes configuration interface that is
1232     * passed to the service it represents as soon it is bound. It also serves as the
1233     * connection for the service.
1234     */
1235    class Service extends IAccessibilityServiceConnection.Stub
1236            implements ServiceConnection, DeathRecipient {
1237
1238        // We pick the MSB to avoid collision since accessibility event types are
1239        // used as message types allowing us to remove messages per event type.
1240        private static final int MSG_ON_GESTURE = 0x80000000;
1241
1242        final int mUserId;
1243
1244        int mId = 0;
1245
1246        AccessibilityServiceInfo mAccessibilityServiceInfo;
1247
1248        IBinder mService;
1249
1250        IAccessibilityServiceClient mServiceInterface;
1251
1252        int mEventTypes;
1253
1254        int mFeedbackType;
1255
1256        Set<String> mPackageNames = new HashSet<String>();
1257
1258        boolean mIsDefault;
1259
1260        boolean mRequestTouchExplorationMode;
1261
1262        boolean mIncludeNotImportantViews;
1263
1264        long mNotificationTimeout;
1265
1266        ComponentName mComponentName;
1267
1268        Intent mIntent;
1269
1270        boolean mCanRetrieveScreenContent;
1271
1272        boolean mIsAutomation;
1273
1274        final Rect mTempBounds = new Rect();
1275
1276        final ResolveInfo mResolveInfo;
1277
1278        // the events pending events to be dispatched to this service
1279        final SparseArray<AccessibilityEvent> mPendingEvents =
1280            new SparseArray<AccessibilityEvent>();
1281
1282        /**
1283         * Handler for delayed event dispatch.
1284         */
1285        public Handler mHandler = new Handler(mMainHandler.getLooper()) {
1286            @Override
1287            public void handleMessage(Message message) {
1288                final int type = message.what;
1289                switch (type) {
1290                    case MSG_ON_GESTURE: {
1291                        final int gestureId = message.arg1;
1292                        notifyGestureInternal(gestureId);
1293                    } break;
1294                    default: {
1295                        final int eventType = type;
1296                        notifyAccessibilityEventInternal(eventType);
1297                    } break;
1298                }
1299            }
1300        };
1301
1302        public Service(int userId, ComponentName componentName,
1303                AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation) {
1304            mUserId = userId;
1305            mResolveInfo = accessibilityServiceInfo.getResolveInfo();
1306            mId = sIdCounter++;
1307            mComponentName = componentName;
1308            mAccessibilityServiceInfo = accessibilityServiceInfo;
1309            mIsAutomation = isAutomation;
1310            if (!isAutomation) {
1311                mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent();
1312                mRequestTouchExplorationMode =
1313                    (accessibilityServiceInfo.flags
1314                            & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
1315                mIntent = new Intent().setComponent(mComponentName);
1316                mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
1317                        com.android.internal.R.string.accessibility_binding_label);
1318                mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
1319                        mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
1320            } else {
1321                mCanRetrieveScreenContent = true;
1322            }
1323            setDynamicallyConfigurableProperties(accessibilityServiceInfo);
1324        }
1325
1326        public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) {
1327            mEventTypes = info.eventTypes;
1328            mFeedbackType = info.feedbackType;
1329            String[] packageNames = info.packageNames;
1330            if (packageNames != null) {
1331                mPackageNames.addAll(Arrays.asList(packageNames));
1332            }
1333            mNotificationTimeout = info.notificationTimeout;
1334            mIsDefault = (info.flags & DEFAULT) != 0;
1335
1336            if (mIsAutomation || info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion
1337                    >= Build.VERSION_CODES.JELLY_BEAN) {
1338                mIncludeNotImportantViews =
1339                    (info.flags & FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0;
1340            }
1341
1342            mRequestTouchExplorationMode = (info.flags
1343                    & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
1344
1345            // If this service is up and running we may have to enable touch
1346            // exploration, otherwise this will happen when the service connects.
1347            synchronized (mLock) {
1348                if (isConfigured()) {
1349                    if (mRequestTouchExplorationMode) {
1350                        tryEnableTouchExplorationLocked(this);
1351                    } else {
1352                        tryDisableTouchExplorationLocked(this);
1353                    }
1354                }
1355            }
1356        }
1357
1358        /**
1359         * Binds to the accessibility service.
1360         *
1361         * @return True if binding is successful.
1362         */
1363        public boolean bind() {
1364            if (!mIsAutomation && mService == null) {
1365                return mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE, mUserId);
1366            }
1367            return false;
1368        }
1369
1370        /**
1371         * Unbinds form the accessibility service and removes it from the data
1372         * structures for service management.
1373         *
1374         * @return True if unbinding is successful.
1375         */
1376        public boolean unbind() {
1377            if (mService != null) {
1378                synchronized (mLock) {
1379                    tryRemoveServiceLocked(this);
1380                }
1381                if (!mIsAutomation) {
1382                    mContext.unbindService(this);
1383                }
1384                return true;
1385            }
1386            return false;
1387        }
1388
1389        /**
1390         * Returns if the service is configured i.e. at least event types of interest
1391         * and feedback type must be set.
1392         *
1393         * @return True if the service is configured, false otherwise.
1394         */
1395        public boolean isConfigured() {
1396            return (mEventTypes != 0 && mFeedbackType != 0 && mService != null);
1397        }
1398
1399        @Override
1400        public AccessibilityServiceInfo getServiceInfo() {
1401            synchronized (mLock) {
1402                return mAccessibilityServiceInfo;
1403            }
1404        }
1405
1406        @Override
1407        public void setServiceInfo(AccessibilityServiceInfo info) {
1408            final long identity = Binder.clearCallingIdentity();
1409            try {
1410                synchronized (mLock) {
1411                    // If the XML manifest had data to configure the service its info
1412                    // should be already set. In such a case update only the dynamically
1413                    // configurable properties.
1414                    AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
1415                    if (oldInfo != null) {
1416                        oldInfo.updateDynamicallyConfigurableProperties(info);
1417                        setDynamicallyConfigurableProperties(oldInfo);
1418                    } else {
1419                        setDynamicallyConfigurableProperties(info);
1420                    }
1421                }
1422            } finally {
1423                Binder.restoreCallingIdentity(identity);
1424            }
1425        }
1426
1427        @Override
1428        public void onServiceConnected(ComponentName componentName, IBinder service) {
1429            mService = service;
1430            mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
1431            try {
1432                mServiceInterface.setConnection(this, mId);
1433                synchronized (mLock) {
1434                    tryAddServiceLocked(this, mUserId);
1435                }
1436            } catch (RemoteException re) {
1437                Slog.w(LOG_TAG, "Error while setting Controller for service: " + service, re);
1438            }
1439        }
1440
1441        @Override
1442        public float findAccessibilityNodeInfoByViewId(int accessibilityWindowId,
1443                long accessibilityNodeId, int viewId, int interactionId,
1444                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1445                throws RemoteException {
1446            final int resolvedWindowId;
1447            IAccessibilityInteractionConnection connection = null;
1448            synchronized (mLock) {
1449                final int resolvedUserId = mSecurityPolicy
1450                        .resolveCallingUserIdEnforcingPermissionsLocked(
1451                                UserHandle.getCallingUserId());
1452                if (resolvedUserId != mCurrentUserId) {
1453                    return -1;
1454                }
1455                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1456                final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
1457                if (!permissionGranted) {
1458                    return 0;
1459                } else {
1460                    resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1461                    connection = getConnectionLocked(resolvedWindowId);
1462                    if (connection == null) {
1463                        return 0;
1464                    }
1465                }
1466            }
1467            final int flags = (mIncludeNotImportantViews) ?
1468                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1469            final int interrogatingPid = Binder.getCallingPid();
1470            final long identityToken = Binder.clearCallingIdentity();
1471            try {
1472                connection.findAccessibilityNodeInfoByViewId(accessibilityNodeId, viewId,
1473                        interactionId, callback, flags, interrogatingPid, interrogatingTid);
1474                return getCompatibilityScale(resolvedWindowId);
1475            } catch (RemoteException re) {
1476                if (DEBUG) {
1477                    Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
1478                }
1479            } finally {
1480                Binder.restoreCallingIdentity(identityToken);
1481            }
1482            return 0;
1483        }
1484
1485        @Override
1486        public float findAccessibilityNodeInfosByText(int accessibilityWindowId,
1487                long accessibilityNodeId, String text, int interactionId,
1488                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1489                throws RemoteException {
1490            final int resolvedWindowId;
1491            IAccessibilityInteractionConnection connection = null;
1492            synchronized (mLock) {
1493                final int resolvedUserId = mSecurityPolicy
1494                        .resolveCallingUserIdEnforcingPermissionsLocked(
1495                        UserHandle.getCallingUserId());
1496                if (resolvedUserId != mCurrentUserId) {
1497                    return -1;
1498                }
1499                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1500                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1501                final boolean permissionGranted =
1502                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1503                if (!permissionGranted) {
1504                    return 0;
1505                } else {
1506                    connection = getConnectionLocked(resolvedWindowId);
1507                    if (connection == null) {
1508                        return 0;
1509                    }
1510                }
1511            }
1512            final int flags = (mIncludeNotImportantViews) ?
1513                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1514            final int interrogatingPid = Binder.getCallingPid();
1515            final long identityToken = Binder.clearCallingIdentity();
1516            try {
1517                connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
1518                        interactionId, callback, flags, interrogatingPid,
1519                        interrogatingTid);
1520                return getCompatibilityScale(resolvedWindowId);
1521            } catch (RemoteException re) {
1522                if (DEBUG) {
1523                    Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
1524                }
1525            } finally {
1526                Binder.restoreCallingIdentity(identityToken);
1527            }
1528            return 0;
1529        }
1530
1531        @Override
1532        public float findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
1533                long accessibilityNodeId, int interactionId,
1534                IAccessibilityInteractionConnectionCallback callback, int flags,
1535                long interrogatingTid) throws RemoteException {
1536            final int resolvedWindowId;
1537            IAccessibilityInteractionConnection connection = null;
1538            synchronized (mLock) {
1539                final int resolvedUserId = mSecurityPolicy
1540                        .resolveCallingUserIdEnforcingPermissionsLocked(
1541                        UserHandle.getCallingUserId());
1542                if (resolvedUserId != mCurrentUserId) {
1543                    return -1;
1544                }
1545                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1546                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1547                final boolean permissionGranted =
1548                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1549                if (!permissionGranted) {
1550                    return 0;
1551                } else {
1552                    connection = getConnectionLocked(resolvedWindowId);
1553                    if (connection == null) {
1554                        return 0;
1555                    }
1556                }
1557            }
1558            final int allFlags = flags | ((mIncludeNotImportantViews) ?
1559                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0);
1560            final int interrogatingPid = Binder.getCallingPid();
1561            final long identityToken = Binder.clearCallingIdentity();
1562            try {
1563                connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
1564                        interactionId, callback, allFlags, interrogatingPid, interrogatingTid);
1565                return getCompatibilityScale(resolvedWindowId);
1566            } catch (RemoteException re) {
1567                if (DEBUG) {
1568                    Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
1569                }
1570            } finally {
1571                Binder.restoreCallingIdentity(identityToken);
1572            }
1573            return 0;
1574        }
1575
1576        @Override
1577        public float findFocus(int accessibilityWindowId, long accessibilityNodeId,
1578                int focusType, int interactionId,
1579                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1580                throws RemoteException {
1581            final int resolvedWindowId;
1582            IAccessibilityInteractionConnection connection = null;
1583            synchronized (mLock) {
1584                final int resolvedUserId = mSecurityPolicy
1585                        .resolveCallingUserIdEnforcingPermissionsLocked(
1586                        UserHandle.getCallingUserId());
1587                if (resolvedUserId != mCurrentUserId) {
1588                    return -1;
1589                }
1590                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1591                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1592                final boolean permissionGranted =
1593                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1594                if (!permissionGranted) {
1595                    return 0;
1596                } else {
1597                    connection = getConnectionLocked(resolvedWindowId);
1598                    if (connection == null) {
1599                        return 0;
1600                    }
1601                }
1602            }
1603            final int flags = (mIncludeNotImportantViews) ?
1604                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1605            final int interrogatingPid = Binder.getCallingPid();
1606            final long identityToken = Binder.clearCallingIdentity();
1607            try {
1608                connection.findFocus(accessibilityNodeId, focusType, interactionId, callback,
1609                        flags, interrogatingPid, interrogatingTid);
1610                return getCompatibilityScale(resolvedWindowId);
1611            } catch (RemoteException re) {
1612                if (DEBUG) {
1613                    Slog.e(LOG_TAG, "Error calling findAccessibilityFocus()");
1614                }
1615            } finally {
1616                Binder.restoreCallingIdentity(identityToken);
1617            }
1618            return 0;
1619        }
1620
1621        @Override
1622        public float focusSearch(int accessibilityWindowId, long accessibilityNodeId,
1623                int direction, int interactionId,
1624                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1625                throws RemoteException {
1626            final int resolvedWindowId;
1627            IAccessibilityInteractionConnection connection = null;
1628            synchronized (mLock) {
1629                final int resolvedUserId = mSecurityPolicy
1630                        .resolveCallingUserIdEnforcingPermissionsLocked(
1631                        UserHandle.getCallingUserId());
1632                if (resolvedUserId != mCurrentUserId) {
1633                    return -1;
1634                }
1635                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1636                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1637                final boolean permissionGranted =
1638                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1639                if (!permissionGranted) {
1640                    return 0;
1641                } else {
1642                    connection = getConnectionLocked(resolvedWindowId);
1643                    if (connection == null) {
1644                        return 0;
1645                    }
1646                }
1647            }
1648            final int flags = (mIncludeNotImportantViews) ?
1649                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1650            final int interrogatingPid = Binder.getCallingPid();
1651            final long identityToken = Binder.clearCallingIdentity();
1652            try {
1653                connection.focusSearch(accessibilityNodeId, direction, interactionId, callback,
1654                        flags, interrogatingPid, interrogatingTid);
1655                return getCompatibilityScale(resolvedWindowId);
1656            } catch (RemoteException re) {
1657                if (DEBUG) {
1658                    Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
1659                }
1660            } finally {
1661                Binder.restoreCallingIdentity(identityToken);
1662            }
1663            return 0;
1664        }
1665
1666        @Override
1667        public boolean performAccessibilityAction(int accessibilityWindowId,
1668                long accessibilityNodeId, int action, Bundle arguments, int interactionId,
1669                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1670                throws RemoteException {
1671            final int resolvedWindowId;
1672            IAccessibilityInteractionConnection connection = null;
1673            synchronized (mLock) {
1674                final int resolvedUserId = mSecurityPolicy
1675                        .resolveCallingUserIdEnforcingPermissionsLocked(
1676                        UserHandle.getCallingUserId());
1677                if (resolvedUserId != mCurrentUserId) {
1678                    return false;
1679                }
1680                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1681                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1682                final boolean permissionGranted = mSecurityPolicy.canPerformActionLocked(this,
1683                        resolvedWindowId, action, arguments);
1684                if (!permissionGranted) {
1685                    return false;
1686                } else {
1687                    connection = getConnectionLocked(resolvedWindowId);
1688                    if (connection == null) {
1689                        return false;
1690                    }
1691                }
1692            }
1693            final int flags = (mIncludeNotImportantViews) ?
1694                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1695            final int interrogatingPid = Binder.getCallingPid();
1696            final long identityToken = Binder.clearCallingIdentity();
1697            try {
1698                connection.performAccessibilityAction(accessibilityNodeId, action, arguments,
1699                        interactionId, callback, flags, interrogatingPid, interrogatingTid);
1700            } catch (RemoteException re) {
1701                if (DEBUG) {
1702                    Slog.e(LOG_TAG, "Error calling performAccessibilityAction()");
1703                }
1704            } finally {
1705                Binder.restoreCallingIdentity(identityToken);
1706            }
1707            return true;
1708        }
1709
1710        public boolean performGlobalAction(int action) {
1711            synchronized (mLock) {
1712                final int resolvedUserId = mSecurityPolicy
1713                        .resolveCallingUserIdEnforcingPermissionsLocked(
1714                        UserHandle.getCallingUserId());
1715                if (resolvedUserId != mCurrentUserId) {
1716                    return false;
1717                }
1718            }
1719            final long identity = Binder.clearCallingIdentity();
1720            try {
1721                switch (action) {
1722                    case AccessibilityService.GLOBAL_ACTION_BACK: {
1723                        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK);
1724                    } return true;
1725                    case AccessibilityService.GLOBAL_ACTION_HOME: {
1726                        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME);
1727                    } return true;
1728                    case AccessibilityService.GLOBAL_ACTION_RECENTS: {
1729                        openRecents();
1730                    } return true;
1731                    case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: {
1732                        expandNotifications();
1733                    } return true;
1734                    case AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS: {
1735                        expandQuickSettings();
1736                    } return true;
1737                }
1738                return false;
1739            } finally {
1740                Binder.restoreCallingIdentity(identity);
1741            }
1742        }
1743
1744        public void onServiceDisconnected(ComponentName componentName) {
1745            /* do nothing - #binderDied takes care */
1746        }
1747
1748        public void linkToOwnDeath() throws RemoteException {
1749            mService.linkToDeath(this, 0);
1750        }
1751
1752        public void unlinkToOwnDeath() {
1753            mService.unlinkToDeath(this, 0);
1754        }
1755
1756        public void dispose() {
1757            try {
1758                // Clear the proxy in the other process so this
1759                // IAccessibilityServiceConnection can be garbage collected.
1760                mServiceInterface.setConnection(null, mId);
1761            } catch (RemoteException re) {
1762                /* ignore */
1763            }
1764            mService = null;
1765            mServiceInterface = null;
1766        }
1767
1768        public void binderDied() {
1769            synchronized (mLock) {
1770                // The death recipient is unregistered in tryRemoveServiceLocked
1771                tryRemoveServiceLocked(this);
1772                // We no longer have an automation service, so restore
1773                // the state based on values in the settings database.
1774                if (mIsAutomation) {
1775                    mUiAutomationService = null;
1776                    recreateInternalStateLocked(getUserStateLocked(mUserId));
1777                }
1778            }
1779        }
1780
1781        /**
1782         * Performs a notification for an {@link AccessibilityEvent}.
1783         *
1784         * @param event The event.
1785         */
1786        public void notifyAccessibilityEvent(AccessibilityEvent event) {
1787            synchronized (mLock) {
1788                final int eventType = event.getEventType();
1789                // Make a copy since during dispatch it is possible the event to
1790                // be modified to remove its source if the receiving service does
1791                // not have permission to access the window content.
1792                AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
1793                AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
1794                mPendingEvents.put(eventType, newEvent);
1795
1796                final int what = eventType;
1797                if (oldEvent != null) {
1798                    mHandler.removeMessages(what);
1799                    oldEvent.recycle();
1800                }
1801
1802                Message message = mHandler.obtainMessage(what);
1803                mHandler.sendMessageDelayed(message, mNotificationTimeout);
1804            }
1805        }
1806
1807        /**
1808         * Notifies an accessibility service client for a scheduled event given the event type.
1809         *
1810         * @param eventType The type of the event to dispatch.
1811         */
1812        private void notifyAccessibilityEventInternal(int eventType) {
1813            IAccessibilityServiceClient listener;
1814            AccessibilityEvent event;
1815
1816            synchronized (mLock) {
1817                listener = mServiceInterface;
1818
1819                // If the service died/was disabled while the message for dispatching
1820                // the accessibility event was propagating the listener may be null.
1821                if (listener == null) {
1822                    return;
1823                }
1824
1825                event = mPendingEvents.get(eventType);
1826
1827                // Check for null here because there is a concurrent scenario in which this
1828                // happens: 1) A binder thread calls notifyAccessibilityServiceDelayedLocked
1829                // which posts a message for dispatching an event. 2) The message is pulled
1830                // from the queue by the handler on the service thread and the latter is
1831                // just about to acquire the lock and call this method. 3) Now another binder
1832                // thread acquires the lock calling notifyAccessibilityServiceDelayedLocked
1833                // so the service thread waits for the lock; 4) The binder thread replaces
1834                // the event with a more recent one (assume the same event type) and posts a
1835                // dispatch request releasing the lock. 5) Now the main thread is unblocked and
1836                // dispatches the event which is removed from the pending ones. 6) And ... now
1837                // the service thread handles the last message posted by the last binder call
1838                // but the event is already dispatched and hence looking it up in the pending
1839                // ones yields null. This check is much simpler that keeping count for each
1840                // event type of each service to catch such a scenario since only one message
1841                // is processed at a time.
1842                if (event == null) {
1843                    return;
1844                }
1845
1846                mPendingEvents.remove(eventType);
1847                if (mSecurityPolicy.canRetrieveWindowContent(this)) {
1848                    event.setConnectionId(mId);
1849                } else {
1850                    event.setSource(null);
1851                }
1852                event.setSealed(true);
1853            }
1854
1855            try {
1856                listener.onAccessibilityEvent(event);
1857                if (DEBUG) {
1858                    Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
1859                }
1860            } catch (RemoteException re) {
1861                Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re);
1862            } finally {
1863                event.recycle();
1864            }
1865        }
1866
1867        public void notifyGesture(int gestureId) {
1868            mHandler.obtainMessage(MSG_ON_GESTURE, gestureId, 0).sendToTarget();
1869        }
1870
1871        private void notifyGestureInternal(int gestureId) {
1872            IAccessibilityServiceClient listener = mServiceInterface;
1873            if (listener != null) {
1874                try {
1875                    listener.onGesture(gestureId);
1876                } catch (RemoteException re) {
1877                    Slog.e(LOG_TAG, "Error during sending gesture " + gestureId
1878                            + " to " + mService, re);
1879                }
1880            }
1881        }
1882
1883        private void sendDownAndUpKeyEvents(int keyCode) {
1884            final long token = Binder.clearCallingIdentity();
1885
1886            // Inject down.
1887            final long downTime = SystemClock.uptimeMillis();
1888            KeyEvent down = KeyEvent.obtain(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
1889                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
1890                    InputDevice.SOURCE_KEYBOARD, null);
1891            InputManager.getInstance().injectInputEvent(down,
1892                    InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
1893            down.recycle();
1894
1895            // Inject up.
1896            final long upTime = SystemClock.uptimeMillis();
1897            KeyEvent up = KeyEvent.obtain(downTime, upTime, KeyEvent.ACTION_UP, keyCode, 0, 0,
1898                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
1899                    InputDevice.SOURCE_KEYBOARD, null);
1900            InputManager.getInstance().injectInputEvent(up,
1901                    InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
1902            up.recycle();
1903
1904            Binder.restoreCallingIdentity(token);
1905        }
1906
1907        private void expandNotifications() {
1908            final long token = Binder.clearCallingIdentity();
1909
1910            StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
1911                    android.app.Service.STATUS_BAR_SERVICE);
1912            statusBarManager.expandNotifications();
1913
1914            Binder.restoreCallingIdentity(token);
1915        }
1916
1917        private void expandQuickSettings() {
1918            final long token = Binder.clearCallingIdentity();
1919
1920            StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
1921                    android.app.Service.STATUS_BAR_SERVICE);
1922            statusBarManager.expandQuickSettings();
1923
1924            Binder.restoreCallingIdentity(token);
1925        }
1926
1927        private void openRecents() {
1928            final long token = Binder.clearCallingIdentity();
1929
1930            IStatusBarService statusBarService = IStatusBarService.Stub.asInterface(
1931                    ServiceManager.getService("statusbar"));
1932            try {
1933                statusBarService.toggleRecentApps();
1934            } catch (RemoteException e) {
1935                Slog.e(LOG_TAG, "Error toggling recent apps.");
1936            }
1937
1938            Binder.restoreCallingIdentity(token);
1939        }
1940
1941        private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
1942            if (DEBUG) {
1943                Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
1944            }
1945            AccessibilityConnectionWrapper wrapper = mGlobalInteractionConnections.get(windowId);
1946            if (wrapper == null) {
1947                wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId);
1948            }
1949            if (wrapper != null && wrapper.mConnection != null) {
1950                return wrapper.mConnection;
1951            }
1952            if (DEBUG) {
1953                Slog.e(LOG_TAG, "No interaction connection to window: " + windowId);
1954            }
1955            return null;
1956        }
1957
1958        private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) {
1959            if (accessibilityWindowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) {
1960                return mSecurityPolicy.mActiveWindowId;
1961            }
1962            return accessibilityWindowId;
1963        }
1964
1965        private float getCompatibilityScale(int windowId) {
1966            try {
1967                IBinder windowToken = mGlobalWindowTokens.get(windowId);
1968                if (windowToken != null) {
1969                    return mWindowManagerService.getWindowCompatibilityScale(windowToken);
1970                }
1971                windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
1972                if (windowToken != null) {
1973                    return mWindowManagerService.getWindowCompatibilityScale(windowToken);
1974                }
1975            } catch (RemoteException re) {
1976                /* ignore */
1977            }
1978            return 1.0f;
1979        }
1980    }
1981
1982    final class SecurityPolicy {
1983        private static final int VALID_ACTIONS =
1984            AccessibilityNodeInfo.ACTION_CLICK
1985            | AccessibilityNodeInfo.ACTION_LONG_CLICK
1986            | AccessibilityNodeInfo.ACTION_FOCUS
1987            | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS
1988            | AccessibilityNodeInfo.ACTION_SELECT
1989            | AccessibilityNodeInfo.ACTION_CLEAR_SELECTION
1990            | AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS
1991            | AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS
1992            | AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1993            | AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1994            | AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT
1995            | AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT
1996            | AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
1997            | AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD;
1998
1999        private static final int RETRIEVAL_ALLOWING_EVENT_TYPES =
2000            AccessibilityEvent.TYPE_VIEW_CLICKED
2001            | AccessibilityEvent.TYPE_VIEW_FOCUSED
2002            | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
2003            | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
2004            | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED
2005            | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
2006            | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
2007            | AccessibilityEvent.TYPE_VIEW_SELECTED
2008            | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
2009            | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
2010            | AccessibilityEvent.TYPE_VIEW_SCROLLED
2011            | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
2012            | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED;
2013
2014        private int mActiveWindowId;
2015
2016        private boolean canDispatchAccessibilityEvent(AccessibilityEvent event) {
2017            // Send window changed event only for the retrieval allowing window.
2018            return (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
2019                    || event.getWindowId() == mActiveWindowId);
2020        }
2021
2022        public void updateActiveWindowAndEventSourceLocked(AccessibilityEvent event) {
2023            // The active window is either the window that has input focus or
2024            // the window that the user is currently touching. If the user is
2025            // touching a window that does not have input focus as soon as the
2026            // the user stops touching that window the focused window becomes
2027            // the active one.
2028            final int windowId = event.getWindowId();
2029            final int eventType = event.getEventType();
2030            switch (eventType) {
2031                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
2032                    if (getFocusedWindowId() == windowId) {
2033                        mActiveWindowId = windowId;
2034                    }
2035                } break;
2036                case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
2037                case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
2038                    mActiveWindowId = windowId;
2039                } break;
2040                case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END: {
2041                    mActiveWindowId = getFocusedWindowId();
2042                } break;
2043            }
2044            if ((eventType & RETRIEVAL_ALLOWING_EVENT_TYPES) == 0) {
2045                event.setSource(null);
2046            }
2047        }
2048
2049        public int getRetrievalAllowingWindowLocked() {
2050            return mActiveWindowId;
2051        }
2052
2053        public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) {
2054            return canRetrieveWindowContent(service) && isRetrievalAllowingWindow(windowId);
2055        }
2056
2057        public boolean canPerformActionLocked(Service service, int windowId, int action,
2058                Bundle arguments) {
2059            return canRetrieveWindowContent(service)
2060                && isRetrievalAllowingWindow(windowId)
2061                && isActionPermitted(action);
2062        }
2063
2064        public boolean canRetrieveWindowContent(Service service) {
2065            return service.mCanRetrieveScreenContent;
2066        }
2067
2068        public void enforceCanRetrieveWindowContent(Service service) throws RemoteException {
2069            // This happens due to incorrect registration so make it apparent.
2070            if (!canRetrieveWindowContent(service)) {
2071                Slog.e(LOG_TAG, "Accessibility serivce " + service.mComponentName + " does not " +
2072                        "declare android:canRetrieveWindowContent.");
2073                throw new RemoteException();
2074            }
2075        }
2076
2077        public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) {
2078            final int callingUid = Binder.getCallingUid();
2079            if (callingUid == Process.SYSTEM_UID
2080                    || callingUid == Process.SHELL_UID) {
2081                return mCurrentUserId;
2082            }
2083            final int callingUserId = UserHandle.getUserId(callingUid);
2084            if (callingUserId == userId) {
2085                return userId;
2086            }
2087            if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS)
2088                    && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) {
2089                throw new SecurityException("Call from user " + callingUserId + " as user "
2090                        + userId + " without permission INTERACT_ACROSS_USERS or "
2091                        + "INTERACT_ACROSS_USERS_FULL not allowed.");
2092            }
2093            if (userId == UserHandle.USER_CURRENT
2094                    || userId == UserHandle.USER_CURRENT_OR_SELF) {
2095                return mCurrentUserId;
2096            }
2097            throw new IllegalArgumentException("Calling user can be changed to only "
2098                    + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
2099        }
2100
2101        public boolean isCallerInteractingAcrossUsers(int userId) {
2102            final int callingUid = Binder.getCallingUid();
2103            return (callingUid == Process.SYSTEM_UID
2104                    || callingUid == Process.SHELL_UID
2105                    || userId == UserHandle.USER_CURRENT
2106                    || userId == UserHandle.USER_CURRENT_OR_SELF);
2107        }
2108
2109        private boolean isRetrievalAllowingWindow(int windowId) {
2110            return (mActiveWindowId == windowId);
2111        }
2112
2113        private boolean isActionPermitted(int action) {
2114             return (VALID_ACTIONS & action) != 0;
2115        }
2116
2117        private void enforceCallingPermission(String permission, String function) {
2118            if (OWN_PROCESS_ID == Binder.getCallingPid()) {
2119                return;
2120            }
2121            if (!hasPermission(permission)) {
2122                throw new SecurityException("You do not have " + permission
2123                        + " required to call " + function);
2124            }
2125        }
2126
2127        private boolean hasPermission(String permission) {
2128            return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
2129        }
2130
2131        private int getFocusedWindowId() {
2132            final long identity = Binder.clearCallingIdentity();
2133            try {
2134                // We call this only on window focus change or after touch
2135                // exploration gesture end and the shown windows are not that
2136                // many, so the linear look up is just fine.
2137                IBinder token = mWindowManagerService.getFocusedWindowToken();
2138                if (token != null) {
2139                    SparseArray<IBinder> windows = getCurrentUserStateLocked().mWindowTokens;
2140                    final int windowCount = windows.size();
2141                    for (int i = 0; i < windowCount; i++) {
2142                        if (windows.valueAt(i) == token) {
2143                            return windows.keyAt(i);
2144                        }
2145                    }
2146                }
2147            } catch (RemoteException re) {
2148                /* ignore */
2149            } finally {
2150                Binder.restoreCallingIdentity(identity);
2151            }
2152            return -1;
2153        }
2154    }
2155
2156    private class UserState {
2157        public final int mUserId;
2158
2159        public final CopyOnWriteArrayList<Service> mServices = new CopyOnWriteArrayList<Service>();
2160
2161        public final RemoteCallbackList<IAccessibilityManagerClient> mClients =
2162            new RemoteCallbackList<IAccessibilityManagerClient>();
2163
2164        public final Map<ComponentName, Service> mComponentNameToServiceMap =
2165                new HashMap<ComponentName, Service>();
2166
2167        public final List<AccessibilityServiceInfo> mInstalledServices =
2168                new ArrayList<AccessibilityServiceInfo>();
2169
2170        public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
2171
2172        public final Set<ComponentName> mTouchExplorationGrantedServices =
2173                new HashSet<ComponentName>();
2174
2175        public final SparseArray<AccessibilityConnectionWrapper>
2176                mInteractionConnections =
2177                new SparseArray<AccessibilityConnectionWrapper>();
2178
2179        public final SparseArray<IBinder> mWindowTokens = new SparseArray<IBinder>();
2180
2181        public int mHandledFeedbackTypes = 0;
2182
2183        public boolean mIsAccessibilityEnabled;
2184        public boolean mIsTouchExplorationEnabled;
2185        public boolean mIsDisplayMagnificationEnabled;
2186
2187        public UserState(int userId) {
2188            mUserId = userId;
2189        }
2190    }
2191
2192    private final class AccessibilityContentObserver extends ContentObserver {
2193
2194        private final Uri mAccessibilityEnabledUri = Settings.Secure.getUriFor(
2195                Settings.Secure.ACCESSIBILITY_ENABLED);
2196
2197        private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor(
2198                Settings.Secure.TOUCH_EXPLORATION_ENABLED);
2199
2200        private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor(
2201                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
2202
2203        private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor(
2204                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
2205
2206        private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
2207                .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
2208
2209        public AccessibilityContentObserver(Handler handler) {
2210            super(handler);
2211        }
2212
2213        public void register(ContentResolver contentResolver) {
2214            contentResolver.registerContentObserver(mAccessibilityEnabledUri,
2215                    false, this, UserHandle.USER_ALL);
2216            contentResolver.registerContentObserver(mTouchExplorationEnabledUri,
2217                    false, this, UserHandle.USER_ALL);
2218            contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri,
2219                    false, this, UserHandle.USER_ALL);
2220            contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri,
2221                    false, this, UserHandle.USER_ALL);
2222            contentResolver.registerContentObserver(
2223                    mTouchExplorationGrantedAccessibilityServicesUri,
2224                    false, this, UserHandle.USER_ALL);
2225        }
2226
2227        @Override
2228        public void onChange(boolean selfChange, Uri uri) {
2229            if (mAccessibilityEnabledUri.equals(uri)) {
2230                synchronized (mLock) {
2231                    // We will update when the automation service dies.
2232                    if (mUiAutomationService == null) {
2233                        UserState userState = getCurrentUserStateLocked();
2234                        handleAccessibilityEnabledSettingChangedLocked(userState);
2235                        updateInputFilterLocked(userState);
2236                        scheduleSendStateToClientsLocked(userState);
2237                    }
2238                }
2239            } else if (mTouchExplorationEnabledUri.equals(uri)) {
2240                synchronized (mLock) {
2241                    // We will update when the automation service dies.
2242                    if (mUiAutomationService == null) {
2243                        UserState userState = getCurrentUserStateLocked();
2244                        handleTouchExplorationEnabledSettingChangedLocked(userState);
2245                        updateInputFilterLocked(userState);
2246                        scheduleSendStateToClientsLocked(userState);
2247                    }
2248                }
2249            } else if (mDisplayMagnificationEnabledUri.equals(uri)) {
2250                synchronized (mLock) {
2251                    // We will update when the automation service dies.
2252                    if (mUiAutomationService == null) {
2253                        UserState userState = getCurrentUserStateLocked();
2254                        handleDisplayMagnificationEnabledSettingChangedLocked(userState);
2255                        updateInputFilterLocked(userState);
2256                        scheduleSendStateToClientsLocked(userState);
2257                    }
2258                }
2259            } else if (mEnabledAccessibilityServicesUri.equals(uri)) {
2260                synchronized (mLock) {
2261                    // We will update when the automation service dies.
2262                    if (mUiAutomationService == null) {
2263                        UserState userState = getCurrentUserStateLocked();
2264                        populateEnabledAccessibilityServicesLocked(userState);
2265                        manageServicesLocked(userState);
2266                    }
2267                }
2268            } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
2269                synchronized (mLock) {
2270                    // We will update when the automation service dies.
2271                    if (mUiAutomationService == null) {
2272                        UserState userState = getCurrentUserStateLocked();
2273                        populateTouchExplorationGrantedAccessibilityServicesLocked(userState);
2274                        handleTouchExplorationGrantedAccessibilityServicesChangedLocked(userState);
2275                    }
2276                }
2277            }
2278        }
2279    }
2280}
2281