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                    event.setWindowId(mSecurityPolicy.getRetrievalAllowingWindowLocked());
1355                    sendAccessibilityEvent(event, mCurrentUserId);
1356                }
1357            }
1358        }
1359
1360        private void sendStateToClientsForUser(int clientState, int userId) {
1361            final UserState userState;
1362            synchronized (mLock) {
1363                userState = getUserStateLocked(userId);
1364            }
1365            sendStateToClients(clientState, userState.mClients);
1366        }
1367
1368        private void sendStateToClients(int clientState,
1369                RemoteCallbackList<IAccessibilityManagerClient> clients) {
1370            try {
1371                final int userClientCount = clients.beginBroadcast();
1372                for (int i = 0; i < userClientCount; i++) {
1373                    IAccessibilityManagerClient client = clients.getBroadcastItem(i);
1374                    try {
1375                        client.setState(clientState);
1376                    } catch (RemoteException re) {
1377                        /* ignore */
1378                    }
1379                }
1380            } finally {
1381                clients.finishBroadcast();
1382            }
1383        }
1384    }
1385
1386    /**
1387     * This class represents an accessibility service. It stores all per service
1388     * data required for the service management, provides API for starting/stopping the
1389     * service and is responsible for adding/removing the service in the data structures
1390     * for service management. The class also exposes configuration interface that is
1391     * passed to the service it represents as soon it is bound. It also serves as the
1392     * connection for the service.
1393     */
1394    class Service extends IAccessibilityServiceConnection.Stub
1395            implements ServiceConnection, DeathRecipient {
1396
1397        // We pick the MSB to avoid collision since accessibility event types are
1398        // used as message types allowing us to remove messages per event type.
1399        private static final int MSG_ON_GESTURE = 0x80000000;
1400
1401        final int mUserId;
1402
1403        int mId = 0;
1404
1405        AccessibilityServiceInfo mAccessibilityServiceInfo;
1406
1407        IBinder mService;
1408
1409        IAccessibilityServiceClient mServiceInterface;
1410
1411        int mEventTypes;
1412
1413        int mFeedbackType;
1414
1415        Set<String> mPackageNames = new HashSet<String>();
1416
1417        boolean mIsDefault;
1418
1419        boolean mRequestTouchExplorationMode;
1420
1421        boolean mIncludeNotImportantViews;
1422
1423        long mNotificationTimeout;
1424
1425        ComponentName mComponentName;
1426
1427        Intent mIntent;
1428
1429        boolean mCanRetrieveScreenContent;
1430
1431        boolean mIsAutomation;
1432
1433        final Rect mTempBounds = new Rect();
1434
1435        final ResolveInfo mResolveInfo;
1436
1437        // the events pending events to be dispatched to this service
1438        final SparseArray<AccessibilityEvent> mPendingEvents =
1439            new SparseArray<AccessibilityEvent>();
1440
1441        /**
1442         * Handler for delayed event dispatch.
1443         */
1444        public Handler mHandler = new Handler(mMainHandler.getLooper()) {
1445            @Override
1446            public void handleMessage(Message message) {
1447                final int type = message.what;
1448                switch (type) {
1449                    case MSG_ON_GESTURE: {
1450                        final int gestureId = message.arg1;
1451                        notifyGestureInternal(gestureId);
1452                    } break;
1453                    default: {
1454                        final int eventType = type;
1455                        notifyAccessibilityEventInternal(eventType);
1456                    } break;
1457                }
1458            }
1459        };
1460
1461        public Service(int userId, ComponentName componentName,
1462                AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation) {
1463            mUserId = userId;
1464            mResolveInfo = accessibilityServiceInfo.getResolveInfo();
1465            mId = sIdCounter++;
1466            mComponentName = componentName;
1467            mAccessibilityServiceInfo = accessibilityServiceInfo;
1468            mIsAutomation = isAutomation;
1469            if (!isAutomation) {
1470                mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent();
1471                mRequestTouchExplorationMode =
1472                    (accessibilityServiceInfo.flags
1473                            & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
1474                mIntent = new Intent().setComponent(mComponentName);
1475                mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
1476                        com.android.internal.R.string.accessibility_binding_label);
1477                mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
1478                        mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
1479            } else {
1480                mCanRetrieveScreenContent = true;
1481            }
1482            setDynamicallyConfigurableProperties(accessibilityServiceInfo);
1483        }
1484
1485        public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) {
1486            mEventTypes = info.eventTypes;
1487            mFeedbackType = info.feedbackType;
1488            String[] packageNames = info.packageNames;
1489            if (packageNames != null) {
1490                mPackageNames.addAll(Arrays.asList(packageNames));
1491            }
1492            mNotificationTimeout = info.notificationTimeout;
1493            mIsDefault = (info.flags & DEFAULT) != 0;
1494
1495            if (mIsAutomation || info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion
1496                    >= Build.VERSION_CODES.JELLY_BEAN) {
1497                mIncludeNotImportantViews =
1498                    (info.flags & FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0;
1499            }
1500
1501            mRequestTouchExplorationMode = (info.flags
1502                    & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
1503
1504            // If this service is up and running we may have to enable touch
1505            // exploration, otherwise this will happen when the service connects.
1506            synchronized (mLock) {
1507                if (canReceiveEvents()) {
1508                    if (mRequestTouchExplorationMode) {
1509                        tryEnableTouchExplorationLocked(this);
1510                    } else {
1511                        tryDisableTouchExplorationLocked(this);
1512                    }
1513                }
1514            }
1515        }
1516
1517        /**
1518         * Binds to the accessibility service.
1519         *
1520         * @return True if binding is successful.
1521         */
1522        public boolean bind() {
1523            if (!mIsAutomation && mService == null) {
1524                return mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE, mUserId);
1525            }
1526            return false;
1527        }
1528
1529        /**
1530         * Unbinds form the accessibility service and removes it from the data
1531         * structures for service management.
1532         *
1533         * @return True if unbinding is successful.
1534         */
1535        public boolean unbind() {
1536            if (mService != null) {
1537                synchronized (mLock) {
1538                    tryRemoveServiceLocked(this);
1539                }
1540                if (!mIsAutomation) {
1541                    mContext.unbindService(this);
1542                }
1543                return true;
1544            }
1545            return false;
1546        }
1547
1548        public boolean canReceiveEvents() {
1549            return (mEventTypes != 0 && mFeedbackType != 0 && mService != null);
1550        }
1551
1552        @Override
1553        public AccessibilityServiceInfo getServiceInfo() {
1554            synchronized (mLock) {
1555                return mAccessibilityServiceInfo;
1556            }
1557        }
1558
1559        @Override
1560        public void setServiceInfo(AccessibilityServiceInfo info) {
1561            final long identity = Binder.clearCallingIdentity();
1562            try {
1563                synchronized (mLock) {
1564                    // If the XML manifest had data to configure the service its info
1565                    // should be already set. In such a case update only the dynamically
1566                    // configurable properties.
1567                    AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
1568                    if (oldInfo != null) {
1569                        oldInfo.updateDynamicallyConfigurableProperties(info);
1570                        setDynamicallyConfigurableProperties(oldInfo);
1571                    } else {
1572                        setDynamicallyConfigurableProperties(info);
1573                    }
1574                }
1575            } finally {
1576                Binder.restoreCallingIdentity(identity);
1577            }
1578        }
1579
1580        @Override
1581        public void onServiceConnected(ComponentName componentName, IBinder service) {
1582            mService = service;
1583            mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
1584            try {
1585                mServiceInterface.setConnection(this, mId);
1586                synchronized (mLock) {
1587                    tryAddServiceLocked(this, mUserId);
1588                }
1589            } catch (RemoteException re) {
1590                Slog.w(LOG_TAG, "Error while setting Controller for service: " + service, re);
1591            }
1592        }
1593
1594        @Override
1595        public float findAccessibilityNodeInfoByViewId(int accessibilityWindowId,
1596                long accessibilityNodeId, int viewId, int interactionId,
1597                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1598                throws RemoteException {
1599            final int resolvedWindowId;
1600            IAccessibilityInteractionConnection connection = null;
1601            synchronized (mLock) {
1602                final int resolvedUserId = mSecurityPolicy
1603                        .resolveCallingUserIdEnforcingPermissionsLocked(
1604                                UserHandle.getCallingUserId());
1605                if (resolvedUserId != mCurrentUserId) {
1606                    return -1;
1607                }
1608                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1609                final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
1610                if (!permissionGranted) {
1611                    return 0;
1612                } else {
1613                    resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1614                    connection = getConnectionLocked(resolvedWindowId);
1615                    if (connection == null) {
1616                        return 0;
1617                    }
1618                }
1619            }
1620            final int flags = (mIncludeNotImportantViews) ?
1621                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1622            final int interrogatingPid = Binder.getCallingPid();
1623            final long identityToken = Binder.clearCallingIdentity();
1624            try {
1625                connection.findAccessibilityNodeInfoByViewId(accessibilityNodeId, viewId,
1626                        interactionId, callback, flags, interrogatingPid, interrogatingTid);
1627                return getCompatibilityScale(resolvedWindowId);
1628            } catch (RemoteException re) {
1629                if (DEBUG) {
1630                    Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
1631                }
1632            } finally {
1633                Binder.restoreCallingIdentity(identityToken);
1634            }
1635            return 0;
1636        }
1637
1638        @Override
1639        public float findAccessibilityNodeInfosByText(int accessibilityWindowId,
1640                long accessibilityNodeId, String text, int interactionId,
1641                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1642                throws RemoteException {
1643            final int resolvedWindowId;
1644            IAccessibilityInteractionConnection connection = null;
1645            synchronized (mLock) {
1646                final int resolvedUserId = mSecurityPolicy
1647                        .resolveCallingUserIdEnforcingPermissionsLocked(
1648                        UserHandle.getCallingUserId());
1649                if (resolvedUserId != mCurrentUserId) {
1650                    return -1;
1651                }
1652                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1653                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1654                final boolean permissionGranted =
1655                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1656                if (!permissionGranted) {
1657                    return 0;
1658                } else {
1659                    connection = getConnectionLocked(resolvedWindowId);
1660                    if (connection == null) {
1661                        return 0;
1662                    }
1663                }
1664            }
1665            final int flags = (mIncludeNotImportantViews) ?
1666                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1667            final int interrogatingPid = Binder.getCallingPid();
1668            final long identityToken = Binder.clearCallingIdentity();
1669            try {
1670                connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
1671                        interactionId, callback, flags, interrogatingPid,
1672                        interrogatingTid);
1673                return getCompatibilityScale(resolvedWindowId);
1674            } catch (RemoteException re) {
1675                if (DEBUG) {
1676                    Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
1677                }
1678            } finally {
1679                Binder.restoreCallingIdentity(identityToken);
1680            }
1681            return 0;
1682        }
1683
1684        @Override
1685        public float findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
1686                long accessibilityNodeId, int interactionId,
1687                IAccessibilityInteractionConnectionCallback callback, int flags,
1688                long interrogatingTid) throws RemoteException {
1689            final int resolvedWindowId;
1690            IAccessibilityInteractionConnection connection = null;
1691            synchronized (mLock) {
1692                final int resolvedUserId = mSecurityPolicy
1693                        .resolveCallingUserIdEnforcingPermissionsLocked(
1694                        UserHandle.getCallingUserId());
1695                if (resolvedUserId != mCurrentUserId) {
1696                    return -1;
1697                }
1698                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1699                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1700                final boolean permissionGranted =
1701                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1702                if (!permissionGranted) {
1703                    return 0;
1704                } else {
1705                    connection = getConnectionLocked(resolvedWindowId);
1706                    if (connection == null) {
1707                        return 0;
1708                    }
1709                }
1710            }
1711            final int allFlags = flags | ((mIncludeNotImportantViews) ?
1712                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0);
1713            final int interrogatingPid = Binder.getCallingPid();
1714            final long identityToken = Binder.clearCallingIdentity();
1715            try {
1716                connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
1717                        interactionId, callback, allFlags, interrogatingPid, interrogatingTid);
1718                return getCompatibilityScale(resolvedWindowId);
1719            } catch (RemoteException re) {
1720                if (DEBUG) {
1721                    Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
1722                }
1723            } finally {
1724                Binder.restoreCallingIdentity(identityToken);
1725            }
1726            return 0;
1727        }
1728
1729        @Override
1730        public float findFocus(int accessibilityWindowId, long accessibilityNodeId,
1731                int focusType, int interactionId,
1732                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1733                throws RemoteException {
1734            final int resolvedWindowId;
1735            IAccessibilityInteractionConnection connection = null;
1736            synchronized (mLock) {
1737                final int resolvedUserId = mSecurityPolicy
1738                        .resolveCallingUserIdEnforcingPermissionsLocked(
1739                        UserHandle.getCallingUserId());
1740                if (resolvedUserId != mCurrentUserId) {
1741                    return -1;
1742                }
1743                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1744                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1745                final boolean permissionGranted =
1746                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1747                if (!permissionGranted) {
1748                    return 0;
1749                } else {
1750                    connection = getConnectionLocked(resolvedWindowId);
1751                    if (connection == null) {
1752                        return 0;
1753                    }
1754                }
1755            }
1756            final int flags = (mIncludeNotImportantViews) ?
1757                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1758            final int interrogatingPid = Binder.getCallingPid();
1759            final long identityToken = Binder.clearCallingIdentity();
1760            try {
1761                connection.findFocus(accessibilityNodeId, focusType, interactionId, callback,
1762                        flags, interrogatingPid, interrogatingTid);
1763                return getCompatibilityScale(resolvedWindowId);
1764            } catch (RemoteException re) {
1765                if (DEBUG) {
1766                    Slog.e(LOG_TAG, "Error calling findAccessibilityFocus()");
1767                }
1768            } finally {
1769                Binder.restoreCallingIdentity(identityToken);
1770            }
1771            return 0;
1772        }
1773
1774        @Override
1775        public float focusSearch(int accessibilityWindowId, long accessibilityNodeId,
1776                int direction, int interactionId,
1777                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1778                throws RemoteException {
1779            final int resolvedWindowId;
1780            IAccessibilityInteractionConnection connection = null;
1781            synchronized (mLock) {
1782                final int resolvedUserId = mSecurityPolicy
1783                        .resolveCallingUserIdEnforcingPermissionsLocked(
1784                        UserHandle.getCallingUserId());
1785                if (resolvedUserId != mCurrentUserId) {
1786                    return -1;
1787                }
1788                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1789                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1790                final boolean permissionGranted =
1791                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1792                if (!permissionGranted) {
1793                    return 0;
1794                } else {
1795                    connection = getConnectionLocked(resolvedWindowId);
1796                    if (connection == null) {
1797                        return 0;
1798                    }
1799                }
1800            }
1801            final int flags = (mIncludeNotImportantViews) ?
1802                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1803            final int interrogatingPid = Binder.getCallingPid();
1804            final long identityToken = Binder.clearCallingIdentity();
1805            try {
1806                connection.focusSearch(accessibilityNodeId, direction, interactionId, callback,
1807                        flags, interrogatingPid, interrogatingTid);
1808                return getCompatibilityScale(resolvedWindowId);
1809            } catch (RemoteException re) {
1810                if (DEBUG) {
1811                    Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
1812                }
1813            } finally {
1814                Binder.restoreCallingIdentity(identityToken);
1815            }
1816            return 0;
1817        }
1818
1819        @Override
1820        public boolean performAccessibilityAction(int accessibilityWindowId,
1821                long accessibilityNodeId, int action, Bundle arguments, int interactionId,
1822                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1823                throws RemoteException {
1824            final int resolvedWindowId;
1825            IAccessibilityInteractionConnection connection = null;
1826            synchronized (mLock) {
1827                final int resolvedUserId = mSecurityPolicy
1828                        .resolveCallingUserIdEnforcingPermissionsLocked(
1829                        UserHandle.getCallingUserId());
1830                if (resolvedUserId != mCurrentUserId) {
1831                    return false;
1832                }
1833                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1834                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1835                final boolean permissionGranted = mSecurityPolicy.canPerformActionLocked(this,
1836                        resolvedWindowId, action, arguments);
1837                if (!permissionGranted) {
1838                    return false;
1839                } else {
1840                    connection = getConnectionLocked(resolvedWindowId);
1841                    if (connection == null) {
1842                        return false;
1843                    }
1844                }
1845            }
1846            final int flags = (mIncludeNotImportantViews) ?
1847                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1848            final int interrogatingPid = Binder.getCallingPid();
1849            final long identityToken = Binder.clearCallingIdentity();
1850            try {
1851                connection.performAccessibilityAction(accessibilityNodeId, action, arguments,
1852                        interactionId, callback, flags, interrogatingPid, interrogatingTid);
1853            } catch (RemoteException re) {
1854                if (DEBUG) {
1855                    Slog.e(LOG_TAG, "Error calling performAccessibilityAction()");
1856                }
1857            } finally {
1858                Binder.restoreCallingIdentity(identityToken);
1859            }
1860            return true;
1861        }
1862
1863        public boolean performGlobalAction(int action) {
1864            synchronized (mLock) {
1865                final int resolvedUserId = mSecurityPolicy
1866                        .resolveCallingUserIdEnforcingPermissionsLocked(
1867                        UserHandle.getCallingUserId());
1868                if (resolvedUserId != mCurrentUserId) {
1869                    return false;
1870                }
1871            }
1872            final long identity = Binder.clearCallingIdentity();
1873            try {
1874                switch (action) {
1875                    case AccessibilityService.GLOBAL_ACTION_BACK: {
1876                        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK);
1877                    } return true;
1878                    case AccessibilityService.GLOBAL_ACTION_HOME: {
1879                        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME);
1880                    } return true;
1881                    case AccessibilityService.GLOBAL_ACTION_RECENTS: {
1882                        openRecents();
1883                    } return true;
1884                    case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: {
1885                        expandNotifications();
1886                    } return true;
1887                    case AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS: {
1888                        expandQuickSettings();
1889                    } return true;
1890                }
1891                return false;
1892            } finally {
1893                Binder.restoreCallingIdentity(identity);
1894            }
1895        }
1896
1897        public void onServiceDisconnected(ComponentName componentName) {
1898            /* do nothing - #binderDied takes care */
1899        }
1900
1901        public void linkToOwnDeath() throws RemoteException {
1902            mService.linkToDeath(this, 0);
1903        }
1904
1905        public void unlinkToOwnDeath() {
1906            mService.unlinkToDeath(this, 0);
1907        }
1908
1909        public void dispose() {
1910            try {
1911                // Clear the proxy in the other process so this
1912                // IAccessibilityServiceConnection can be garbage collected.
1913                mServiceInterface.setConnection(null, mId);
1914            } catch (RemoteException re) {
1915                /* ignore */
1916            }
1917            mService = null;
1918            mServiceInterface = null;
1919        }
1920
1921        public void binderDied() {
1922            synchronized (mLock) {
1923                // The death recipient is unregistered in tryRemoveServiceLocked
1924                tryRemoveServiceLocked(this);
1925                // We no longer have an automation service, so restore
1926                // the state based on values in the settings database.
1927                if (mIsAutomation) {
1928                    mUiAutomationService = null;
1929                    recreateInternalStateLocked(getUserStateLocked(mUserId));
1930                }
1931            }
1932        }
1933
1934        /**
1935         * Performs a notification for an {@link AccessibilityEvent}.
1936         *
1937         * @param event The event.
1938         */
1939        public void notifyAccessibilityEvent(AccessibilityEvent event) {
1940            synchronized (mLock) {
1941                final int eventType = event.getEventType();
1942                // Make a copy since during dispatch it is possible the event to
1943                // be modified to remove its source if the receiving service does
1944                // not have permission to access the window content.
1945                AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
1946                AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
1947                mPendingEvents.put(eventType, newEvent);
1948
1949                final int what = eventType;
1950                if (oldEvent != null) {
1951                    mHandler.removeMessages(what);
1952                    oldEvent.recycle();
1953                }
1954
1955                Message message = mHandler.obtainMessage(what);
1956                mHandler.sendMessageDelayed(message, mNotificationTimeout);
1957            }
1958        }
1959
1960        /**
1961         * Notifies an accessibility service client for a scheduled event given the event type.
1962         *
1963         * @param eventType The type of the event to dispatch.
1964         */
1965        private void notifyAccessibilityEventInternal(int eventType) {
1966            IAccessibilityServiceClient listener;
1967            AccessibilityEvent event;
1968
1969            synchronized (mLock) {
1970                listener = mServiceInterface;
1971
1972                // If the service died/was disabled while the message for dispatching
1973                // the accessibility event was propagating the listener may be null.
1974                if (listener == null) {
1975                    return;
1976                }
1977
1978                event = mPendingEvents.get(eventType);
1979
1980                // Check for null here because there is a concurrent scenario in which this
1981                // happens: 1) A binder thread calls notifyAccessibilityServiceDelayedLocked
1982                // which posts a message for dispatching an event. 2) The message is pulled
1983                // from the queue by the handler on the service thread and the latter is
1984                // just about to acquire the lock and call this method. 3) Now another binder
1985                // thread acquires the lock calling notifyAccessibilityServiceDelayedLocked
1986                // so the service thread waits for the lock; 4) The binder thread replaces
1987                // the event with a more recent one (assume the same event type) and posts a
1988                // dispatch request releasing the lock. 5) Now the main thread is unblocked and
1989                // dispatches the event which is removed from the pending ones. 6) And ... now
1990                // the service thread handles the last message posted by the last binder call
1991                // but the event is already dispatched and hence looking it up in the pending
1992                // ones yields null. This check is much simpler that keeping count for each
1993                // event type of each service to catch such a scenario since only one message
1994                // is processed at a time.
1995                if (event == null) {
1996                    return;
1997                }
1998
1999                mPendingEvents.remove(eventType);
2000                if (mSecurityPolicy.canRetrieveWindowContent(this)) {
2001                    event.setConnectionId(mId);
2002                } else {
2003                    event.setSource(null);
2004                }
2005                event.setSealed(true);
2006            }
2007
2008            try {
2009                listener.onAccessibilityEvent(event);
2010                if (DEBUG) {
2011                    Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
2012                }
2013            } catch (RemoteException re) {
2014                Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re);
2015            } finally {
2016                event.recycle();
2017            }
2018        }
2019
2020        public void notifyGesture(int gestureId) {
2021            mHandler.obtainMessage(MSG_ON_GESTURE, gestureId, 0).sendToTarget();
2022        }
2023
2024        private void notifyGestureInternal(int gestureId) {
2025            IAccessibilityServiceClient listener = mServiceInterface;
2026            if (listener != null) {
2027                try {
2028                    listener.onGesture(gestureId);
2029                } catch (RemoteException re) {
2030                    Slog.e(LOG_TAG, "Error during sending gesture " + gestureId
2031                            + " to " + mService, re);
2032                }
2033            }
2034        }
2035
2036        private void sendDownAndUpKeyEvents(int keyCode) {
2037            final long token = Binder.clearCallingIdentity();
2038
2039            // Inject down.
2040            final long downTime = SystemClock.uptimeMillis();
2041            KeyEvent down = KeyEvent.obtain(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
2042                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
2043                    InputDevice.SOURCE_KEYBOARD, null);
2044            InputManager.getInstance().injectInputEvent(down,
2045                    InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
2046            down.recycle();
2047
2048            // Inject up.
2049            final long upTime = SystemClock.uptimeMillis();
2050            KeyEvent up = KeyEvent.obtain(downTime, upTime, KeyEvent.ACTION_UP, keyCode, 0, 0,
2051                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
2052                    InputDevice.SOURCE_KEYBOARD, null);
2053            InputManager.getInstance().injectInputEvent(up,
2054                    InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
2055            up.recycle();
2056
2057            Binder.restoreCallingIdentity(token);
2058        }
2059
2060        private void expandNotifications() {
2061            final long token = Binder.clearCallingIdentity();
2062
2063            StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
2064                    android.app.Service.STATUS_BAR_SERVICE);
2065            statusBarManager.expandNotificationsPanel();
2066
2067            Binder.restoreCallingIdentity(token);
2068        }
2069
2070        private void expandQuickSettings() {
2071            final long token = Binder.clearCallingIdentity();
2072
2073            StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
2074                    android.app.Service.STATUS_BAR_SERVICE);
2075            statusBarManager.expandSettingsPanel();
2076
2077            Binder.restoreCallingIdentity(token);
2078        }
2079
2080        private void openRecents() {
2081            final long token = Binder.clearCallingIdentity();
2082
2083            IStatusBarService statusBarService = IStatusBarService.Stub.asInterface(
2084                    ServiceManager.getService("statusbar"));
2085            try {
2086                statusBarService.toggleRecentApps();
2087            } catch (RemoteException e) {
2088                Slog.e(LOG_TAG, "Error toggling recent apps.");
2089            }
2090
2091            Binder.restoreCallingIdentity(token);
2092        }
2093
2094        private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
2095            if (DEBUG) {
2096                Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
2097            }
2098            AccessibilityConnectionWrapper wrapper = mGlobalInteractionConnections.get(windowId);
2099            if (wrapper == null) {
2100                wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId);
2101            }
2102            if (wrapper != null && wrapper.mConnection != null) {
2103                return wrapper.mConnection;
2104            }
2105            if (DEBUG) {
2106                Slog.e(LOG_TAG, "No interaction connection to window: " + windowId);
2107            }
2108            return null;
2109        }
2110
2111        private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) {
2112            if (accessibilityWindowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) {
2113                return mSecurityPolicy.mActiveWindowId;
2114            }
2115            return accessibilityWindowId;
2116        }
2117
2118        private float getCompatibilityScale(int windowId) {
2119            try {
2120                IBinder windowToken = mGlobalWindowTokens.get(windowId);
2121                if (windowToken != null) {
2122                    return mWindowManagerService.getWindowCompatibilityScale(windowToken);
2123                }
2124                windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
2125                if (windowToken != null) {
2126                    return mWindowManagerService.getWindowCompatibilityScale(windowToken);
2127                }
2128            } catch (RemoteException re) {
2129                /* ignore */
2130            }
2131            return 1.0f;
2132        }
2133    }
2134
2135    final class SecurityPolicy {
2136        private static final int VALID_ACTIONS =
2137            AccessibilityNodeInfo.ACTION_CLICK
2138            | AccessibilityNodeInfo.ACTION_LONG_CLICK
2139            | AccessibilityNodeInfo.ACTION_FOCUS
2140            | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS
2141            | AccessibilityNodeInfo.ACTION_SELECT
2142            | AccessibilityNodeInfo.ACTION_CLEAR_SELECTION
2143            | AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS
2144            | AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS
2145            | AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2146            | AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2147            | AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT
2148            | AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT
2149            | AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
2150            | AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD;
2151
2152        private static final int RETRIEVAL_ALLOWING_EVENT_TYPES =
2153            AccessibilityEvent.TYPE_VIEW_CLICKED
2154            | AccessibilityEvent.TYPE_VIEW_FOCUSED
2155            | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
2156            | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
2157            | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED
2158            | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
2159            | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
2160            | AccessibilityEvent.TYPE_VIEW_SELECTED
2161            | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
2162            | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
2163            | AccessibilityEvent.TYPE_VIEW_SCROLLED
2164            | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
2165            | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED;
2166
2167        private int mActiveWindowId;
2168        private boolean mTouchInteractionInProgress;
2169
2170        private boolean canDispatchAccessibilityEvent(AccessibilityEvent event) {
2171            final int eventType = event.getEventType();
2172            switch (eventType) {
2173                // All events that are for changes in a global window
2174                // state should *always* be dispatched.
2175                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
2176                case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
2177                // All events generated by the user touching the
2178                // screen should *always* be dispatched.
2179                case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
2180                case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END:
2181                case AccessibilityEvent.TYPE_GESTURE_DETECTION_START:
2182                case AccessibilityEvent.TYPE_GESTURE_DETECTION_END:
2183                case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START:
2184                case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
2185                // These will change the active window, so dispatch.
2186                case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
2187                case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
2188                    return true;
2189                }
2190                // All events for changes in window content should be
2191                // dispatched *only* if this window is the active one.
2192                default:
2193                    return event.getWindowId() == mActiveWindowId;
2194            }
2195        }
2196
2197        public void updateEventSourceLocked(AccessibilityEvent event) {
2198            if ((event.getEventType() & RETRIEVAL_ALLOWING_EVENT_TYPES) == 0) {
2199                event.setSource(null);
2200            }
2201        }
2202
2203        public void updateActiveWindow(int windowId, int eventType) {
2204            // The active window is either the window that has input focus or
2205            // the window that the user is currently touching. If the user is
2206            // touching a window that does not have input focus as soon as the
2207            // the user stops touching that window the focused window becomes
2208            // the active one.
2209            switch (eventType) {
2210                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
2211                    if (getFocusedWindowId() == windowId) {
2212                        mActiveWindowId = windowId;
2213                    }
2214                } break;
2215                case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: {
2216                    // Do not allow delayed hover events to confuse us
2217                    // which the active window is.
2218                    if (mTouchInteractionInProgress) {
2219                        mActiveWindowId = windowId;
2220                    }
2221                } break;
2222            }
2223        }
2224
2225        public void onTouchInteractionStart() {
2226            mTouchInteractionInProgress = true;
2227        }
2228
2229        public void onTouchInteractionEnd() {
2230            mTouchInteractionInProgress = false;
2231            // We want to set the active window to be current immediately
2232            // after the user has stopped touching the screen since if the
2233            // user types with the IME he should get a feedback for the
2234            // letter typed in the text view which is in the input focused
2235            // window. Note that we always deliver hover accessibility events
2236            // (they are a result of user touching the screen) so change of
2237            // the active window before all hover accessibility events from
2238            // the touched window are delivered is fine.
2239            mActiveWindowId = getFocusedWindowId();
2240        }
2241
2242        public int getRetrievalAllowingWindowLocked() {
2243            return mActiveWindowId;
2244        }
2245
2246        public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) {
2247            return canRetrieveWindowContent(service) && isRetrievalAllowingWindow(windowId);
2248        }
2249
2250        public boolean canPerformActionLocked(Service service, int windowId, int action,
2251                Bundle arguments) {
2252            return canRetrieveWindowContent(service)
2253                && isRetrievalAllowingWindow(windowId)
2254                && isActionPermitted(action);
2255        }
2256
2257        public boolean canRetrieveWindowContent(Service service) {
2258            return service.mCanRetrieveScreenContent;
2259        }
2260
2261        public void enforceCanRetrieveWindowContent(Service service) throws RemoteException {
2262            // This happens due to incorrect registration so make it apparent.
2263            if (!canRetrieveWindowContent(service)) {
2264                Slog.e(LOG_TAG, "Accessibility serivce " + service.mComponentName + " does not " +
2265                        "declare android:canRetrieveWindowContent.");
2266                throw new RemoteException();
2267            }
2268        }
2269
2270        public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) {
2271            final int callingUid = Binder.getCallingUid();
2272            if (callingUid == Process.SYSTEM_UID
2273                    || callingUid == Process.SHELL_UID) {
2274                return mCurrentUserId;
2275            }
2276            final int callingUserId = UserHandle.getUserId(callingUid);
2277            if (callingUserId == userId) {
2278                return userId;
2279            }
2280            if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS)
2281                    && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) {
2282                throw new SecurityException("Call from user " + callingUserId + " as user "
2283                        + userId + " without permission INTERACT_ACROSS_USERS or "
2284                        + "INTERACT_ACROSS_USERS_FULL not allowed.");
2285            }
2286            if (userId == UserHandle.USER_CURRENT
2287                    || userId == UserHandle.USER_CURRENT_OR_SELF) {
2288                return mCurrentUserId;
2289            }
2290            throw new IllegalArgumentException("Calling user can be changed to only "
2291                    + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
2292        }
2293
2294        public boolean isCallerInteractingAcrossUsers(int userId) {
2295            final int callingUid = Binder.getCallingUid();
2296            return (Binder.getCallingPid() == android.os.Process.myPid()
2297                    || callingUid == Process.SHELL_UID
2298                    || userId == UserHandle.USER_CURRENT
2299                    || userId == UserHandle.USER_CURRENT_OR_SELF);
2300        }
2301
2302        private boolean isRetrievalAllowingWindow(int windowId) {
2303            return (mActiveWindowId == windowId);
2304        }
2305
2306        private boolean isActionPermitted(int action) {
2307             return (VALID_ACTIONS & action) != 0;
2308        }
2309
2310        private void enforceCallingPermission(String permission, String function) {
2311            if (OWN_PROCESS_ID == Binder.getCallingPid()) {
2312                return;
2313            }
2314            if (!hasPermission(permission)) {
2315                throw new SecurityException("You do not have " + permission
2316                        + " required to call " + function);
2317            }
2318        }
2319
2320        private boolean hasPermission(String permission) {
2321            return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
2322        }
2323
2324        private int getFocusedWindowId() {
2325            try {
2326                // We call this only on window focus change or after touch
2327                // exploration gesture end and the shown windows are not that
2328                // many, so the linear look up is just fine.
2329                IBinder token = mWindowManagerService.getFocusedWindowToken();
2330                if (token != null) {
2331                    synchronized (mLock) {
2332                        int windowId = getFocusedWindowIdLocked(token, mGlobalWindowTokens);
2333                        if (windowId < 0) {
2334                            windowId = getFocusedWindowIdLocked(token,
2335                                    getCurrentUserStateLocked().mWindowTokens);
2336                        }
2337                        return windowId;
2338                    }
2339                }
2340            } catch (RemoteException re) {
2341                /* ignore */
2342            }
2343            return -1;
2344        }
2345
2346        private int getFocusedWindowIdLocked(IBinder token, SparseArray<IBinder> windows) {
2347            final int windowCount = windows.size();
2348            for (int i = 0; i < windowCount; i++) {
2349                if (windows.valueAt(i) == token) {
2350                    return windows.keyAt(i);
2351                }
2352            }
2353            return -1;
2354        }
2355    }
2356
2357    private class UserState {
2358        public final int mUserId;
2359
2360        public final CopyOnWriteArrayList<Service> mServices = new CopyOnWriteArrayList<Service>();
2361
2362        public final RemoteCallbackList<IAccessibilityManagerClient> mClients =
2363            new RemoteCallbackList<IAccessibilityManagerClient>();
2364
2365        public final Map<ComponentName, Service> mComponentNameToServiceMap =
2366                new HashMap<ComponentName, Service>();
2367
2368        public final List<AccessibilityServiceInfo> mInstalledServices =
2369                new ArrayList<AccessibilityServiceInfo>();
2370
2371        public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
2372
2373        public final Set<ComponentName> mTouchExplorationGrantedServices =
2374                new HashSet<ComponentName>();
2375
2376        public final SparseArray<AccessibilityConnectionWrapper>
2377                mInteractionConnections =
2378                new SparseArray<AccessibilityConnectionWrapper>();
2379
2380        public final SparseArray<IBinder> mWindowTokens = new SparseArray<IBinder>();
2381
2382        public int mHandledFeedbackTypes = 0;
2383
2384        public boolean mIsAccessibilityEnabled;
2385        public boolean mIsTouchExplorationEnabled;
2386        public boolean mIsDisplayMagnificationEnabled;
2387
2388        public UserState(int userId) {
2389            mUserId = userId;
2390        }
2391    }
2392
2393    private class TempUserStateChangeMemento {
2394        public int mUserId = UserHandle.USER_NULL;
2395        public boolean mIsAccessibilityEnabled;
2396        public boolean mIsTouchExplorationEnabled;
2397        public boolean mIsDisplayMagnificationEnabled;
2398        public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
2399        public final Set<ComponentName> mTouchExplorationGrantedServices =
2400                new HashSet<ComponentName>();
2401
2402        public void initialize(int userId, UserState userState) {
2403            mUserId = userId;
2404            mIsAccessibilityEnabled = userState.mIsAccessibilityEnabled;
2405            mIsTouchExplorationEnabled = userState.mIsTouchExplorationEnabled;
2406            mIsDisplayMagnificationEnabled = userState.mIsDisplayMagnificationEnabled;
2407            mEnabledServices.clear();
2408            mEnabledServices.addAll(userState.mEnabledServices);
2409            mTouchExplorationGrantedServices.clear();
2410            mTouchExplorationGrantedServices.addAll(userState.mTouchExplorationGrantedServices);
2411        }
2412
2413        public void applyTo(UserState userState) {
2414            userState.mIsAccessibilityEnabled = mIsAccessibilityEnabled;
2415            userState.mIsTouchExplorationEnabled = mIsTouchExplorationEnabled;
2416            userState.mIsDisplayMagnificationEnabled = mIsDisplayMagnificationEnabled;
2417            userState.mEnabledServices.clear();
2418            userState.mEnabledServices.addAll(mEnabledServices);
2419            userState.mTouchExplorationGrantedServices.clear();
2420            userState.mTouchExplorationGrantedServices.addAll(mTouchExplorationGrantedServices);
2421        }
2422
2423        public void clear() {
2424            mUserId = UserHandle.USER_NULL;
2425            mIsAccessibilityEnabled = false;
2426            mIsTouchExplorationEnabled = false;
2427            mIsDisplayMagnificationEnabled = false;
2428            mEnabledServices.clear();
2429            mTouchExplorationGrantedServices.clear();
2430        }
2431    }
2432
2433    private final class AccessibilityContentObserver extends ContentObserver {
2434
2435        private final Uri mAccessibilityEnabledUri = Settings.Secure.getUriFor(
2436                Settings.Secure.ACCESSIBILITY_ENABLED);
2437
2438        private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor(
2439                Settings.Secure.TOUCH_EXPLORATION_ENABLED);
2440
2441        private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor(
2442                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
2443
2444        private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor(
2445                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
2446
2447        private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
2448                .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
2449
2450        public AccessibilityContentObserver(Handler handler) {
2451            super(handler);
2452        }
2453
2454        public void register(ContentResolver contentResolver) {
2455            contentResolver.registerContentObserver(mAccessibilityEnabledUri,
2456                    false, this, UserHandle.USER_ALL);
2457            contentResolver.registerContentObserver(mTouchExplorationEnabledUri,
2458                    false, this, UserHandle.USER_ALL);
2459            contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri,
2460                    false, this, UserHandle.USER_ALL);
2461            contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri,
2462                    false, this, UserHandle.USER_ALL);
2463            contentResolver.registerContentObserver(
2464                    mTouchExplorationGrantedAccessibilityServicesUri,
2465                    false, this, UserHandle.USER_ALL);
2466        }
2467
2468        @Override
2469        public void onChange(boolean selfChange, Uri uri) {
2470            if (mAccessibilityEnabledUri.equals(uri)) {
2471                synchronized (mLock) {
2472                    // We will update when the automation service dies.
2473                    if (mUiAutomationService == null) {
2474                        UserState userState = getCurrentUserStateLocked();
2475                        handleAccessibilityEnabledSettingChangedLocked(userState);
2476                        performServiceManagementLocked(userState);
2477                        updateInputFilterLocked(userState);
2478                        scheduleSendStateToClientsLocked(userState);
2479                    }
2480                }
2481            } else if (mTouchExplorationEnabledUri.equals(uri)) {
2482                synchronized (mLock) {
2483                    // We will update when the automation service dies.
2484                    if (mUiAutomationService == null) {
2485                        UserState userState = getCurrentUserStateLocked();
2486                        handleTouchExplorationEnabledSettingChangedLocked(userState);
2487                        updateInputFilterLocked(userState);
2488                        scheduleSendStateToClientsLocked(userState);
2489                    }
2490                }
2491            } else if (mDisplayMagnificationEnabledUri.equals(uri)) {
2492                synchronized (mLock) {
2493                    // We will update when the automation service dies.
2494                    if (mUiAutomationService == null) {
2495                        UserState userState = getCurrentUserStateLocked();
2496                        handleDisplayMagnificationEnabledSettingChangedLocked(userState);
2497                        updateInputFilterLocked(userState);
2498                        scheduleSendStateToClientsLocked(userState);
2499                    }
2500                }
2501            } else if (mEnabledAccessibilityServicesUri.equals(uri)) {
2502                synchronized (mLock) {
2503                    // We will update when the automation service dies.
2504                    if (mUiAutomationService == null) {
2505                        UserState userState = getCurrentUserStateLocked();
2506                        populateEnabledAccessibilityServicesLocked(userState);
2507                        manageServicesLocked(userState);
2508                    }
2509                }
2510            } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
2511                synchronized (mLock) {
2512                    // We will update when the automation service dies.
2513                    if (mUiAutomationService == null) {
2514                        UserState userState = getCurrentUserStateLocked();
2515                        populateTouchExplorationGrantedAccessibilityServicesLocked(userState);
2516                        handleTouchExplorationGrantedAccessibilityServicesChangedLocked(userState);
2517                    }
2518                }
2519            }
2520        }
2521    }
2522}
2523