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