AccessibilityManagerService.java revision cbcc9695f0a701d620f48de75eaee05c4fef6f22
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;
20
21import android.Manifest;
22import android.accessibilityservice.AccessibilityService;
23import android.accessibilityservice.AccessibilityServiceInfo;
24import android.accessibilityservice.IAccessibilityServiceClient;
25import android.accessibilityservice.IAccessibilityServiceConnection;
26import android.app.AlertDialog;
27import android.app.PendingIntent;
28import android.app.StatusBarManager;
29import android.content.BroadcastReceiver;
30import android.content.ComponentName;
31import android.content.ContentResolver;
32import android.content.Context;
33import android.content.DialogInterface;
34import android.content.DialogInterface.OnClickListener;
35import android.content.Intent;
36import android.content.IntentFilter;
37import android.content.ServiceConnection;
38import android.content.pm.PackageManager;
39import android.content.pm.ResolveInfo;
40import android.content.pm.ServiceInfo;
41import android.database.ContentObserver;
42import android.graphics.Point;
43import android.graphics.Rect;
44import android.hardware.display.DisplayManager;
45import android.hardware.input.InputManager;
46import android.net.Uri;
47import android.os.Binder;
48import android.os.Build;
49import android.os.Bundle;
50import android.os.Handler;
51import android.os.IBinder;
52import android.os.Looper;
53import android.os.Message;
54import android.os.Process;
55import android.os.RemoteCallbackList;
56import android.os.RemoteException;
57import android.os.ServiceManager;
58import android.os.SystemClock;
59import android.os.UserHandle;
60import android.os.UserManager;
61import android.provider.Settings;
62import android.text.TextUtils;
63import android.text.TextUtils.SimpleStringSplitter;
64import android.util.LongArray;
65import android.util.Pools.Pool;
66import android.util.Pools.SimplePool;
67import android.util.Slog;
68import android.util.SparseArray;
69import android.view.Display;
70import android.view.IWindow;
71import android.view.InputDevice;
72import android.view.InputEventConsistencyVerifier;
73import android.view.KeyCharacterMap;
74import android.view.KeyEvent;
75import android.view.MagnificationSpec;
76import android.view.WindowInfo;
77import android.view.WindowManager;
78import android.view.WindowManagerInternal;
79import android.view.WindowManagerPolicy;
80import android.view.accessibility.AccessibilityEvent;
81import android.view.accessibility.AccessibilityInteractionClient;
82import android.view.accessibility.AccessibilityManager;
83import android.view.accessibility.AccessibilityNodeInfo;
84import android.view.accessibility.AccessibilityWindowInfo;
85import android.view.accessibility.IAccessibilityInteractionConnection;
86import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
87import android.view.accessibility.IAccessibilityManager;
88import android.view.accessibility.IAccessibilityManagerClient;
89
90import com.android.internal.R;
91import com.android.internal.content.PackageMonitor;
92import com.android.internal.statusbar.IStatusBarService;
93import com.android.server.LocalServices;
94
95import org.xmlpull.v1.XmlPullParserException;
96
97import java.io.FileDescriptor;
98import java.io.IOException;
99import java.io.PrintWriter;
100import java.util.ArrayList;
101import java.util.Arrays;
102import java.util.Collections;
103import java.util.HashMap;
104import java.util.HashSet;
105import java.util.Iterator;
106import java.util.List;
107import java.util.Map;
108import java.util.Set;
109import java.util.concurrent.CopyOnWriteArrayList;
110
111/**
112 * This class is instantiated by the system as a system level service and can be
113 * accessed only by the system. The task of this service is to be a centralized
114 * event dispatch for {@link AccessibilityEvent}s generated across all processes
115 * on the device. Events are dispatched to {@link AccessibilityService}s.
116 *
117 * @hide
118 */
119public class AccessibilityManagerService extends IAccessibilityManager.Stub {
120
121    private static final boolean DEBUG = false;
122
123    private static final String LOG_TAG = "AccessibilityManagerService";
124
125    // TODO: This is arbitrary. When there is time implement this by watching
126    //       when that accessibility services are bound.
127    private static final int WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS = 3000;
128
129    private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE =
130        "registerUiTestAutomationService";
131
132    private static final String TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED =
133            "temporaryEnableAccessibilityStateUntilKeyguardRemoved";
134
135    private static final ComponentName sFakeAccessibilityServiceComponentName =
136            new ComponentName("foo.bar", "FakeService");
137
138    private static final String FUNCTION_DUMP = "dump";
139
140    private static final char COMPONENT_NAME_SEPARATOR = ':';
141
142    private static final int OWN_PROCESS_ID = android.os.Process.myPid();
143
144    private static final int MAX_POOL_SIZE = 10;
145
146    private static int sIdCounter = 0;
147
148    private static int sNextWindowId;
149
150    private final Context mContext;
151
152    private final Object mLock = new Object();
153
154    private final Pool<PendingEvent> mPendingEventPool =
155            new SimplePool<PendingEvent>(MAX_POOL_SIZE);
156
157    private final SimpleStringSplitter mStringColonSplitter =
158            new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
159
160    private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList =
161            new ArrayList<AccessibilityServiceInfo>();
162
163    private final Rect mTempRect = new Rect();
164
165    private final Point mTempPoint = new Point();
166
167    private final Display mDefaultDisplay;
168
169    private final PackageManager mPackageManager;
170
171    private final WindowManagerInternal mWindowManagerService;
172
173    private final SecurityPolicy mSecurityPolicy;
174
175    private final MainHandler mMainHandler;
176
177    private Service mQueryBridge;
178
179    private AlertDialog mEnableTouchExplorationDialog;
180
181    private AccessibilityInputFilter mInputFilter;
182
183    private boolean mHasInputFilter;
184
185    private final Set<ComponentName> mTempComponentNameSet = new HashSet<ComponentName>();
186
187    private final List<AccessibilityServiceInfo> mTempAccessibilityServiceInfoList =
188            new ArrayList<AccessibilityServiceInfo>();
189
190    private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
191            new RemoteCallbackList<IAccessibilityManagerClient>();
192
193    private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections =
194            new SparseArray<AccessibilityConnectionWrapper>();
195
196    private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<IBinder>();
197
198    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
199
200    private int mCurrentUserId = UserHandle.USER_OWNER;
201
202    private final LongArray mTempLongArray = new LongArray();
203
204    //TODO: Remove this hack
205    private boolean mInitialized;
206
207    private WindowsForAccessibilityCallback mWindowsForAccessibilityCallback;
208
209    private UserState getCurrentUserStateLocked() {
210        return getUserStateLocked(mCurrentUserId);
211    }
212
213    private UserState getUserStateLocked(int userId) {
214        UserState state = mUserStates.get(userId);
215        if (state == null) {
216            state = new UserState(userId);
217            mUserStates.put(userId, state);
218        }
219        return state;
220    }
221
222    /**
223     * Creates a new instance.
224     *
225     * @param context A {@link Context} instance.
226     */
227    public AccessibilityManagerService(Context context) {
228        mContext = context;
229        mPackageManager = mContext.getPackageManager();
230        mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
231        mSecurityPolicy = new SecurityPolicy();
232        mMainHandler = new MainHandler(mContext.getMainLooper());
233        //TODO: (multi-display) We need to support multiple displays.
234        DisplayManager displayManager = (DisplayManager)
235                mContext.getSystemService(Context.DISPLAY_SERVICE);
236        mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
237        registerBroadcastReceivers();
238        new AccessibilityContentObserver(mMainHandler).register(
239                context.getContentResolver());
240    }
241
242    private void registerBroadcastReceivers() {
243        PackageMonitor monitor = new PackageMonitor() {
244            @Override
245            public void onSomePackagesChanged() {
246                synchronized (mLock) {
247                    if (getChangingUserId() != mCurrentUserId) {
248                        return;
249                    }
250                    // We will update when the automation service dies.
251                    UserState userState = getCurrentUserStateLocked();
252                    // We have to reload the installed services since some services may
253                    // have different attributes, resolve info (does not support equals),
254                    // etc. Remove them then to force reload. Do it even if automation is
255                    // running since when it goes away, we will have to reload as well.
256                    userState.mInstalledServices.clear();
257                    if (userState.mUiAutomationService == null) {
258                        if (readConfigurationForUserStateLocked(userState)) {
259                            onUserStateChangedLocked(userState);
260                        }
261                    }
262                }
263            }
264
265            @Override
266            public void onPackageRemoved(String packageName, int uid) {
267                synchronized (mLock) {
268                    final int userId = getChangingUserId();
269                    if (userId != mCurrentUserId) {
270                        return;
271                    }
272                    UserState userState = getUserStateLocked(userId);
273                    Iterator<ComponentName> it = userState.mEnabledServices.iterator();
274                    while (it.hasNext()) {
275                        ComponentName comp = it.next();
276                        String compPkg = comp.getPackageName();
277                        if (compPkg.equals(packageName)) {
278                            it.remove();
279                            // Update the enabled services setting.
280                            persistComponentNamesToSettingLocked(
281                                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
282                                    userState.mEnabledServices, userId);
283                            // Update the touch exploration granted services setting.
284                            userState.mTouchExplorationGrantedServices.remove(comp);
285                            persistComponentNamesToSettingLocked(
286                                    Settings.Secure.
287                                    TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
288                                    userState.mTouchExplorationGrantedServices, userId);
289                            // We will update when the automation service dies.
290                            if (userState.mUiAutomationService == null) {
291                                onUserStateChangedLocked(userState);
292                            }
293                            return;
294                        }
295                    }
296                }
297            }
298
299            @Override
300            public boolean onHandleForceStop(Intent intent, String[] packages,
301                    int uid, boolean doit) {
302                synchronized (mLock) {
303                    final int userId = getChangingUserId();
304                    if (userId != mCurrentUserId) {
305                        return false;
306                    }
307                    UserState userState = getUserStateLocked(userId);
308                    Iterator<ComponentName> it = userState.mEnabledServices.iterator();
309                    while (it.hasNext()) {
310                        ComponentName comp = it.next();
311                        String compPkg = comp.getPackageName();
312                        for (String pkg : packages) {
313                            if (compPkg.equals(pkg)) {
314                                if (!doit) {
315                                    return true;
316                                }
317                                it.remove();
318                                persistComponentNamesToSettingLocked(
319                                        Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
320                                        userState.mEnabledServices, userId);
321                                // We will update when the automation service dies.
322                                if (userState.mUiAutomationService == null) {
323                                    onUserStateChangedLocked(userState);
324                                }
325                            }
326                        }
327                    }
328                    return false;
329                }
330            }
331        };
332
333        // package changes
334        monitor.register(mContext, null,  UserHandle.ALL, true);
335
336        // user change and unlock
337        IntentFilter intentFilter = new IntentFilter();
338        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
339        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
340        intentFilter.addAction(Intent.ACTION_USER_PRESENT);
341
342        mContext.registerReceiverAsUser(new BroadcastReceiver() {
343            @Override
344            public void onReceive(Context context, Intent intent) {
345                String action = intent.getAction();
346                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
347                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
348                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
349                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
350                } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
351                    // We will update when the automation service dies.
352                    UserState userState = getCurrentUserStateLocked();
353                    if (userState.mUiAutomationService == null) {
354                        if (readConfigurationForUserStateLocked(userState)) {
355                            onUserStateChangedLocked(userState);
356                        }
357                    }
358                }
359            }
360        }, UserHandle.ALL, intentFilter, null, null);
361    }
362
363    public int addClient(IAccessibilityManagerClient client, int userId) {
364        synchronized (mLock) {
365            final int resolvedUserId = mSecurityPolicy
366                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
367            // If the client is from a process that runs across users such as
368            // the system UI or the system we add it to the global state that
369            // is shared across users.
370            UserState userState = getUserStateLocked(resolvedUserId);
371            if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
372                mGlobalClients.register(client);
373                if (DEBUG) {
374                    Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid());
375                }
376                return userState.getClientState();
377            } else {
378                userState.mClients.register(client);
379                // If this client is not for the current user we do not
380                // return a state since it is not for the foreground user.
381                // We will send the state to the client on a user switch.
382                if (DEBUG) {
383                    Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid()
384                            + " and userId:" + mCurrentUserId);
385                }
386                return (resolvedUserId == mCurrentUserId) ? userState.getClientState() : 0;
387            }
388        }
389    }
390
391    public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) {
392        synchronized (mLock) {
393            final int resolvedUserId = mSecurityPolicy
394                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
395            // This method does nothing for a background user.
396            if (resolvedUserId != mCurrentUserId) {
397                return true; // yes, recycle the event
398            }
399            if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
400                mSecurityPolicy.updateActiveWindowLocked(event.getWindowId(), event.getEventType());
401                mSecurityPolicy.updateEventSourceLocked(event);
402                notifyAccessibilityServicesDelayedLocked(event, false);
403                notifyAccessibilityServicesDelayedLocked(event, true);
404            }
405            if (mHasInputFilter && mInputFilter != null) {
406                mMainHandler.obtainMessage(MainHandler.MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER,
407                        AccessibilityEvent.obtain(event)).sendToTarget();
408            }
409            event.recycle();
410            getUserStateLocked(resolvedUserId).mHandledFeedbackTypes = 0;
411        }
412        return (OWN_PROCESS_ID != Binder.getCallingPid());
413    }
414
415    public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
416        synchronized (mLock) {
417            final int resolvedUserId = mSecurityPolicy
418                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
419            // The automation service is a fake one and should not be reported
420            // to clients as being installed - it really is not.
421            UserState userState = getUserStateLocked(resolvedUserId);
422            if (userState.mUiAutomationService != null) {
423                List<AccessibilityServiceInfo> installedServices =
424                        new ArrayList<AccessibilityServiceInfo>();
425                installedServices.addAll(userState.mInstalledServices);
426                installedServices.remove(userState.mUiAutomationService);
427                return installedServices;
428            }
429            return userState.mInstalledServices;
430        }
431    }
432
433    public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,
434            int userId) {
435        List<AccessibilityServiceInfo> result = null;
436        synchronized (mLock) {
437            final int resolvedUserId = mSecurityPolicy
438                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
439
440            // The automation service is a fake one and should not be reported
441            // to clients as being enabled. The automation service is always the
442            // only active one, if it exists.
443            UserState userState = getUserStateLocked(resolvedUserId);
444            if (userState.mUiAutomationService != null) {
445                return Collections.emptyList();
446            }
447
448            result = mEnabledServicesForFeedbackTempList;
449            result.clear();
450            List<Service> services = userState.mBoundServices;
451            while (feedbackType != 0) {
452                final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType));
453                feedbackType &= ~feedbackTypeBit;
454                final int serviceCount = services.size();
455                for (int i = 0; i < serviceCount; i++) {
456                    Service service = services.get(i);
457                    if ((service.mFeedbackType & feedbackTypeBit) != 0) {
458                        result.add(service.mAccessibilityServiceInfo);
459                    }
460                }
461            }
462        }
463        return result;
464    }
465
466    public void interrupt(int userId) {
467        CopyOnWriteArrayList<Service> services;
468        synchronized (mLock) {
469            final int resolvedUserId = mSecurityPolicy
470                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
471            // This method does nothing for a background user.
472            if (resolvedUserId != mCurrentUserId) {
473                return;
474            }
475            services = getUserStateLocked(resolvedUserId).mBoundServices;
476        }
477        for (int i = 0, count = services.size(); i < count; i++) {
478            Service service = services.get(i);
479            try {
480                service.mServiceInterface.onInterrupt();
481            } catch (RemoteException re) {
482                Slog.e(LOG_TAG, "Error during sending interrupt request to "
483                    + service.mService, re);
484            }
485        }
486    }
487
488    public int addAccessibilityInteractionConnection(IWindow windowToken,
489            IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
490        synchronized (mLock) {
491            final int resolvedUserId = mSecurityPolicy
492                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
493            final int windowId = sNextWindowId++;
494            // If the window is from a process that runs across users such as
495            // the system UI or the system we add it to the global state that
496            // is shared across users.
497            if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
498                AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
499                        windowId, connection, UserHandle.USER_ALL);
500                wrapper.linkToDeath();
501                mGlobalInteractionConnections.put(windowId, wrapper);
502                mGlobalWindowTokens.put(windowId, windowToken.asBinder());
503                if (DEBUG) {
504                    Slog.i(LOG_TAG, "Added global connection for pid:" + Binder.getCallingPid()
505                            + " with windowId: " + windowId + " and  token: " + windowToken.asBinder());
506                }
507            } else {
508                AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
509                        windowId, connection, resolvedUserId);
510                wrapper.linkToDeath();
511                UserState userState = getUserStateLocked(resolvedUserId);
512                userState.mInteractionConnections.put(windowId, wrapper);
513                userState.mWindowTokens.put(windowId, windowToken.asBinder());
514                if (DEBUG) {
515                    Slog.i(LOG_TAG, "Added user connection for pid:" + Binder.getCallingPid()
516                            + " with windowId: " + windowId + " and userId:" + mCurrentUserId
517                            + " and  token: " + windowToken.asBinder());
518                }
519            }
520            return windowId;
521        }
522    }
523
524    public void removeAccessibilityInteractionConnection(IWindow window) {
525        synchronized (mLock) {
526            mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
527                    UserHandle.getCallingUserId());
528            IBinder token = window.asBinder();
529            final int removedWindowId = removeAccessibilityInteractionConnectionInternalLocked(
530                    token, mGlobalWindowTokens, mGlobalInteractionConnections);
531            if (removedWindowId >= 0) {
532                if (DEBUG) {
533                    Slog.i(LOG_TAG, "Removed global connection for pid:" + Binder.getCallingPid()
534                            + " with windowId: " + removedWindowId + " and token: " + window.asBinder());
535                }
536                return;
537            }
538            final int userCount = mUserStates.size();
539            for (int i = 0; i < userCount; i++) {
540                UserState userState = mUserStates.valueAt(i);
541                final int removedWindowIdForUser =
542                        removeAccessibilityInteractionConnectionInternalLocked(
543                        token, userState.mWindowTokens, userState.mInteractionConnections);
544                if (removedWindowIdForUser >= 0) {
545                    if (DEBUG) {
546                        Slog.i(LOG_TAG, "Removed user connection for pid:" + Binder.getCallingPid()
547                                + " with windowId: " + removedWindowIdForUser + " and userId:"
548                                + mUserStates.keyAt(i) + " and token: " + window.asBinder());
549                    }
550                    return;
551                }
552            }
553        }
554    }
555
556    private int removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken,
557            SparseArray<IBinder> windowTokens,
558            SparseArray<AccessibilityConnectionWrapper> interactionConnections) {
559        final int count = windowTokens.size();
560        for (int i = 0; i < count; i++) {
561            if (windowTokens.valueAt(i) == windowToken) {
562                final int windowId = windowTokens.keyAt(i);
563                windowTokens.removeAt(i);
564                AccessibilityConnectionWrapper wrapper = interactionConnections.get(windowId);
565                wrapper.unlinkToDeath();
566                interactionConnections.remove(windowId);
567                return windowId;
568            }
569        }
570        return -1;
571    }
572
573    public void registerUiTestAutomationService(IBinder owner,
574            IAccessibilityServiceClient serviceClient,
575            AccessibilityServiceInfo accessibilityServiceInfo) {
576        mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
577                FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
578
579        accessibilityServiceInfo.setComponentName(sFakeAccessibilityServiceComponentName);
580
581        synchronized (mLock) {
582            UserState userState = getCurrentUserStateLocked();
583
584            if (userState.mUiAutomationService != null) {
585                throw new IllegalStateException("UiAutomationService " + serviceClient
586                        + "already registered!");
587            }
588
589            try {
590                owner.linkToDeath(userState.mUiAutomationSerivceOnwerDeathRecipient, 0);
591            } catch (RemoteException re) {
592                Slog.e(LOG_TAG, "Couldn't register for the death of a"
593                        + " UiTestAutomationService!", re);
594                return;
595            }
596
597            userState.mUiAutomationServiceOwner = owner;
598            userState.mUiAutomationServiceClient = serviceClient;
599
600            // Set the temporary state.
601            userState.mIsAccessibilityEnabled = true;
602            userState.mIsTouchExplorationEnabled = false;
603            userState.mIsEnhancedWebAccessibilityEnabled = false;
604            userState.mIsDisplayMagnificationEnabled = false;
605            userState.mInstalledServices.add(accessibilityServiceInfo);
606            userState.mEnabledServices.clear();
607            userState.mEnabledServices.add(sFakeAccessibilityServiceComponentName);
608            userState.mTouchExplorationGrantedServices.add(sFakeAccessibilityServiceComponentName);
609
610            // Use the new state instead of settings.
611            onUserStateChangedLocked(userState);
612        }
613    }
614
615    public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
616        synchronized (mLock) {
617            UserState userState = getCurrentUserStateLocked();
618            // Automation service is not bound, so pretend it died to perform clean up.
619            if (userState.mUiAutomationService != null
620                    && serviceClient != null
621                    && userState.mUiAutomationService != null
622                    && userState.mUiAutomationService.mServiceInterface != null
623                    && userState.mUiAutomationService.mServiceInterface.asBinder()
624                    == serviceClient.asBinder()) {
625                userState.mUiAutomationService.binderDied();
626            } else {
627                throw new IllegalStateException("UiAutomationService " + serviceClient
628                        + " not registered!");
629            }
630        }
631    }
632
633    public void temporaryEnableAccessibilityStateUntilKeyguardRemoved(
634            ComponentName service, boolean touchExplorationEnabled) {
635        mSecurityPolicy.enforceCallingPermission(
636                Manifest.permission.TEMPORARY_ENABLE_ACCESSIBILITY,
637                TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED);
638        if (!mWindowManagerService.isKeyguardLocked()) {
639            return;
640        }
641        synchronized (mLock) {
642            // Set the temporary state.
643            UserState userState = getCurrentUserStateLocked();
644
645            // This is a nop if UI automation is enabled.
646            if (userState.mUiAutomationService != null) {
647                return;
648            }
649
650            userState.mIsAccessibilityEnabled = true;
651            userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
652            userState.mIsEnhancedWebAccessibilityEnabled = false;
653            userState.mIsDisplayMagnificationEnabled = false;
654            userState.mEnabledServices.clear();
655            userState.mEnabledServices.add(service);
656            userState.mBindingServices.clear();
657            userState.mTouchExplorationGrantedServices.clear();
658            userState.mTouchExplorationGrantedServices.add(service);
659
660            // User the current state instead settings.
661            onUserStateChangedLocked(userState);
662        }
663    }
664
665    boolean onGesture(int gestureId) {
666        synchronized (mLock) {
667            boolean handled = notifyGestureLocked(gestureId, false);
668            if (!handled) {
669                handled = notifyGestureLocked(gestureId, true);
670            }
671            return handled;
672        }
673    }
674
675    boolean notifyKeyEvent(KeyEvent event, int policyFlags) {
676        synchronized (mLock) {
677            KeyEvent localClone = KeyEvent.obtain(event);
678            boolean handled = notifyKeyEventLocked(localClone, policyFlags, false);
679            if (!handled) {
680                handled = notifyKeyEventLocked(localClone, policyFlags, true);
681            }
682            return handled;
683        }
684    }
685
686    /**
687     * Gets the bounds of the accessibility focus in the active window.
688     *
689     * @param outBounds The output to which to write the focus bounds.
690     * @return Whether accessibility focus was found and the bounds are populated.
691     */
692    // TODO: (multi-display) Make sure this works for multiple displays.
693    boolean getAccessibilityFocusBoundsInActiveWindow(Rect outBounds) {
694        // Instead of keeping track of accessibility focus events per
695        // window to be able to find the focus in the active window,
696        // we take a stateless approach and look it up. This is fine
697        // since we do this only when the user clicks/long presses.
698        Service service = getQueryBridge();
699        final int connectionId = service.mId;
700        AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
701        client.addConnection(connectionId, service);
702        try {
703            AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance()
704                    .getRootInActiveWindow(connectionId);
705            if (root == null) {
706                return false;
707            }
708            AccessibilityNodeInfo focus = root.findFocus(
709                    AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
710            if (focus == null) {
711                return false;
712            }
713            focus.getBoundsInScreen(outBounds);
714
715            MagnificationSpec spec = service.getCompatibleMagnificationSpec(focus.getWindowId());
716            if (spec != null && !spec.isNop()) {
717                outBounds.offset((int) -spec.offsetX, (int) -spec.offsetY);
718                outBounds.scale(1 / spec.scale);
719            }
720
721            // Clip to the window rectangle.
722            Rect windowBounds = mTempRect;
723            getActiveWindowBounds(windowBounds);
724            outBounds.intersect(windowBounds);
725            // Clip to the screen rectangle.
726            mDefaultDisplay.getRealSize(mTempPoint);
727            outBounds.intersect(0,  0,  mTempPoint.x, mTempPoint.y);
728
729            return true;
730        } finally {
731            client.removeConnection(connectionId);
732        }
733    }
734
735    /**
736     * Gets the bounds of the active window.
737     *
738     * @param outBounds The output to which to write the bounds.
739     */
740    boolean getActiveWindowBounds(Rect outBounds) {
741        // TODO: This should be refactored to work with accessibility
742        // focus in multiple windows.
743        IBinder token;
744        synchronized (mLock) {
745            final int windowId = mSecurityPolicy.mActiveWindowId;
746            token = mGlobalWindowTokens.get(windowId);
747            if (token == null) {
748                token = getCurrentUserStateLocked().mWindowTokens.get(windowId);
749            }
750        }
751        mWindowManagerService.getWindowFrame(token, outBounds);
752        if (!outBounds.isEmpty()) {
753            return true;
754        }
755        return false;
756    }
757
758    int getActiveWindowId() {
759        return mSecurityPolicy.mActiveWindowId;
760    }
761
762    void onTouchInteractionStart() {
763        mSecurityPolicy.onTouchInteractionStart();
764    }
765
766    void onTouchInteractionEnd() {
767        mSecurityPolicy.onTouchInteractionEnd();
768    }
769
770    void onMagnificationStateChanged() {
771        notifyClearAccessibilityCacheLocked();
772    }
773
774    private void switchUser(int userId) {
775        synchronized (mLock) {
776            if (mCurrentUserId == userId && mInitialized) {
777                return;
778            }
779
780            // Disconnect from services for the old user.
781            UserState oldUserState = getUserStateLocked(mCurrentUserId);
782            oldUserState.onSwitchToAnotherUser();
783
784            // Disable the local managers for the old user.
785            if (oldUserState.mClients.getRegisteredCallbackCount() > 0) {
786                mMainHandler.obtainMessage(MainHandler.MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER,
787                        oldUserState.mUserId, 0).sendToTarget();
788            }
789
790            // Announce user changes only if more that one exist.
791            UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
792            final boolean announceNewUser = userManager.getUsers().size() > 1;
793
794            // The user changed.
795            mCurrentUserId = userId;
796
797            UserState userState = getCurrentUserStateLocked();
798            if (userState.mUiAutomationService != null) {
799                // Switching users disables the UI automation service.
800                userState.mUiAutomationService.binderDied();
801            }
802
803            readConfigurationForUserStateLocked(userState);
804            // Even if reading did not yield change, we have to update
805            // the state since the context in which the current user
806            // state was used has changed since it was inactive.
807            onUserStateChangedLocked(userState);
808
809            if (announceNewUser) {
810                // Schedule announcement of the current user if needed.
811                mMainHandler.sendEmptyMessageDelayed(MainHandler.MSG_ANNOUNCE_NEW_USER_IF_NEEDED,
812                        WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS);
813            }
814        }
815    }
816
817    private void removeUser(int userId) {
818        synchronized (mLock) {
819            mUserStates.remove(userId);
820        }
821    }
822
823    private Service getQueryBridge() {
824        if (mQueryBridge == null) {
825            AccessibilityServiceInfo info = new AccessibilityServiceInfo();
826            info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
827            mQueryBridge = new Service(UserHandle.USER_NULL,
828                    sFakeAccessibilityServiceComponentName, info);
829        }
830        return mQueryBridge;
831    }
832
833    private boolean notifyGestureLocked(int gestureId, boolean isDefault) {
834        // TODO: Now we are giving the gestures to the last enabled
835        //       service that can handle them which is the last one
836        //       in our list since we write the last enabled as the
837        //       last record in the enabled services setting. Ideally,
838        //       the user should make the call which service handles
839        //       gestures. However, only one service should handle
840        //       gestures to avoid user frustration when different
841        //       behavior is observed from different combinations of
842        //       enabled accessibility services.
843        UserState state = getCurrentUserStateLocked();
844        for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
845            Service service = state.mBoundServices.get(i);
846            if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) {
847                service.notifyGesture(gestureId);
848                return true;
849            }
850        }
851        return false;
852    }
853
854    private boolean notifyKeyEventLocked(KeyEvent event, int policyFlags, boolean isDefault) {
855        // TODO: Now we are giving the key events to the last enabled
856        //       service that can handle them Ideally, the user should
857        //       make the call which service handles key events. However,
858        //       only one service should handle key events to avoid user
859        //       frustration when different behavior is observed from
860        //       different combinations of enabled accessibility services.
861        UserState state = getCurrentUserStateLocked();
862        for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
863            Service service = state.mBoundServices.get(i);
864            // Key events are handled only by services that declared
865            // this capability and requested to filter key events.
866            if (!service.mRequestFilterKeyEvents ||
867                    (service.mAccessibilityServiceInfo.getCapabilities() & AccessibilityServiceInfo
868                            .CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) == 0) {
869                continue;
870            }
871            if (service.mIsDefault == isDefault) {
872                service.notifyKeyEvent(event, policyFlags);
873                return true;
874            }
875        }
876        return false;
877    }
878
879    private void notifyClearAccessibilityCacheLocked() {
880        UserState state = getCurrentUserStateLocked();
881        for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
882            Service service = state.mBoundServices.get(i);
883            service.notifyClearAccessibilityNodeInfoCache();
884        }
885    }
886
887    private void notifyWindowsChangedLocked(List<AccessibilityWindowInfo> windows) {
888        UserState state = getCurrentUserStateLocked();
889        for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
890            Service service = state.mBoundServices.get(i);
891            if (mSecurityPolicy.canRetrieveWindowsLocked(service)) {
892                service.notifyWindowsChangedLocked(windows);
893            }
894        }
895    }
896
897    /**
898     * Removes an AccessibilityInteractionConnection.
899     *
900     * @param windowId The id of the window to which the connection is targeted.
901     * @param userId The id of the user owning the connection. UserHandle.USER_ALL
902     *     if global.
903     */
904    private void removeAccessibilityInteractionConnectionLocked(int windowId, int userId) {
905        if (userId == UserHandle.USER_ALL) {
906            mGlobalWindowTokens.remove(windowId);
907            mGlobalInteractionConnections.remove(windowId);
908        } else {
909            UserState userState = getCurrentUserStateLocked();
910            userState.mWindowTokens.remove(windowId);
911            userState.mInteractionConnections.remove(windowId);
912        }
913        if (DEBUG) {
914            Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId);
915        }
916    }
917
918    private boolean readInstalledAccessibilityServiceLocked(UserState userState) {
919        mTempAccessibilityServiceInfoList.clear();
920
921        List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
922                new Intent(AccessibilityService.SERVICE_INTERFACE),
923                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
924                mCurrentUserId);
925
926        for (int i = 0, count = installedServices.size(); i < count; i++) {
927            ResolveInfo resolveInfo = installedServices.get(i);
928            ServiceInfo serviceInfo = resolveInfo.serviceInfo;
929            if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals(
930                    serviceInfo.permission)) {
931                Slog.w(LOG_TAG, "Skipping accessibilty service " + new ComponentName(
932                        serviceInfo.packageName, serviceInfo.name).flattenToShortString()
933                        + ": it does not require the permission "
934                        + android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE);
935                continue;
936            }
937            AccessibilityServiceInfo accessibilityServiceInfo;
938            try {
939                accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
940                mTempAccessibilityServiceInfoList.add(accessibilityServiceInfo);
941            } catch (XmlPullParserException xppe) {
942                Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe);
943            } catch (IOException ioe) {
944                Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", ioe);
945            }
946        }
947
948        if (!mTempAccessibilityServiceInfoList.equals(userState.mInstalledServices)) {
949            userState.mInstalledServices.clear();
950            userState.mInstalledServices.addAll(mTempAccessibilityServiceInfoList);
951            mTempAccessibilityServiceInfoList.clear();
952            return true;
953        }
954
955        mTempAccessibilityServiceInfoList.clear();
956        return false;
957    }
958
959    private boolean readEnabledAccessibilityServicesLocked(UserState userState) {
960        mTempComponentNameSet.clear();
961        readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
962                userState.mUserId, mTempComponentNameSet);
963        if (!mTempComponentNameSet.equals(userState.mEnabledServices)) {
964            userState.mEnabledServices.clear();
965            userState.mEnabledServices.addAll(mTempComponentNameSet);
966            mTempComponentNameSet.clear();
967            return true;
968        }
969        mTempComponentNameSet.clear();
970        return false;
971    }
972
973    private boolean readTouchExplorationGrantedAccessibilityServicesLocked(
974            UserState userState) {
975        mTempComponentNameSet.clear();
976        readComponentNamesFromSettingLocked(
977                Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
978                userState.mUserId, mTempComponentNameSet);
979        if (!mTempComponentNameSet.equals(userState.mTouchExplorationGrantedServices)) {
980            userState.mTouchExplorationGrantedServices.clear();
981            userState.mTouchExplorationGrantedServices.addAll(mTempComponentNameSet);
982            mTempComponentNameSet.clear();
983            return true;
984        }
985        mTempComponentNameSet.clear();
986        return false;
987    }
988
989    /**
990     * Performs {@link AccessibilityService}s delayed notification. The delay is configurable
991     * and denotes the period after the last event before notifying the service.
992     *
993     * @param event The event.
994     * @param isDefault True to notify default listeners, not default services.
995     */
996    private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event,
997            boolean isDefault) {
998        try {
999            UserState state = getCurrentUserStateLocked();
1000            for (int i = 0, count = state.mBoundServices.size(); i < count; i++) {
1001                Service service = state.mBoundServices.get(i);
1002
1003                if (service.mIsDefault == isDefault) {
1004                    if (canDispatchEventToServiceLocked(service, event,
1005                            state.mHandledFeedbackTypes)) {
1006                        state.mHandledFeedbackTypes |= service.mFeedbackType;
1007                        service.notifyAccessibilityEvent(event);
1008                    }
1009                }
1010            }
1011        } catch (IndexOutOfBoundsException oobe) {
1012            // An out of bounds exception can happen if services are going away
1013            // as the for loop is running. If that happens, just bail because
1014            // there are no more services to notify.
1015            return;
1016        }
1017    }
1018
1019    private void addServiceLocked(Service service, UserState userState) {
1020        try {
1021            service.linkToOwnDeathLocked();
1022            userState.mBoundServices.add(service);
1023            userState.mComponentNameToServiceMap.put(service.mComponentName, service);
1024        } catch (RemoteException re) {
1025            /* do nothing */
1026        }
1027    }
1028
1029    /**
1030     * Removes a service.
1031     *
1032     * @param service The service.
1033     * @return True if the service was removed, false otherwise.
1034     */
1035    private void removeServiceLocked(Service service, UserState userState) {
1036        userState.mBoundServices.remove(service);
1037        userState.mComponentNameToServiceMap.remove(service.mComponentName);
1038        service.unlinkToOwnDeathLocked();
1039    }
1040
1041    /**
1042     * Determines if given event can be dispatched to a service based on the package of the
1043     * event source and already notified services for that event type. Specifically, a
1044     * service is notified if it is interested in events from the package and no other service
1045     * providing the same feedback type has been notified. Exception are services the
1046     * provide generic feedback (feedback type left as a safety net for unforeseen feedback
1047     * types) which are always notified.
1048     *
1049     * @param service The potential receiver.
1050     * @param event The event.
1051     * @param handledFeedbackTypes The feedback types for which services have been notified.
1052     * @return True if the listener should be notified, false otherwise.
1053     */
1054    private boolean canDispatchEventToServiceLocked(Service service, AccessibilityEvent event,
1055            int handledFeedbackTypes) {
1056
1057        if (!service.canReceiveEventsLocked()) {
1058            return false;
1059        }
1060
1061        if (!event.isImportantForAccessibility()
1062                && (service.mFetchFlags
1063                        & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) {
1064            return false;
1065        }
1066
1067        int eventType = event.getEventType();
1068        if ((service.mEventTypes & eventType) != eventType) {
1069            return false;
1070        }
1071
1072        Set<String> packageNames = service.mPackageNames;
1073        CharSequence packageName = event.getPackageName();
1074
1075        if (packageNames.isEmpty() || packageNames.contains(packageName)) {
1076            int feedbackType = service.mFeedbackType;
1077            if ((handledFeedbackTypes & feedbackType) != feedbackType
1078                    || feedbackType == AccessibilityServiceInfo.FEEDBACK_GENERIC) {
1079                return true;
1080            }
1081        }
1082
1083        return false;
1084    }
1085
1086    private void unbindAllServicesLocked(UserState userState) {
1087        List<Service> services = userState.mBoundServices;
1088        for (int i = 0, count = services.size(); i < count; i++) {
1089            Service service = services.get(i);
1090            if (service.unbindLocked()) {
1091                i--;
1092                count--;
1093            }
1094        }
1095    }
1096
1097    /**
1098     * Populates a set with the {@link ComponentName}s stored in a colon
1099     * separated value setting for a given user.
1100     *
1101     * @param settingName The setting to parse.
1102     * @param userId The user id.
1103     * @param outComponentNames The output component names.
1104     */
1105    private void readComponentNamesFromSettingLocked(String settingName, int userId,
1106            Set<ComponentName> outComponentNames) {
1107        String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
1108                settingName, userId);
1109        outComponentNames.clear();
1110        if (settingValue != null) {
1111            TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
1112            splitter.setString(settingValue);
1113            while (splitter.hasNext()) {
1114                String str = splitter.next();
1115                if (str == null || str.length() <= 0) {
1116                    continue;
1117                }
1118                ComponentName enabledService = ComponentName.unflattenFromString(str);
1119                if (enabledService != null) {
1120                    outComponentNames.add(enabledService);
1121                }
1122            }
1123        }
1124    }
1125
1126    /**
1127     * Persists the component names in the specified setting in a
1128     * colon separated fashion.
1129     *
1130     * @param settingName The setting name.
1131     * @param componentNames The component names.
1132     */
1133    private void persistComponentNamesToSettingLocked(String settingName,
1134            Set<ComponentName> componentNames, int userId) {
1135        StringBuilder builder = new StringBuilder();
1136        for (ComponentName componentName : componentNames) {
1137            if (builder.length() > 0) {
1138                builder.append(COMPONENT_NAME_SEPARATOR);
1139            }
1140            builder.append(componentName.flattenToShortString());
1141        }
1142        Settings.Secure.putStringForUser(mContext.getContentResolver(),
1143                settingName, builder.toString(), userId);
1144    }
1145
1146    private void manageServicesLocked(UserState userState) {
1147        Map<ComponentName, Service> componentNameToServiceMap =
1148                userState.mComponentNameToServiceMap;
1149        boolean isEnabled = userState.mIsAccessibilityEnabled;
1150
1151        for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
1152            AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
1153            ComponentName componentName = ComponentName.unflattenFromString(
1154                    installedService.getId());
1155            Service service = componentNameToServiceMap.get(componentName);
1156
1157            if (isEnabled) {
1158                // Wait for the binding if it is in process.
1159                if (userState.mBindingServices.contains(componentName)) {
1160                    continue;
1161                }
1162                if (userState.mEnabledServices.contains(componentName)) {
1163                    if (service == null) {
1164                        service = new Service(userState.mUserId, componentName, installedService);
1165                    } else if (userState.mBoundServices.contains(service)) {
1166                        continue;
1167                    }
1168                    service.bindLocked();
1169                } else {
1170                    if (service != null) {
1171                        service.unbindLocked();
1172                    }
1173                }
1174            } else {
1175                if (service != null) {
1176                    service.unbindLocked();
1177                } else {
1178                    userState.mBindingServices.remove(componentName);
1179                }
1180            }
1181        }
1182
1183        // No enabled installed services => disable accessibility to avoid
1184        // sending accessibility events with no recipient across processes.
1185        if (isEnabled && userState.mEnabledServices.isEmpty()) {
1186            userState.mIsAccessibilityEnabled = false;
1187            Settings.Secure.putIntForUser(mContext.getContentResolver(),
1188                    Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
1189        }
1190    }
1191
1192    private void scheduleUpdateClientsIfNeededLocked(UserState userState) {
1193        final int clientState = userState.getClientState();
1194        if (userState.mLastSentClientState != clientState
1195                && (mGlobalClients.getRegisteredCallbackCount() > 0
1196                        || userState.mClients.getRegisteredCallbackCount() > 0)) {
1197            userState.mLastSentClientState = clientState;
1198            mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS,
1199                    clientState, userState.mUserId) .sendToTarget();
1200        }
1201    }
1202
1203    private void scheduleUpdateInputFilter(UserState userState) {
1204        mMainHandler.obtainMessage(MainHandler.MSG_UPDATE_INPUT_FILTER, userState).sendToTarget();
1205    }
1206
1207    private void updateInputFilter(UserState userState) {
1208        boolean setInputFilter = false;
1209        AccessibilityInputFilter inputFilter = null;
1210        synchronized (mLock) {
1211            int flags = 0;
1212            if (userState.mIsDisplayMagnificationEnabled) {
1213                flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
1214            }
1215            // Touch exploration without accessibility makes no sense.
1216            if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) {
1217                flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
1218            }
1219            if (userState.mIsFilterKeyEventsEnabled) {
1220                flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS;
1221            }
1222            if (flags != 0) {
1223                if (!mHasInputFilter) {
1224                    mHasInputFilter = true;
1225                    if (mInputFilter == null) {
1226                        mInputFilter = new AccessibilityInputFilter(mContext,
1227                                AccessibilityManagerService.this);
1228                    }
1229                    inputFilter = mInputFilter;
1230                    setInputFilter = true;
1231                }
1232                mInputFilter.setEnabledFeatures(flags);
1233            } else {
1234                if (mHasInputFilter) {
1235                    mHasInputFilter = false;
1236                    mInputFilter.disableFeatures();
1237                    inputFilter = null;
1238                    setInputFilter = true;
1239                }
1240            }
1241        }
1242        if (setInputFilter) {
1243            mWindowManagerService.setInputFilter(inputFilter);
1244        }
1245    }
1246
1247    private void showEnableTouchExplorationDialog(final Service service) {
1248        synchronized (mLock) {
1249            String label = service.mResolveInfo.loadLabel(
1250            mContext.getPackageManager()).toString();
1251
1252            final UserState state = getCurrentUserStateLocked();
1253            if (state.mIsTouchExplorationEnabled) {
1254                return;
1255            }
1256            if (mEnableTouchExplorationDialog != null
1257                    && mEnableTouchExplorationDialog.isShowing()) {
1258                return;
1259            }
1260            mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext)
1261                .setIconAttribute(android.R.attr.alertDialogIcon)
1262                .setPositiveButton(android.R.string.ok, new OnClickListener() {
1263                     @Override
1264                     public void onClick(DialogInterface dialog, int which) {
1265                         // The user allowed the service to toggle touch exploration.
1266                         state.mTouchExplorationGrantedServices.add(service.mComponentName);
1267                         persistComponentNamesToSettingLocked(
1268                                 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
1269                                 state.mTouchExplorationGrantedServices, state.mUserId);
1270                         // Enable touch exploration.
1271                         UserState userState = getUserStateLocked(service.mUserId);
1272                         userState.mIsTouchExplorationEnabled = true;
1273                         Settings.Secure.putIntForUser(mContext.getContentResolver(),
1274                                 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1,
1275                                 service.mUserId);
1276                         onUserStateChangedLocked(userState);
1277                     }
1278                 })
1279                 .setNegativeButton(android.R.string.cancel, new OnClickListener() {
1280                     @Override
1281                     public void onClick(DialogInterface dialog, int which) {
1282                         dialog.dismiss();
1283                     }
1284                 })
1285                 .setTitle(R.string.enable_explore_by_touch_warning_title)
1286                 .setMessage(mContext.getString(
1287                         R.string.enable_explore_by_touch_warning_message, label))
1288                 .create();
1289             mEnableTouchExplorationDialog.getWindow().setType(
1290                     WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1291             mEnableTouchExplorationDialog.getWindow().getAttributes().privateFlags
1292                     |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
1293             mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true);
1294             mEnableTouchExplorationDialog.show();
1295        }
1296    }
1297
1298    private void onUserStateChangedLocked(UserState userState) {
1299        // TODO: Remove this hack
1300        mInitialized = true;
1301        updateLegacyCapabilities(userState);
1302        updateServicesLocked(userState);
1303        updateWindowsForAccessibilityCallback(userState);
1304        updateFilterKeyEventsLocked(userState);
1305        updateTouchExplorationLocked(userState);
1306        updateEnhancedWebAccessibilityLocked(userState);
1307        updateDisplayColorAdjustmentSettingsLocked(userState);
1308        scheduleUpdateInputFilter(userState);
1309        scheduleUpdateClientsIfNeededLocked(userState);
1310    }
1311
1312    private void updateWindowsForAccessibilityCallback(UserState userState) {
1313        if (userState.mIsAccessibilityEnabled) {
1314            // We observe windows for accessibility only if there is at least
1315            // one bound service that can retrieve window content that specified
1316            // it is interested in accessing such windows. For services that are
1317            // binding we do an update pass after each bind event, so we run this
1318            // code and register the callback if needed.
1319            boolean boundServiceCanRetrieveInteractiveWindows = false;
1320
1321            List<Service> boundServices = userState.mBoundServices;
1322            final int boundServiceCount = boundServices.size();
1323            for (int i = 0; i < boundServiceCount; i++) {
1324                Service boundService = boundServices.get(i);
1325                if (mSecurityPolicy.canRetrieveWindowContentLocked(boundService)
1326                        && boundService.mRetrieveInteractiveWindows) {
1327                    boundServiceCanRetrieveInteractiveWindows = true;
1328                    break;
1329                }
1330            }
1331
1332            if (boundServiceCanRetrieveInteractiveWindows) {
1333                if (mWindowsForAccessibilityCallback == null) {
1334                    mWindowsForAccessibilityCallback = new WindowsForAccessibilityCallback();
1335                    mWindowManagerService.setWindowsForAccessibilityCallback(
1336                            mWindowsForAccessibilityCallback);
1337                }
1338                return;
1339            }
1340        }
1341
1342        if (mWindowsForAccessibilityCallback != null) {
1343            mWindowsForAccessibilityCallback = null;
1344            mWindowManagerService.setWindowsForAccessibilityCallback(
1345                    mWindowsForAccessibilityCallback);
1346        }
1347    }
1348
1349    private void updateLegacyCapabilities(UserState userState) {
1350        // Up to JB-MR1 we had a white list with services that can enable touch
1351        // exploration. When a service is first started we show a dialog to the
1352        // use to get a permission to white list the service.
1353        final int installedServiceCount = userState.mInstalledServices.size();
1354        for (int i = 0; i < installedServiceCount; i++) {
1355            AccessibilityServiceInfo serviceInfo = userState.mInstalledServices.get(i);
1356            ResolveInfo resolveInfo = serviceInfo.getResolveInfo();
1357            if ((serviceInfo.getCapabilities()
1358                        & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) == 0
1359                    && resolveInfo.serviceInfo.applicationInfo.targetSdkVersion
1360                        <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
1361                ComponentName componentName = new ComponentName(
1362                        resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
1363                if (userState.mTouchExplorationGrantedServices.contains(componentName)) {
1364                    serviceInfo.setCapabilities(serviceInfo.getCapabilities()
1365                            | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION);
1366                }
1367            }
1368        }
1369    }
1370
1371    private void updateFilterKeyEventsLocked(UserState userState) {
1372        final int serviceCount = userState.mBoundServices.size();
1373        for (int i = 0; i < serviceCount; i++) {
1374            Service service = userState.mBoundServices.get(i);
1375            if (service.mRequestFilterKeyEvents
1376                    && (service.mAccessibilityServiceInfo.getCapabilities()
1377                            & AccessibilityServiceInfo
1378                            .CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) != 0) {
1379                userState.mIsFilterKeyEventsEnabled = true;
1380                return;
1381            }
1382        }
1383        userState.mIsFilterKeyEventsEnabled = false;
1384    }
1385
1386    private void updateServicesLocked(UserState userState) {
1387        if (userState.mIsAccessibilityEnabled) {
1388            manageServicesLocked(userState);
1389        } else {
1390            unbindAllServicesLocked(userState);
1391        }
1392    }
1393
1394    private boolean readConfigurationForUserStateLocked(UserState userState) {
1395        boolean somthingChanged = false;
1396        somthingChanged |= readAccessibilityEnabledSettingLocked(userState);
1397        somthingChanged |= readInstalledAccessibilityServiceLocked(userState);
1398        somthingChanged |= readEnabledAccessibilityServicesLocked(userState);
1399        somthingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
1400        somthingChanged |= readTouchExplorationEnabledSettingLocked(userState);
1401        somthingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
1402        somthingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
1403        somthingChanged |= readDisplayColorAdjustmentSettingsLocked(userState);
1404        return somthingChanged;
1405    }
1406
1407    private boolean readAccessibilityEnabledSettingLocked(UserState userState) {
1408        final boolean accessibilityEnabled = Settings.Secure.getIntForUser(
1409               mContext.getContentResolver(),
1410               Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1;
1411        if (accessibilityEnabled != userState.mIsAccessibilityEnabled) {
1412            userState.mIsAccessibilityEnabled = accessibilityEnabled;
1413            return true;
1414        }
1415        return false;
1416    }
1417
1418    private boolean readTouchExplorationEnabledSettingLocked(UserState userState) {
1419        final boolean touchExplorationEnabled = Settings.Secure.getIntForUser(
1420                mContext.getContentResolver(),
1421                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1;
1422        if (touchExplorationEnabled != userState.mIsTouchExplorationEnabled) {
1423            userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
1424            return true;
1425        }
1426        return false;
1427    }
1428
1429    private boolean readDisplayMagnificationEnabledSettingLocked(UserState userState) {
1430        final boolean displayMagnificationEnabled = Settings.Secure.getIntForUser(
1431                mContext.getContentResolver(),
1432                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
1433                0, userState.mUserId) == 1;
1434        if (displayMagnificationEnabled != userState.mIsDisplayMagnificationEnabled) {
1435            userState.mIsDisplayMagnificationEnabled = displayMagnificationEnabled;
1436            return true;
1437        }
1438        return false;
1439    }
1440
1441    private boolean readEnhancedWebAccessibilityEnabledChangedLocked(UserState userState) {
1442         final boolean enhancedWeAccessibilityEnabled = Settings.Secure.getIntForUser(
1443                mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
1444                0, userState.mUserId) == 1;
1445         if (enhancedWeAccessibilityEnabled != userState.mIsEnhancedWebAccessibilityEnabled) {
1446             userState.mIsEnhancedWebAccessibilityEnabled = enhancedWeAccessibilityEnabled;
1447             return true;
1448         }
1449         return false;
1450    }
1451
1452    private boolean readDisplayColorAdjustmentSettingsLocked(UserState userState) {
1453        final boolean displayAdjustmentsEnabled = DisplayAdjustmentUtils.hasAdjustments(mContext,
1454                userState.mUserId);
1455        if (displayAdjustmentsEnabled != userState.mHasDisplayColorAdjustment) {
1456            userState.mHasDisplayColorAdjustment = displayAdjustmentsEnabled;
1457            return true;
1458        }
1459        // If display adjustment is enabled, always assume there was a change in
1460        // the adjustment settings.
1461        return displayAdjustmentsEnabled;
1462    }
1463
1464    private void updateTouchExplorationLocked(UserState userState) {
1465        boolean enabled = false;
1466        final int serviceCount = userState.mBoundServices.size();
1467        for (int i = 0; i < serviceCount; i++) {
1468            Service service = userState.mBoundServices.get(i);
1469            if (canRequestAndRequestsTouchExplorationLocked(service)) {
1470                enabled = true;
1471                break;
1472            }
1473        }
1474        if (enabled != userState.mIsTouchExplorationEnabled) {
1475            userState.mIsTouchExplorationEnabled = enabled;
1476            Settings.Secure.putIntForUser(mContext.getContentResolver(),
1477                    Settings.Secure.TOUCH_EXPLORATION_ENABLED, enabled ? 1 : 0,
1478                    userState.mUserId);
1479        }
1480    }
1481
1482    private boolean canRequestAndRequestsTouchExplorationLocked(Service service) {
1483        // Service not ready or cannot request the feature - well nothing to do.
1484        if (!service.canReceiveEventsLocked() || !service.mRequestTouchExplorationMode) {
1485            return false;
1486        }
1487        // UI test automation service can always enable it.
1488        if (service.mIsAutomation) {
1489            return true;
1490        }
1491        if (service.mResolveInfo.serviceInfo.applicationInfo.targetSdkVersion
1492                <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
1493            // Up to JB-MR1 we had a white list with services that can enable touch
1494            // exploration. When a service is first started we show a dialog to the
1495            // use to get a permission to white list the service.
1496            UserState userState = getUserStateLocked(service.mUserId);
1497            if (userState.mTouchExplorationGrantedServices.contains(service.mComponentName)) {
1498                return true;
1499            } else if (mEnableTouchExplorationDialog == null
1500                    || !mEnableTouchExplorationDialog.isShowing()) {
1501                mMainHandler.obtainMessage(
1502                        MainHandler.MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG,
1503                        service).sendToTarget();
1504            }
1505        } else {
1506            // Starting in JB-MR2 we request an accessibility service to declare
1507            // certain capabilities in its meta-data to allow it to enable the
1508            // corresponding features.
1509            if ((service.mAccessibilityServiceInfo.getCapabilities()
1510                    & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0) {
1511                return true;
1512            }
1513        }
1514        return false;
1515    }
1516
1517    private void updateEnhancedWebAccessibilityLocked(UserState userState) {
1518        boolean enabled = false;
1519        final int serviceCount = userState.mBoundServices.size();
1520        for (int i = 0; i < serviceCount; i++) {
1521            Service service = userState.mBoundServices.get(i);
1522            if (canRequestAndRequestsEnhancedWebAccessibilityLocked(service)) {
1523                enabled = true;
1524                break;
1525            }
1526        }
1527        if (enabled != userState.mIsEnhancedWebAccessibilityEnabled) {
1528            userState.mIsEnhancedWebAccessibilityEnabled = enabled;
1529            Settings.Secure.putIntForUser(mContext.getContentResolver(),
1530                    Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, enabled ? 1 : 0,
1531                    userState.mUserId);
1532        }
1533    }
1534
1535    private boolean canRequestAndRequestsEnhancedWebAccessibilityLocked(Service service) {
1536        if (!service.canReceiveEventsLocked() || !service.mRequestEnhancedWebAccessibility ) {
1537            return false;
1538        }
1539        if (service.mIsAutomation || (service.mAccessibilityServiceInfo.getCapabilities()
1540               & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0) {
1541            return true;
1542        }
1543        return false;
1544    }
1545
1546    private void updateDisplayColorAdjustmentSettingsLocked(UserState userState) {
1547        DisplayAdjustmentUtils.applyAdjustments(mContext, userState.mUserId);
1548    }
1549
1550    @Override
1551    public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
1552        mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
1553        synchronized (mLock) {
1554            pw.println("ACCESSIBILITY MANAGER (dumpsys accessibility)");
1555            pw.println();
1556            final int userCount = mUserStates.size();
1557            for (int i = 0; i < userCount; i++) {
1558                UserState userState = mUserStates.valueAt(i);
1559                pw.append("User state[attributes:{id=" + userState.mUserId);
1560                pw.append(", currentUser=" + (userState.mUserId == mCurrentUserId));
1561                pw.append(", accessibilityEnabled=" + userState.mIsAccessibilityEnabled);
1562                pw.append(", touchExplorationEnabled=" + userState.mIsTouchExplorationEnabled);
1563                pw.append(", displayMagnificationEnabled="
1564                        + userState.mIsDisplayMagnificationEnabled);
1565                if (userState.mUiAutomationService != null) {
1566                    pw.append(", ");
1567                    userState.mUiAutomationService.dump(fd, pw, args);
1568                    pw.println();
1569                }
1570                pw.append("}");
1571                pw.println();
1572                pw.append("           services:{");
1573                final int serviceCount = userState.mBoundServices.size();
1574                for (int j = 0; j < serviceCount; j++) {
1575                    if (j > 0) {
1576                        pw.append(", ");
1577                        pw.println();
1578                        pw.append("                     ");
1579                    }
1580                    Service service = userState.mBoundServices.get(j);
1581                    service.dump(fd, pw, args);
1582                }
1583                pw.println("}]");
1584                pw.println();
1585            }
1586        }
1587    }
1588
1589    private class AccessibilityConnectionWrapper implements DeathRecipient {
1590        private final int mWindowId;
1591        private final int mUserId;
1592        private final IAccessibilityInteractionConnection mConnection;
1593
1594        public AccessibilityConnectionWrapper(int windowId,
1595                IAccessibilityInteractionConnection connection, int userId) {
1596            mWindowId = windowId;
1597            mUserId = userId;
1598            mConnection = connection;
1599        }
1600
1601        public void linkToDeath() throws RemoteException {
1602            mConnection.asBinder().linkToDeath(this, 0);
1603        }
1604
1605        public void unlinkToDeath() {
1606            mConnection.asBinder().unlinkToDeath(this, 0);
1607        }
1608
1609        @Override
1610        public void binderDied() {
1611            unlinkToDeath();
1612            synchronized (mLock) {
1613                removeAccessibilityInteractionConnectionLocked(mWindowId, mUserId);
1614            }
1615        }
1616    }
1617
1618    private final class MainHandler extends Handler {
1619        public static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 1;
1620        public static final int MSG_SEND_STATE_TO_CLIENTS = 2;
1621        public static final int MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER = 3;
1622        public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 5;
1623        public static final int MSG_UPDATE_INPUT_FILTER = 6;
1624        public static final int MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG = 7;
1625        public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8;
1626
1627        public MainHandler(Looper looper) {
1628            super(looper);
1629        }
1630
1631        @Override
1632        public void handleMessage(Message msg) {
1633            final int type = msg.what;
1634            switch (type) {
1635                case MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER: {
1636                    AccessibilityEvent event = (AccessibilityEvent) msg.obj;
1637                    synchronized (mLock) {
1638                        if (mHasInputFilter && mInputFilter != null) {
1639                            mInputFilter.notifyAccessibilityEvent(event);
1640                        }
1641                    }
1642                    event.recycle();
1643                } break;
1644
1645                case MSG_SEND_KEY_EVENT_TO_INPUT_FILTER: {
1646                    KeyEvent event = (KeyEvent) msg.obj;
1647                    final int policyFlags = msg.arg1;
1648                    synchronized (mLock) {
1649                        if (mHasInputFilter && mInputFilter != null) {
1650                            mInputFilter.sendInputEvent(event, policyFlags);
1651                        }
1652                    }
1653                    event.recycle();
1654                } break;
1655
1656                case MSG_SEND_STATE_TO_CLIENTS: {
1657                    final int clientState = msg.arg1;
1658                    final int userId = msg.arg2;
1659                    sendStateToClients(clientState, mGlobalClients);
1660                    sendStateToClientsForUser(clientState, userId);
1661                } break;
1662
1663                case MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER: {
1664                    final int userId = msg.arg1;
1665                    sendStateToClientsForUser(0, userId);
1666                } break;
1667
1668                case MSG_ANNOUNCE_NEW_USER_IF_NEEDED: {
1669                    announceNewUserIfNeeded();
1670                } break;
1671
1672                case MSG_UPDATE_INPUT_FILTER: {
1673                    UserState userState = (UserState) msg.obj;
1674                    updateInputFilter(userState);
1675                } break;
1676
1677                case MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG: {
1678                    Service service = (Service) msg.obj;
1679                    showEnableTouchExplorationDialog(service);
1680                } break;
1681            }
1682        }
1683
1684        private void announceNewUserIfNeeded() {
1685            synchronized (mLock) {
1686                UserState userState = getCurrentUserStateLocked();
1687                if (userState.mIsAccessibilityEnabled) {
1688                    UserManager userManager = (UserManager) mContext.getSystemService(
1689                            Context.USER_SERVICE);
1690                    String message = mContext.getString(R.string.user_switched,
1691                            userManager.getUserInfo(mCurrentUserId).name);
1692                    AccessibilityEvent event = AccessibilityEvent.obtain(
1693                            AccessibilityEvent.TYPE_ANNOUNCEMENT);
1694                    event.getText().add(message);
1695                    sendAccessibilityEvent(event, mCurrentUserId);
1696                }
1697            }
1698        }
1699
1700        private void sendStateToClientsForUser(int clientState, int userId) {
1701            final UserState userState;
1702            synchronized (mLock) {
1703                userState = getUserStateLocked(userId);
1704            }
1705            sendStateToClients(clientState, userState.mClients);
1706        }
1707
1708        private void sendStateToClients(int clientState,
1709                RemoteCallbackList<IAccessibilityManagerClient> clients) {
1710            try {
1711                final int userClientCount = clients.beginBroadcast();
1712                for (int i = 0; i < userClientCount; i++) {
1713                    IAccessibilityManagerClient client = clients.getBroadcastItem(i);
1714                    try {
1715                        client.setState(clientState);
1716                    } catch (RemoteException re) {
1717                        /* ignore */
1718                    }
1719                }
1720            } finally {
1721                clients.finishBroadcast();
1722            }
1723        }
1724    }
1725
1726    private PendingEvent obtainPendingEventLocked(KeyEvent event, int policyFlags, int sequence) {
1727        PendingEvent pendingEvent = mPendingEventPool.acquire();
1728        if (pendingEvent == null) {
1729            pendingEvent = new PendingEvent();
1730        }
1731        pendingEvent.event = event;
1732        pendingEvent.policyFlags = policyFlags;
1733        pendingEvent.sequence = sequence;
1734        return pendingEvent;
1735    }
1736
1737    private void recyclePendingEventLocked(PendingEvent pendingEvent) {
1738        pendingEvent.clear();
1739        mPendingEventPool.release(pendingEvent);
1740    }
1741
1742    private int findWindowIdLocked(IBinder token) {
1743        final int globalIndex = mGlobalWindowTokens.indexOfValue(token);
1744        if (globalIndex >= 0) {
1745            return mGlobalWindowTokens.keyAt(globalIndex);
1746        }
1747        UserState userState = getCurrentUserStateLocked();
1748        final int userIndex = userState.mWindowTokens.indexOfValue(token);
1749        if (userIndex >= 0) {
1750            return userState.mWindowTokens.keyAt(userIndex);
1751        }
1752        return -1;
1753    }
1754
1755    /**
1756     * This class represents an accessibility service. It stores all per service
1757     * data required for the service management, provides API for starting/stopping the
1758     * service and is responsible for adding/removing the service in the data structures
1759     * for service management. The class also exposes configuration interface that is
1760     * passed to the service it represents as soon it is bound. It also serves as the
1761     * connection for the service.
1762     */
1763    class Service extends IAccessibilityServiceConnection.Stub
1764            implements ServiceConnection, DeathRecipient {;
1765
1766        final int mUserId;
1767
1768        int mId = 0;
1769
1770        AccessibilityServiceInfo mAccessibilityServiceInfo;
1771
1772        IBinder mService;
1773
1774        IAccessibilityServiceClient mServiceInterface;
1775
1776        int mEventTypes;
1777
1778        int mFeedbackType;
1779
1780        Set<String> mPackageNames = new HashSet<String>();
1781
1782        boolean mIsDefault;
1783
1784        boolean mRequestTouchExplorationMode;
1785
1786        boolean mRequestEnhancedWebAccessibility;
1787
1788        boolean mRequestFilterKeyEvents;
1789
1790        boolean mRetrieveInteractiveWindows;
1791
1792        int mFetchFlags;
1793
1794        long mNotificationTimeout;
1795
1796        ComponentName mComponentName;
1797
1798        Intent mIntent;
1799
1800        boolean mIsAutomation;
1801
1802        final Rect mTempBounds1 = new Rect();
1803
1804        final Rect mTempBounds2 = new Rect();
1805
1806        final ResolveInfo mResolveInfo;
1807
1808        // the events pending events to be dispatched to this service
1809        final SparseArray<AccessibilityEvent> mPendingEvents =
1810            new SparseArray<AccessibilityEvent>();
1811
1812        final KeyEventDispatcher mKeyEventDispatcher = new KeyEventDispatcher();
1813
1814        final SparseArray<AccessibilityWindowInfo> mIntrospectedWindows =
1815                new SparseArray<AccessibilityWindowInfo>();
1816
1817        boolean mWasConnectedAndDied;
1818
1819        // Handler only for dispatching accessibility events since we use event
1820        // types as message types allowing us to remove messages per event type.
1821        public Handler mEventDispatchHandler = new Handler(mMainHandler.getLooper()) {
1822            @Override
1823            public void handleMessage(Message message) {
1824                final int eventType =  message.what;
1825                notifyAccessibilityEventInternal(eventType);
1826            }
1827        };
1828
1829        // Handler for scheduling method invocations on the main thread.
1830        public InvocationHandler mInvocationHandler = new InvocationHandler(
1831                mMainHandler.getLooper());
1832
1833        public Service(int userId, ComponentName componentName,
1834                AccessibilityServiceInfo accessibilityServiceInfo) {
1835            mUserId = userId;
1836            mResolveInfo = accessibilityServiceInfo.getResolveInfo();
1837            mId = sIdCounter++;
1838            mComponentName = componentName;
1839            mAccessibilityServiceInfo = accessibilityServiceInfo;
1840            mIsAutomation = (sFakeAccessibilityServiceComponentName.equals(componentName));
1841            if (!mIsAutomation) {
1842                mIntent = new Intent().setComponent(mComponentName);
1843                mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
1844                        com.android.internal.R.string.accessibility_binding_label);
1845                mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
1846                        mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
1847            }
1848            setDynamicallyConfigurableProperties(accessibilityServiceInfo);
1849        }
1850
1851        public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) {
1852            mEventTypes = info.eventTypes;
1853            mFeedbackType = info.feedbackType;
1854            String[] packageNames = info.packageNames;
1855            if (packageNames != null) {
1856                mPackageNames.addAll(Arrays.asList(packageNames));
1857            }
1858            mNotificationTimeout = info.notificationTimeout;
1859            mIsDefault = (info.flags & DEFAULT) != 0;
1860
1861            if (mIsAutomation || info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion
1862                    >= Build.VERSION_CODES.JELLY_BEAN) {
1863                if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) {
1864                    mFetchFlags |= AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
1865                } else {
1866                    mFetchFlags &= ~AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
1867                }
1868            }
1869
1870            if ((info.flags & AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) != 0) {
1871                mFetchFlags |= AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
1872            } else {
1873                mFetchFlags &= ~AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
1874            }
1875
1876            mRequestTouchExplorationMode = (info.flags
1877                    & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
1878            mRequestEnhancedWebAccessibility = (info.flags
1879                    & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0;
1880            mRequestFilterKeyEvents = (info.flags
1881                    & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0;
1882            mRetrieveInteractiveWindows = (info.flags
1883                    & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0;
1884
1885            if (!mRetrieveInteractiveWindows) {
1886                clearIntrospectedWindows();
1887            }
1888        }
1889
1890        /**
1891         * Binds to the accessibility service.
1892         *
1893         * @return True if binding is successful.
1894         */
1895        public boolean bindLocked() {
1896            UserState userState = getUserStateLocked(mUserId);
1897            if (!mIsAutomation) {
1898                if (mService == null && mContext.bindServiceAsUser(
1899                        mIntent, this, Context.BIND_AUTO_CREATE, new UserHandle(mUserId))) {
1900                    userState.mBindingServices.add(mComponentName);
1901                }
1902            } else {
1903                userState.mBindingServices.add(mComponentName);
1904                mService = userState.mUiAutomationServiceClient.asBinder();
1905                onServiceConnected(mComponentName, mService);
1906                userState.mUiAutomationService = this;
1907            }
1908            return false;
1909        }
1910
1911        /**
1912         * Unbinds form the accessibility service and removes it from the data
1913         * structures for service management.
1914         *
1915         * @return True if unbinding is successful.
1916         */
1917        public boolean unbindLocked() {
1918            if (mService == null) {
1919                return false;
1920            }
1921            UserState userState = getUserStateLocked(mUserId);
1922            mKeyEventDispatcher.flush();
1923            if (!mIsAutomation) {
1924                mContext.unbindService(this);
1925            } else {
1926                userState.destroyUiAutomationService();
1927            }
1928            removeServiceLocked(this, userState);
1929            resetLocked();
1930            return true;
1931        }
1932
1933        public boolean canReceiveEventsLocked() {
1934            return (mEventTypes != 0 && mFeedbackType != 0 && mService != null);
1935        }
1936
1937        @Override
1938        public void setOnKeyEventResult(boolean handled, int sequence) {
1939            mKeyEventDispatcher.setOnKeyEventResult(handled, sequence);
1940        }
1941
1942        @Override
1943        public AccessibilityServiceInfo getServiceInfo() {
1944            synchronized (mLock) {
1945                return mAccessibilityServiceInfo;
1946            }
1947        }
1948
1949        @Override
1950        public void setServiceInfo(AccessibilityServiceInfo info) {
1951            final long identity = Binder.clearCallingIdentity();
1952            try {
1953                synchronized (mLock) {
1954                    // If the XML manifest had data to configure the service its info
1955                    // should be already set. In such a case update only the dynamically
1956                    // configurable properties.
1957                    AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
1958                    if (oldInfo != null) {
1959                        oldInfo.updateDynamicallyConfigurableProperties(info);
1960                        setDynamicallyConfigurableProperties(oldInfo);
1961                    } else {
1962                        setDynamicallyConfigurableProperties(info);
1963                    }
1964                    UserState userState = getUserStateLocked(mUserId);
1965                    onUserStateChangedLocked(userState);
1966                }
1967            } finally {
1968                Binder.restoreCallingIdentity(identity);
1969            }
1970        }
1971
1972        @Override
1973        public void onServiceConnected(ComponentName componentName, IBinder service) {
1974            synchronized (mLock) {
1975                mService = service;
1976                mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
1977                UserState userState = getUserStateLocked(mUserId);
1978                addServiceLocked(this, userState);
1979                if (userState.mBindingServices.contains(mComponentName) || mWasConnectedAndDied) {
1980                    userState.mBindingServices.remove(mComponentName);
1981                    mWasConnectedAndDied = false;
1982                    try {
1983                       mServiceInterface.setConnection(this, mId);
1984                       onUserStateChangedLocked(userState);
1985                    } catch (RemoteException re) {
1986                        Slog.w(LOG_TAG, "Error while setting connection for service: "
1987                                + service, re);
1988                        binderDied();
1989                    }
1990                } else {
1991                    binderDied();
1992                }
1993            }
1994        }
1995
1996        @Override
1997        public List<AccessibilityWindowInfo> getWindows() {
1998            synchronized (mLock) {
1999                final int resolvedUserId = mSecurityPolicy
2000                        .resolveCallingUserIdEnforcingPermissionsLocked(
2001                                UserHandle.getCallingUserId());
2002                if (resolvedUserId != mCurrentUserId) {
2003                    return null;
2004                }
2005                final boolean permissionGranted =
2006                        mSecurityPolicy.canRetrieveWindowsLocked(this);
2007                if (!permissionGranted) {
2008                    return null;
2009                }
2010                List<AccessibilityWindowInfo> windows = new ArrayList<AccessibilityWindowInfo>();
2011                final int windowCount = mSecurityPolicy.mWindows.size();
2012                for (int i = 0; i < windowCount; i++) {
2013                    AccessibilityWindowInfo window = mSecurityPolicy.mWindows.get(i);
2014                    AccessibilityWindowInfo windowClone =
2015                            AccessibilityWindowInfo.obtain(window);
2016                    windowClone.setConnectionId(mId);
2017                    mIntrospectedWindows.put(window.getId(), windowClone);
2018                    windows.add(windowClone);
2019                }
2020                return windows;
2021            }
2022        }
2023
2024        @Override
2025        public AccessibilityWindowInfo getWindow(int windowId) {
2026            synchronized (mLock) {
2027                final int resolvedUserId = mSecurityPolicy
2028                        .resolveCallingUserIdEnforcingPermissionsLocked(
2029                                UserHandle.getCallingUserId());
2030                if (resolvedUserId != mCurrentUserId) {
2031                    return null;
2032                }
2033                final boolean permissionGranted =
2034                        mSecurityPolicy.canRetrieveWindowsLocked(this);
2035                if (!permissionGranted) {
2036                    return null;
2037                }
2038                AccessibilityWindowInfo window = mSecurityPolicy.findWindowById(windowId);
2039                if (window != null) {
2040                    AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window);
2041                    windowClone.setConnectionId(mId);
2042                    mIntrospectedWindows.put(windowId, windowClone);
2043                    return windowClone;
2044                }
2045                return null;
2046            }
2047        }
2048
2049        @Override
2050        public boolean findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
2051                long accessibilityNodeId, String viewIdResName, int interactionId,
2052                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
2053                throws RemoteException {
2054            final int resolvedWindowId;
2055            IAccessibilityInteractionConnection connection = null;
2056            synchronized (mLock) {
2057                final int resolvedUserId = mSecurityPolicy
2058                        .resolveCallingUserIdEnforcingPermissionsLocked(
2059                                UserHandle.getCallingUserId());
2060                if (resolvedUserId != mCurrentUserId) {
2061                    return false;
2062                }
2063                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
2064                final boolean permissionGranted =
2065                        mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
2066                if (!permissionGranted) {
2067                    return false;
2068                } else {
2069                    connection = getConnectionLocked(resolvedWindowId);
2070                    if (connection == null) {
2071                        return false;
2072                    }
2073                }
2074            }
2075            final int interrogatingPid = Binder.getCallingPid();
2076            final long identityToken = Binder.clearCallingIdentity();
2077            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
2078            try {
2079                connection.findAccessibilityNodeInfosByViewId(accessibilityNodeId,
2080                        viewIdResName, interactionId, callback, mFetchFlags, interrogatingPid,
2081                        interrogatingTid, spec);
2082                return true;
2083            } catch (RemoteException re) {
2084                if (DEBUG) {
2085                    Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
2086                }
2087            } finally {
2088                Binder.restoreCallingIdentity(identityToken);
2089            }
2090            return false;
2091        }
2092
2093        @Override
2094        public boolean findAccessibilityNodeInfosByText(int accessibilityWindowId,
2095                long accessibilityNodeId, String text, int interactionId,
2096                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
2097                throws RemoteException {
2098            final int resolvedWindowId;
2099            IAccessibilityInteractionConnection connection = null;
2100            synchronized (mLock) {
2101                final int resolvedUserId = mSecurityPolicy
2102                        .resolveCallingUserIdEnforcingPermissionsLocked(
2103                        UserHandle.getCallingUserId());
2104                if (resolvedUserId != mCurrentUserId) {
2105                    return false;
2106                }
2107                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
2108                final boolean permissionGranted =
2109                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
2110                if (!permissionGranted) {
2111                    return false;
2112                } else {
2113                    connection = getConnectionLocked(resolvedWindowId);
2114                    if (connection == null) {
2115                        return false;
2116                    }
2117                }
2118            }
2119            final int interrogatingPid = Binder.getCallingPid();
2120            final long identityToken = Binder.clearCallingIdentity();
2121            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
2122            try {
2123                connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
2124                        interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
2125                        spec);
2126                return true;
2127            } catch (RemoteException re) {
2128                if (DEBUG) {
2129                    Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
2130                }
2131            } finally {
2132                Binder.restoreCallingIdentity(identityToken);
2133            }
2134            return false;
2135        }
2136
2137        @Override
2138        public boolean findAccessibilityNodeInfoByAccessibilityId(
2139                int accessibilityWindowId, long accessibilityNodeId, int interactionId,
2140                IAccessibilityInteractionConnectionCallback callback, int flags,
2141                long interrogatingTid) throws RemoteException {
2142            final int resolvedWindowId;
2143            IAccessibilityInteractionConnection connection = null;
2144            synchronized (mLock) {
2145                final int resolvedUserId = mSecurityPolicy
2146                        .resolveCallingUserIdEnforcingPermissionsLocked(
2147                        UserHandle.getCallingUserId());
2148                if (resolvedUserId != mCurrentUserId) {
2149                    return false;
2150                }
2151                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
2152                final boolean permissionGranted =
2153                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
2154                if (!permissionGranted) {
2155                    return false;
2156                } else {
2157                    connection = getConnectionLocked(resolvedWindowId);
2158                    if (connection == null) {
2159                        return false;
2160                    }
2161                }
2162            }
2163            final int interrogatingPid = Binder.getCallingPid();
2164            final long identityToken = Binder.clearCallingIdentity();
2165            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
2166            try {
2167                connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
2168                        interactionId, callback, mFetchFlags | flags, interrogatingPid,
2169                        interrogatingTid, spec);
2170                return true;
2171            } catch (RemoteException re) {
2172                if (DEBUG) {
2173                    Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
2174                }
2175            } finally {
2176                Binder.restoreCallingIdentity(identityToken);
2177            }
2178            return false;
2179        }
2180
2181        @Override
2182        public boolean findFocus(int accessibilityWindowId, long accessibilityNodeId,
2183                int focusType, int interactionId,
2184                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
2185                throws RemoteException {
2186            final int resolvedWindowId;
2187            IAccessibilityInteractionConnection connection = null;
2188            synchronized (mLock) {
2189                final int resolvedUserId = mSecurityPolicy
2190                        .resolveCallingUserIdEnforcingPermissionsLocked(
2191                        UserHandle.getCallingUserId());
2192                if (resolvedUserId != mCurrentUserId) {
2193                    return false;
2194                }
2195                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
2196                final boolean permissionGranted =
2197                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
2198                if (!permissionGranted) {
2199                    return false;
2200                } else {
2201                    connection = getConnectionLocked(resolvedWindowId);
2202                    if (connection == null) {
2203                        return false;
2204                    }
2205                }
2206            }
2207            final int interrogatingPid = Binder.getCallingPid();
2208            final long identityToken = Binder.clearCallingIdentity();
2209            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
2210            try {
2211                connection.findFocus(accessibilityNodeId, focusType, interactionId, callback,
2212                        mFetchFlags, interrogatingPid, interrogatingTid, spec);
2213                return true;
2214            } catch (RemoteException re) {
2215                if (DEBUG) {
2216                    Slog.e(LOG_TAG, "Error calling findAccessibilityFocus()");
2217                }
2218            } finally {
2219                Binder.restoreCallingIdentity(identityToken);
2220            }
2221            return false;
2222        }
2223
2224        @Override
2225        public boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId,
2226                int direction, int interactionId,
2227                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
2228                throws RemoteException {
2229            final int resolvedWindowId;
2230            IAccessibilityInteractionConnection connection = null;
2231            synchronized (mLock) {
2232                final int resolvedUserId = mSecurityPolicy
2233                        .resolveCallingUserIdEnforcingPermissionsLocked(
2234                        UserHandle.getCallingUserId());
2235                if (resolvedUserId != mCurrentUserId) {
2236                    return false;
2237                }
2238                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
2239                final boolean permissionGranted =
2240                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
2241                if (!permissionGranted) {
2242                    return false;
2243                } else {
2244                    connection = getConnectionLocked(resolvedWindowId);
2245                    if (connection == null) {
2246                        return false;
2247                    }
2248                }
2249            }
2250            final int interrogatingPid = Binder.getCallingPid();
2251            final long identityToken = Binder.clearCallingIdentity();
2252            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
2253            try {
2254                connection.focusSearch(accessibilityNodeId, direction, interactionId, callback,
2255                        mFetchFlags, interrogatingPid, interrogatingTid, spec);
2256                return true;
2257            } catch (RemoteException re) {
2258                if (DEBUG) {
2259                    Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
2260                }
2261            } finally {
2262                Binder.restoreCallingIdentity(identityToken);
2263            }
2264            return false;
2265        }
2266
2267        @Override
2268        public boolean performAccessibilityAction(int accessibilityWindowId,
2269                long accessibilityNodeId, int action, Bundle arguments, int interactionId,
2270                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
2271                throws RemoteException {
2272            final int resolvedWindowId;
2273            IAccessibilityInteractionConnection connection = null;
2274            synchronized (mLock) {
2275                final int resolvedUserId = mSecurityPolicy
2276                        .resolveCallingUserIdEnforcingPermissionsLocked(
2277                        UserHandle.getCallingUserId());
2278                if (resolvedUserId != mCurrentUserId) {
2279                    return false;
2280                }
2281                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
2282                final boolean permissionGranted = mSecurityPolicy.canPerformActionLocked(this,
2283                        resolvedWindowId, action, arguments);
2284                if (!permissionGranted) {
2285                    return false;
2286                } else {
2287                    connection = getConnectionLocked(resolvedWindowId);
2288                    if (connection == null) {
2289                        return false;
2290                    }
2291                }
2292            }
2293            final int interrogatingPid = Binder.getCallingPid();
2294            final long identityToken = Binder.clearCallingIdentity();
2295            try {
2296                connection.performAccessibilityAction(accessibilityNodeId, action, arguments,
2297                        interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid);
2298            } catch (RemoteException re) {
2299                if (DEBUG) {
2300                    Slog.e(LOG_TAG, "Error calling performAccessibilityAction()");
2301                }
2302            } finally {
2303                Binder.restoreCallingIdentity(identityToken);
2304            }
2305            return true;
2306        }
2307
2308        public boolean performGlobalAction(int action) {
2309            synchronized (mLock) {
2310                final int resolvedUserId = mSecurityPolicy
2311                        .resolveCallingUserIdEnforcingPermissionsLocked(
2312                        UserHandle.getCallingUserId());
2313                if (resolvedUserId != mCurrentUserId) {
2314                    return false;
2315                }
2316            }
2317            final long identity = Binder.clearCallingIdentity();
2318            try {
2319                switch (action) {
2320                    case AccessibilityService.GLOBAL_ACTION_BACK: {
2321                        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK);
2322                    } return true;
2323                    case AccessibilityService.GLOBAL_ACTION_HOME: {
2324                        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME);
2325                    } return true;
2326                    case AccessibilityService.GLOBAL_ACTION_RECENTS: {
2327                        openRecents();
2328                    } return true;
2329                    case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: {
2330                        expandNotifications();
2331                    } return true;
2332                    case AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS: {
2333                        expandQuickSettings();
2334                    } return true;
2335                }
2336                return false;
2337            } finally {
2338                Binder.restoreCallingIdentity(identity);
2339            }
2340        }
2341
2342        @Override
2343        public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
2344            mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
2345            synchronized (mLock) {
2346                pw.append("Service[label=" + mAccessibilityServiceInfo.getResolveInfo()
2347                        .loadLabel(mContext.getPackageManager()));
2348                pw.append(", feedbackType"
2349                        + AccessibilityServiceInfo.feedbackTypeToString(mFeedbackType));
2350                pw.append(", capabilities=" + mAccessibilityServiceInfo.getCapabilities());
2351                pw.append(", eventTypes="
2352                        + AccessibilityEvent.eventTypeToString(mEventTypes));
2353                pw.append(", notificationTimeout=" + mNotificationTimeout);
2354                pw.append("]");
2355            }
2356        }
2357
2358        @Override
2359        public void onServiceDisconnected(ComponentName componentName) {
2360            /* do nothing - #binderDied takes care */
2361        }
2362
2363        public void linkToOwnDeathLocked() throws RemoteException {
2364            mService.linkToDeath(this, 0);
2365        }
2366
2367        public void unlinkToOwnDeathLocked() {
2368            mService.unlinkToDeath(this, 0);
2369        }
2370
2371        public void resetLocked() {
2372            try {
2373                // Clear the proxy in the other process so this
2374                // IAccessibilityServiceConnection can be garbage collected.
2375                mServiceInterface.setConnection(null, mId);
2376            } catch (RemoteException re) {
2377                /* ignore */
2378            }
2379            mService = null;
2380            mServiceInterface = null;
2381        }
2382
2383        public boolean isConnectedLocked() {
2384            return (mService != null);
2385        }
2386
2387        public void binderDied() {
2388            synchronized (mLock) {
2389                // It is possible that this service's package was force stopped during
2390                // whose handling the death recipient is unlinked and still get a call
2391                // on binderDied since the call was made before we unlink but was
2392                // waiting on the lock we held during the force stop handling.
2393                if (!isConnectedLocked()) {
2394                    return;
2395                }
2396                mWasConnectedAndDied = true;
2397                mKeyEventDispatcher.flush();
2398                UserState userState = getUserStateLocked(mUserId);
2399                // The death recipient is unregistered in removeServiceLocked
2400                removeServiceLocked(this, userState);
2401                resetLocked();
2402                if (mIsAutomation) {
2403                    // We no longer have an automation service, so restore
2404                    // the state based on values in the settings database.
2405                    userState.mInstalledServices.remove(mAccessibilityServiceInfo);
2406                    userState.mEnabledServices.remove(mComponentName);
2407                    userState.destroyUiAutomationService();
2408                }
2409            }
2410        }
2411
2412        /**
2413         * Performs a notification for an {@link AccessibilityEvent}.
2414         *
2415         * @param event The event.
2416         */
2417        public void notifyAccessibilityEvent(AccessibilityEvent event) {
2418            synchronized (mLock) {
2419                final int eventType = event.getEventType();
2420                // Make a copy since during dispatch it is possible the event to
2421                // be modified to remove its source if the receiving service does
2422                // not have permission to access the window content.
2423                AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
2424                AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
2425                mPendingEvents.put(eventType, newEvent);
2426
2427                final int what = eventType;
2428                if (oldEvent != null) {
2429                    mEventDispatchHandler.removeMessages(what);
2430                    oldEvent.recycle();
2431                }
2432
2433                Message message = mEventDispatchHandler.obtainMessage(what);
2434                mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout);
2435            }
2436        }
2437
2438        /**
2439         * Notifies an accessibility service client for a scheduled event given the event type.
2440         *
2441         * @param eventType The type of the event to dispatch.
2442         */
2443        private void notifyAccessibilityEventInternal(int eventType) {
2444            IAccessibilityServiceClient listener;
2445            AccessibilityEvent event;
2446
2447            synchronized (mLock) {
2448                listener = mServiceInterface;
2449
2450                // If the service died/was disabled while the message for dispatching
2451                // the accessibility event was propagating the listener may be null.
2452                if (listener == null) {
2453                    return;
2454                }
2455
2456                event = mPendingEvents.get(eventType);
2457
2458                // Check for null here because there is a concurrent scenario in which this
2459                // happens: 1) A binder thread calls notifyAccessibilityServiceDelayedLocked
2460                // which posts a message for dispatching an event. 2) The message is pulled
2461                // from the queue by the handler on the service thread and the latter is
2462                // just about to acquire the lock and call this method. 3) Now another binder
2463                // thread acquires the lock calling notifyAccessibilityServiceDelayedLocked
2464                // so the service thread waits for the lock; 4) The binder thread replaces
2465                // the event with a more recent one (assume the same event type) and posts a
2466                // dispatch request releasing the lock. 5) Now the main thread is unblocked and
2467                // dispatches the event which is removed from the pending ones. 6) And ... now
2468                // the service thread handles the last message posted by the last binder call
2469                // but the event is already dispatched and hence looking it up in the pending
2470                // ones yields null. This check is much simpler that keeping count for each
2471                // event type of each service to catch such a scenario since only one message
2472                // is processed at a time.
2473                if (event == null) {
2474                    return;
2475                }
2476
2477                mPendingEvents.remove(eventType);
2478                if (mSecurityPolicy.canRetrieveWindowContentLocked(this)) {
2479                    event.setConnectionId(mId);
2480                } else {
2481                    event.setSource(null);
2482                }
2483                event.setSealed(true);
2484            }
2485
2486            try {
2487                listener.onAccessibilityEvent(event);
2488                if (DEBUG) {
2489                    Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
2490                }
2491            } catch (RemoteException re) {
2492                Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re);
2493            } finally {
2494                event.recycle();
2495            }
2496        }
2497
2498        public void notifyGesture(int gestureId) {
2499            mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE,
2500                    gestureId, 0).sendToTarget();
2501        }
2502
2503        public void notifyKeyEvent(KeyEvent event, int policyFlags) {
2504            mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_KEY_EVENT,
2505                    policyFlags, 0, event).sendToTarget();
2506        }
2507
2508        public void notifyClearAccessibilityNodeInfoCache() {
2509            clearIntrospectedWindows();
2510            mInvocationHandler.sendEmptyMessage(
2511                    InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE);
2512        }
2513
2514        private void clearIntrospectedWindows() {
2515            final int windowCount = mIntrospectedWindows.size();
2516            for (int i = windowCount - 1; i >= 0; i--) {
2517                mIntrospectedWindows.valueAt(i).recycle();
2518                mIntrospectedWindows.removeAt(i);
2519            }
2520        }
2521
2522        public void notifyWindowsChangedLocked(List<AccessibilityWindowInfo> windows) {
2523            LongArray changedWindows = mTempLongArray;
2524            changedWindows.clear();
2525
2526            // Figure out which windows the service cares about changed.
2527            final int windowCount = windows.size();
2528            for (int i = 0; i < windowCount; i++) {
2529                AccessibilityWindowInfo newState = windows.get(i);
2530                final int windowId = newState.getId();
2531                AccessibilityWindowInfo oldState = mIntrospectedWindows.get(windowId);
2532                if (oldState != null && oldState.changed(newState)) {
2533                    oldState.recycle();
2534                    mIntrospectedWindows.put(newState.getId(),
2535                            AccessibilityWindowInfo.obtain(newState));
2536                    changedWindows.add(windowId);
2537                }
2538            }
2539
2540            // Figure out which windows the service cares about went away.
2541            final int introspectedWindowCount = mIntrospectedWindows.size();
2542            for (int i = introspectedWindowCount - 1; i >= 0; i--) {
2543                AccessibilityWindowInfo window = mIntrospectedWindows.valueAt(i);
2544                if (changedWindows.indexOf(window.getId()) < 0 && !windows.contains(window)) {
2545                    changedWindows.add(window.getId());
2546                    mIntrospectedWindows.removeAt(i);
2547                    window.recycle();
2548                }
2549            }
2550
2551            int[] windowIds = null;
2552
2553            final int changedWindowCount = changedWindows.size();
2554            if (changedWindowCount > 0) {
2555                windowIds = new int[changedWindowCount];
2556                for (int i = 0; i < changedWindowCount; i++) {
2557                    // Cast is fine as we use long array to cache ints.
2558                    windowIds[i] = (int) changedWindows.get(i);
2559                }
2560                changedWindows.clear();
2561            }
2562
2563            mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_WINDOWS_CHANGED,
2564                    windowIds).sendToTarget();
2565        }
2566
2567        private void notifyGestureInternal(int gestureId) {
2568            final IAccessibilityServiceClient listener;
2569            synchronized (mLock) {
2570                listener = mServiceInterface;
2571            }
2572            if (listener != null) {
2573                try {
2574                    listener.onGesture(gestureId);
2575                } catch (RemoteException re) {
2576                    Slog.e(LOG_TAG, "Error during sending gesture " + gestureId
2577                            + " to " + mService, re);
2578                }
2579            }
2580        }
2581
2582        private void notifyKeyEventInternal(KeyEvent event, int policyFlags) {
2583            mKeyEventDispatcher.notifyKeyEvent(event, policyFlags);
2584        }
2585
2586        private void notifyClearAccessibilityCacheInternal() {
2587            final IAccessibilityServiceClient listener;
2588            synchronized (mLock) {
2589                listener = mServiceInterface;
2590            }
2591            if (listener != null) {
2592                try {
2593                    listener.clearAccessibilityCache();
2594                } catch (RemoteException re) {
2595                    Slog.e(LOG_TAG, "Error during requesting accessibility info cache"
2596                            + " to be cleared.", re);
2597                }
2598            }
2599        }
2600
2601        private void notifyWindowsChangedInternal(int[] windowIds) {
2602            final IAccessibilityServiceClient listener;
2603            synchronized (mLock) {
2604                listener = mServiceInterface;
2605            }
2606            if (listener != null) {
2607                try {
2608                    listener.onWindowsChanged(windowIds);
2609                } catch (RemoteException re) {
2610                    Slog.e(LOG_TAG, "Error during sending windows to: " + mService, re);
2611                }
2612            }
2613        }
2614
2615        private void sendDownAndUpKeyEvents(int keyCode) {
2616            final long token = Binder.clearCallingIdentity();
2617
2618            // Inject down.
2619            final long downTime = SystemClock.uptimeMillis();
2620            KeyEvent down = KeyEvent.obtain(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
2621                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
2622                    InputDevice.SOURCE_KEYBOARD, null);
2623            InputManager.getInstance().injectInputEvent(down,
2624                    InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
2625            down.recycle();
2626
2627            // Inject up.
2628            final long upTime = SystemClock.uptimeMillis();
2629            KeyEvent up = KeyEvent.obtain(downTime, upTime, KeyEvent.ACTION_UP, keyCode, 0, 0,
2630                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
2631                    InputDevice.SOURCE_KEYBOARD, null);
2632            InputManager.getInstance().injectInputEvent(up,
2633                    InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
2634            up.recycle();
2635
2636            Binder.restoreCallingIdentity(token);
2637        }
2638
2639        private void expandNotifications() {
2640            final long token = Binder.clearCallingIdentity();
2641
2642            StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
2643                    android.app.Service.STATUS_BAR_SERVICE);
2644            statusBarManager.expandNotificationsPanel();
2645
2646            Binder.restoreCallingIdentity(token);
2647        }
2648
2649        private void expandQuickSettings() {
2650            final long token = Binder.clearCallingIdentity();
2651
2652            StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
2653                    android.app.Service.STATUS_BAR_SERVICE);
2654            statusBarManager.expandSettingsPanel();
2655
2656            Binder.restoreCallingIdentity(token);
2657        }
2658
2659        private void openRecents() {
2660            final long token = Binder.clearCallingIdentity();
2661
2662            IStatusBarService statusBarService = IStatusBarService.Stub.asInterface(
2663                    ServiceManager.getService("statusbar"));
2664            try {
2665                statusBarService.toggleRecentApps();
2666            } catch (RemoteException e) {
2667                Slog.e(LOG_TAG, "Error toggling recent apps.");
2668            }
2669
2670            Binder.restoreCallingIdentity(token);
2671        }
2672
2673        private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
2674            if (DEBUG) {
2675                Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
2676            }
2677            AccessibilityConnectionWrapper wrapper = mGlobalInteractionConnections.get(windowId);
2678            if (wrapper == null) {
2679                wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId);
2680            }
2681            if (wrapper != null && wrapper.mConnection != null) {
2682                return wrapper.mConnection;
2683            }
2684            if (DEBUG) {
2685                Slog.e(LOG_TAG, "No interaction connection to window: " + windowId);
2686            }
2687            return null;
2688        }
2689
2690        private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) {
2691            if (accessibilityWindowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) {
2692                return mSecurityPolicy.mActiveWindowId;
2693            }
2694            return accessibilityWindowId;
2695        }
2696
2697        private MagnificationSpec getCompatibleMagnificationSpec(int windowId) {
2698            IBinder windowToken = mGlobalWindowTokens.get(windowId);
2699            if (windowToken == null) {
2700                windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
2701            }
2702            if (windowToken != null) {
2703                return mWindowManagerService.getCompatibleMagnificationSpecForWindow(
2704                        windowToken);
2705            }
2706            return null;
2707        }
2708
2709        private final class InvocationHandler extends Handler {
2710            public static final int MSG_ON_GESTURE = 1;
2711            public static final int MSG_ON_KEY_EVENT = 2;
2712            public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 3;
2713            public static final int MSG_ON_KEY_EVENT_TIMEOUT = 4;
2714            public static final int MSG_ON_WINDOWS_CHANGED = 5;
2715
2716            public InvocationHandler(Looper looper) {
2717                super(looper, null, true);
2718            }
2719
2720            @Override
2721            public void handleMessage(Message message) {
2722                final int type = message.what;
2723                switch (type) {
2724                    case MSG_ON_GESTURE: {
2725                        final int gestureId = message.arg1;
2726                        notifyGestureInternal(gestureId);
2727                    } break;
2728
2729                    case MSG_ON_KEY_EVENT: {
2730                        KeyEvent event = (KeyEvent) message.obj;
2731                        final int policyFlags = message.arg1;
2732                        notifyKeyEventInternal(event, policyFlags);
2733                    } break;
2734
2735                    case MSG_CLEAR_ACCESSIBILITY_CACHE: {
2736                        notifyClearAccessibilityCacheInternal();
2737                    } break;
2738
2739                    case MSG_ON_KEY_EVENT_TIMEOUT: {
2740                        PendingEvent eventState = (PendingEvent) message.obj;
2741                        setOnKeyEventResult(false, eventState.sequence);
2742                    } break;
2743
2744                    case MSG_ON_WINDOWS_CHANGED: {
2745                        final int[] windowIds = (int[]) message.obj;
2746                        notifyWindowsChangedInternal(windowIds);
2747                    } break;
2748
2749                    default: {
2750                        throw new IllegalArgumentException("Unknown message: " + type);
2751                    }
2752                }
2753            }
2754        }
2755
2756        private final class KeyEventDispatcher {
2757
2758            private static final long ON_KEY_EVENT_TIMEOUT_MILLIS = 500;
2759
2760            private PendingEvent mPendingEvents;
2761
2762            private final InputEventConsistencyVerifier mSentEventsVerifier =
2763                    InputEventConsistencyVerifier.isInstrumentationEnabled()
2764                            ? new InputEventConsistencyVerifier(
2765                                    this, 0, KeyEventDispatcher.class.getSimpleName()) : null;
2766
2767            public void notifyKeyEvent(KeyEvent event, int policyFlags) {
2768                final PendingEvent pendingEvent;
2769
2770                synchronized (mLock) {
2771                    pendingEvent = addPendingEventLocked(event, policyFlags);
2772                }
2773
2774                Message message = mInvocationHandler.obtainMessage(
2775                        InvocationHandler.MSG_ON_KEY_EVENT_TIMEOUT, pendingEvent);
2776                mInvocationHandler.sendMessageDelayed(message, ON_KEY_EVENT_TIMEOUT_MILLIS);
2777
2778                try {
2779                    // Accessibility services are exclusively not in the system
2780                    // process, therefore no need to clone the motion event to
2781                    // prevent tampering. It will be cloned in the IPC call.
2782                    mServiceInterface.onKeyEvent(pendingEvent.event, pendingEvent.sequence);
2783                } catch (RemoteException re) {
2784                    setOnKeyEventResult(false, pendingEvent.sequence);
2785                }
2786            }
2787
2788            public void setOnKeyEventResult(boolean handled, int sequence) {
2789                synchronized (mLock) {
2790                    PendingEvent pendingEvent = removePendingEventLocked(sequence);
2791                    if (pendingEvent != null) {
2792                        mInvocationHandler.removeMessages(
2793                                InvocationHandler.MSG_ON_KEY_EVENT_TIMEOUT,
2794                                pendingEvent);
2795                        pendingEvent.handled = handled;
2796                        finishPendingEventLocked(pendingEvent);
2797                    }
2798                }
2799            }
2800
2801            public void flush() {
2802                synchronized (mLock) {
2803                    cancelAllPendingEventsLocked();
2804                    if (mSentEventsVerifier != null) {
2805                        mSentEventsVerifier.reset();
2806                    }
2807                }
2808            }
2809
2810            private PendingEvent addPendingEventLocked(KeyEvent event, int policyFlags) {
2811                final int sequence = event.getSequenceNumber();
2812                PendingEvent pendingEvent = obtainPendingEventLocked(event, policyFlags, sequence);
2813                pendingEvent.next = mPendingEvents;
2814                mPendingEvents = pendingEvent;
2815                return pendingEvent;
2816            }
2817
2818            private PendingEvent removePendingEventLocked(int sequence) {
2819                PendingEvent previous = null;
2820                PendingEvent current = mPendingEvents;
2821
2822                while (current != null) {
2823                    if (current.sequence == sequence) {
2824                        if (previous != null) {
2825                            previous.next = current.next;
2826                        } else {
2827                            mPendingEvents = current.next;
2828                        }
2829                        current.next = null;
2830                        return current;
2831                    }
2832                    previous = current;
2833                    current = current.next;
2834                }
2835                return null;
2836            }
2837
2838            private void finishPendingEventLocked(PendingEvent pendingEvent) {
2839                if (!pendingEvent.handled) {
2840                    sendKeyEventToInputFilter(pendingEvent.event, pendingEvent.policyFlags);
2841                }
2842                // Nullify the event since we do not want it to be
2843                // recycled yet. It will be sent to the input filter.
2844                pendingEvent.event = null;
2845                recyclePendingEventLocked(pendingEvent);
2846            }
2847
2848            private void sendKeyEventToInputFilter(KeyEvent event, int policyFlags) {
2849                if (DEBUG) {
2850                    Slog.i(LOG_TAG, "Injecting event: " + event);
2851                }
2852                if (mSentEventsVerifier != null) {
2853                    mSentEventsVerifier.onKeyEvent(event, 0);
2854                }
2855                policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER;
2856                mMainHandler.obtainMessage(MainHandler.MSG_SEND_KEY_EVENT_TO_INPUT_FILTER,
2857                        policyFlags, 0, event).sendToTarget();
2858            }
2859
2860            private void cancelAllPendingEventsLocked() {
2861                while (mPendingEvents != null) {
2862                    PendingEvent pendingEvent = removePendingEventLocked(mPendingEvents.sequence);
2863                    pendingEvent.handled = false;
2864                    mInvocationHandler.removeMessages(InvocationHandler.MSG_ON_KEY_EVENT_TIMEOUT,
2865                            pendingEvent);
2866                    finishPendingEventLocked(pendingEvent);
2867                }
2868            }
2869        }
2870    }
2871
2872    private static final class PendingEvent {
2873        PendingEvent next;
2874
2875        KeyEvent event;
2876        int policyFlags;
2877        int sequence;
2878        boolean handled;
2879
2880        public void clear() {
2881            if (event != null) {
2882                event.recycle();
2883                event = null;
2884            }
2885            next = null;
2886            policyFlags = 0;
2887            sequence = 0;
2888            handled = false;
2889        }
2890    }
2891
2892    final class WindowsForAccessibilityCallback implements
2893            WindowManagerInternal.WindowsForAccessibilityCallback {
2894
2895        @Override
2896        public void onWindowsForAccessibilityChanged(List<WindowInfo> windows) {
2897            synchronized (mLock) {
2898                List<WindowInfo> receivedWindows = (List<WindowInfo>) windows;
2899
2900                // Populate the windows to report.
2901                List<AccessibilityWindowInfo> reportedWindows =
2902                        new ArrayList<AccessibilityWindowInfo>();
2903                final int receivedWindowCount = receivedWindows.size();
2904                for (int i = 0; i < receivedWindowCount; i++) {
2905                    WindowInfo receivedWindow = receivedWindows.get(i);
2906                    AccessibilityWindowInfo reportedWindow = populateReportedWindow(
2907                            receivedWindow);
2908                    if (reportedWindow != null) {
2909                        reportedWindows.add(reportedWindow);
2910                    }
2911                }
2912
2913                if (DEBUG) {
2914                    Slog.i(LOG_TAG, "Windows changed: " + reportedWindows);
2915                }
2916
2917                // Let the policy update the focused and active windows.
2918                mSecurityPolicy.updateWindowsLocked(reportedWindows);
2919            }
2920        }
2921
2922        private AccessibilityWindowInfo populateReportedWindow(WindowInfo window) {
2923            final int windowId = findWindowIdLocked(window.token);
2924            if (windowId < 0) {
2925                return null;
2926            }
2927
2928            AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain();
2929
2930            reportedWindow.setId(windowId);
2931            reportedWindow.setType(getTypeForWindowManagerWindowType(window.type));
2932            reportedWindow.setLayer(window.layer);
2933            reportedWindow.setFocused(window.focused);
2934            reportedWindow.setBoundsInScreen(window.boundsInScreen);
2935
2936            final int parentId = findWindowIdLocked(window.parentToken);
2937            if (parentId >= 0) {
2938                reportedWindow.setParentId(parentId);
2939            }
2940
2941            if (window.childTokens != null) {
2942                final int childCount = window.childTokens.size();
2943                for (int i = 0; i < childCount; i++) {
2944                    IBinder childToken = window.childTokens.get(i);
2945                    final int childId = findWindowIdLocked(childToken);
2946                    if (childId >= 0) {
2947                        reportedWindow.addChild(childId);
2948                    }
2949                }
2950            }
2951
2952            return reportedWindow;
2953        }
2954
2955        private int getTypeForWindowManagerWindowType(int windowType) {
2956            switch (windowType) {
2957                case WindowManager.LayoutParams.TYPE_APPLICATION:
2958                case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
2959                case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
2960                case WindowManager.LayoutParams.TYPE_APPLICATION_STARTING:
2961                case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
2962                case WindowManager.LayoutParams.TYPE_BASE_APPLICATION:
2963                case WindowManager.LayoutParams.TYPE_PHONE:
2964                case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
2965                case WindowManager.LayoutParams.TYPE_TOAST:
2966                case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG: {
2967                    return AccessibilityWindowInfo.TYPE_APPLICATION;
2968                }
2969
2970                case WindowManager.LayoutParams.TYPE_INPUT_METHOD:
2971                case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: {
2972                    return AccessibilityWindowInfo.TYPE_INPUT_METHOD;
2973                }
2974
2975                case WindowManager.LayoutParams.TYPE_KEYGUARD:
2976                case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
2977                case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR:
2978                case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
2979                case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
2980                case WindowManager.LayoutParams.TYPE_STATUS_BAR:
2981                case WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL:
2982                case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL:
2983                case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY:
2984                case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
2985                case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
2986                case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
2987                case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
2988                case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: {
2989                    return AccessibilityWindowInfo.TYPE_SYSTEM;
2990                }
2991
2992                default: {
2993                    return -1;
2994                }
2995            }
2996        }
2997    }
2998
2999    final class SecurityPolicy {
3000        private static final int VALID_ACTIONS =
3001            AccessibilityNodeInfo.ACTION_CLICK
3002            | AccessibilityNodeInfo.ACTION_LONG_CLICK
3003            | AccessibilityNodeInfo.ACTION_FOCUS
3004            | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS
3005            | AccessibilityNodeInfo.ACTION_SELECT
3006            | AccessibilityNodeInfo.ACTION_CLEAR_SELECTION
3007            | AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS
3008            | AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS
3009            | AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
3010            | AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
3011            | AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT
3012            | AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT
3013            | AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
3014            | AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD
3015            | AccessibilityNodeInfo.ACTION_COPY
3016            | AccessibilityNodeInfo.ACTION_PASTE
3017            | AccessibilityNodeInfo.ACTION_CUT
3018            | AccessibilityNodeInfo.ACTION_SET_SELECTION
3019            | AccessibilityNodeInfo.ACTION_EXPAND
3020            | AccessibilityNodeInfo.ACTION_COLLAPSE
3021            | AccessibilityNodeInfo.ACTION_DISMISS
3022            | AccessibilityNodeInfo.ACTION_SET_TEXT;
3023
3024        private static final int RETRIEVAL_ALLOWING_EVENT_TYPES =
3025            AccessibilityEvent.TYPE_VIEW_CLICKED
3026            | AccessibilityEvent.TYPE_VIEW_FOCUSED
3027            | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
3028            | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
3029            | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED
3030            | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
3031            | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
3032            | AccessibilityEvent.TYPE_VIEW_SELECTED
3033            | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
3034            | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
3035            | AccessibilityEvent.TYPE_VIEW_SCROLLED
3036            | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
3037            | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
3038            | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY;
3039
3040        public final List<AccessibilityWindowInfo> mWindows =
3041                new ArrayList<AccessibilityWindowInfo>();
3042
3043        public int mActiveWindowId;
3044        public int mFocusedWindowId;
3045        public AccessibilityEvent mShowingFocusedWindowEvent;
3046
3047        private boolean mTouchInteractionInProgress;
3048
3049        private boolean canDispatchAccessibilityEventLocked(AccessibilityEvent event) {
3050            final int eventType = event.getEventType();
3051            switch (eventType) {
3052                // All events that are for changes in a global window
3053                // state should *always* be dispatched.
3054                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
3055                    if (mWindowsForAccessibilityCallback != null) {
3056                        // OK, this is fun. Sometimes the focused window is notified
3057                        // it has focus before being shown. Historically this event
3058                        // means that the window is focused and can be introspected.
3059                        // But we still have not gotten the window state from the
3060                        // window manager, so delay the notification until then.
3061                        AccessibilityWindowInfo window = findWindowById(event.getWindowId());
3062                        if (window == null || !window.isFocused()) {
3063                            mShowingFocusedWindowEvent = AccessibilityEvent.obtain(event);
3064                            return false;
3065                        }
3066                    }
3067                // $fall-through$
3068                case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
3069                // All events generated by the user touching the
3070                // screen should *always* be dispatched.
3071                case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
3072                case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END:
3073                case AccessibilityEvent.TYPE_GESTURE_DETECTION_START:
3074                case AccessibilityEvent.TYPE_GESTURE_DETECTION_END:
3075                case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START:
3076                case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
3077                case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
3078                case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
3079                    return true;
3080                }
3081                // All events for changes in window content should be
3082                // dispatched *only* if this window is one of the windows
3083                // the accessibility layer reports which are windows
3084                // that a sighted user can touch.
3085                default: {
3086                    return isRetrievalAllowingWindow(event.getWindowId());
3087                }
3088            }
3089        }
3090
3091        public void updateWindowsLocked(List<AccessibilityWindowInfo> windows) {
3092            final int oldWindowCount = mWindows.size();
3093            for (int i = oldWindowCount - 1; i >= 0; i--) {
3094                mWindows.remove(i).recycle();
3095            }
3096
3097            mFocusedWindowId = -1;
3098            if (!mTouchInteractionInProgress) {
3099                mActiveWindowId = -1;
3100            }
3101
3102            // If the active window goes away while the user is touch exploring we
3103            // reset the active window id and wait for the next hover event from
3104            // under the user's finger to determine which one is the new one. It
3105            // is possible that the finger is not moving and the input system
3106            // filters out such events.
3107            boolean activeWindowGone = true;
3108
3109            final int windowCount = windows.size();
3110            if (windowCount > 0) {
3111                for (int i = 0; i < windowCount; i++) {
3112                    AccessibilityWindowInfo window = windows.get(i);
3113                    final int windowId = window.getId();
3114                    if (window.isFocused()) {
3115                        mFocusedWindowId = windowId;
3116                        if (!mTouchInteractionInProgress) {
3117                            mActiveWindowId = windowId;
3118                            window.setActive(true);
3119                        } else if (windowId == mActiveWindowId) {
3120                            activeWindowGone = false;
3121                        }
3122                    }
3123                    mWindows.add(window);
3124                }
3125
3126                if (mTouchInteractionInProgress && activeWindowGone) {
3127                    mActiveWindowId = -1;
3128                }
3129
3130                // Focused window may change the active one, so set the
3131                // active window once we decided which it is.
3132                for (int i = 0; i < windowCount; i++) {
3133                    AccessibilityWindowInfo window = mWindows.get(i);
3134                    if (window.getId() == mActiveWindowId) {
3135                       window.setActive(true);
3136                    }
3137                }
3138            }
3139
3140            notifyWindowsChangedLocked(mWindows);
3141
3142            // If we are delaying a window state change event as the window
3143            // source was showing when it was fired, now is the time to send.
3144            if (mShowingFocusedWindowEvent != null) {
3145                final int windowId = mShowingFocusedWindowEvent.getWindowId();
3146                AccessibilityWindowInfo window = findWindowById(windowId);
3147                if (window != null && window.isFocused()) {
3148                    // Sending does the recycle.
3149                    sendAccessibilityEvent(mShowingFocusedWindowEvent, mCurrentUserId);
3150                }
3151                mShowingFocusedWindowEvent = null;
3152            }
3153        }
3154
3155        public void updateEventSourceLocked(AccessibilityEvent event) {
3156            if ((event.getEventType() & RETRIEVAL_ALLOWING_EVENT_TYPES) == 0) {
3157                event.setSource(null);
3158            }
3159        }
3160
3161        public void updateActiveWindowLocked(int windowId, int eventType) {
3162            // The active window is either the window that has input focus or
3163            // the window that the user is currently touching. If the user is
3164            // touching a window that does not have input focus as soon as the
3165            // the user stops touching that window the focused window becomes
3166            // the active one. Here we detect the touched window and make it
3167            // active. In updateWindowsLocked() we update the focused window
3168            // and if the user is not touching the screen, we make the focused
3169            // window the active one.
3170            switch (eventType) {
3171                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
3172                    // If no service has the capability to introspect screen,
3173                    // we do not register callback in the window manager for
3174                    // window changes, so we have to ask the window manager
3175                    // what the focused window is to update the active one.
3176                    // The active window also determined events from which
3177                    // windows are delivered.
3178                    synchronized (mLock) {
3179                        if (mWindowsForAccessibilityCallback == null
3180                                && windowId == getFocusedWindowId()) {
3181                            mActiveWindowId = windowId;
3182                        }
3183                    }
3184                } break;
3185
3186                case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: {
3187                    // Do not allow delayed hover events to confuse us
3188                    // which the active window is.
3189                    synchronized (mLock) {
3190                        if (mTouchInteractionInProgress && mActiveWindowId != windowId) {
3191                            setActiveWindowLocked(windowId);
3192                        }
3193                    }
3194                } break;
3195            }
3196        }
3197
3198        public void onTouchInteractionStart() {
3199            synchronized (mLock) {
3200                mTouchInteractionInProgress = true;
3201            }
3202        }
3203
3204        public void onTouchInteractionEnd() {
3205            synchronized (mLock) {
3206                mTouchInteractionInProgress = false;
3207                // We want to set the active window to be current immediately
3208                // after the user has stopped touching the screen since if the
3209                // user types with the IME he should get a feedback for the
3210                // letter typed in the text view which is in the input focused
3211                // window. Note that we always deliver hover accessibility events
3212                // (they are a result of user touching the screen) so change of
3213                // the active window before all hover accessibility events from
3214                // the touched window are delivered is fine.
3215                setActiveWindowLocked(mFocusedWindowId);
3216            }
3217        }
3218
3219        private void setActiveWindowLocked(int windowId) {
3220            if (mActiveWindowId != windowId) {
3221                mActiveWindowId = windowId;
3222                final int windowCount = mWindows.size();
3223                for (int i = 0; i < windowCount; i++) {
3224                    AccessibilityWindowInfo window = mWindows.get(i);
3225                    window.setActive(window.getId() == windowId);
3226                }
3227                notifyWindowsChangedLocked(mWindows);
3228            }
3229        }
3230
3231        public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) {
3232            return canRetrieveWindowContentLocked(service) && isRetrievalAllowingWindow(windowId);
3233        }
3234
3235        public boolean canPerformActionLocked(Service service, int windowId, int action,
3236                Bundle arguments) {
3237            return canRetrieveWindowContentLocked(service)
3238                && isRetrievalAllowingWindow(windowId)
3239                && isActionPermitted(action);
3240        }
3241
3242        public boolean canRetrieveWindowsLocked(Service service) {
3243            return canRetrieveWindowContentLocked(service) && service.mRetrieveInteractiveWindows;
3244        }
3245
3246        public boolean canRetrieveWindowContentLocked(Service service) {
3247            return (service.mAccessibilityServiceInfo.getCapabilities()
3248                    & AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
3249        }
3250
3251        public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) {
3252            final int callingUid = Binder.getCallingUid();
3253            if (callingUid == 0
3254                    || callingUid == Process.SYSTEM_UID
3255                    || callingUid == Process.SHELL_UID) {
3256                return mCurrentUserId;
3257            }
3258            final int callingUserId = UserHandle.getUserId(callingUid);
3259            if (callingUserId == userId) {
3260                return userId;
3261            }
3262            if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS)
3263                    && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) {
3264                throw new SecurityException("Call from user " + callingUserId + " as user "
3265                        + userId + " without permission INTERACT_ACROSS_USERS or "
3266                        + "INTERACT_ACROSS_USERS_FULL not allowed.");
3267            }
3268            if (userId == UserHandle.USER_CURRENT
3269                    || userId == UserHandle.USER_CURRENT_OR_SELF) {
3270                return mCurrentUserId;
3271            }
3272            throw new IllegalArgumentException("Calling user can be changed to only "
3273                    + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
3274        }
3275
3276        public boolean isCallerInteractingAcrossUsers(int userId) {
3277            final int callingUid = Binder.getCallingUid();
3278            return (Binder.getCallingPid() == android.os.Process.myPid()
3279                    || callingUid == Process.SHELL_UID
3280                    || userId == UserHandle.USER_CURRENT
3281                    || userId == UserHandle.USER_CURRENT_OR_SELF);
3282        }
3283
3284        private boolean isRetrievalAllowingWindow(int windowId) {
3285            if (windowId == mActiveWindowId) {
3286                return true;
3287            }
3288            return findWindowById(windowId) != null;
3289        }
3290
3291        private AccessibilityWindowInfo findWindowById(int windowId) {
3292            final int windowCount = mWindows.size();
3293            for (int i = 0; i < windowCount; i++) {
3294                AccessibilityWindowInfo window = mWindows.get(i);
3295                if (window.getId() == windowId) {
3296                    return window;
3297                }
3298            }
3299            return null;
3300        }
3301
3302        private boolean isActionPermitted(int action) {
3303             return (VALID_ACTIONS & action) != 0;
3304        }
3305
3306        private void enforceCallingPermission(String permission, String function) {
3307            if (OWN_PROCESS_ID == Binder.getCallingPid()) {
3308                return;
3309            }
3310            if (!hasPermission(permission)) {
3311                throw new SecurityException("You do not have " + permission
3312                        + " required to call " + function + " from pid="
3313                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
3314            }
3315        }
3316
3317        private boolean hasPermission(String permission) {
3318            return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
3319        }
3320
3321        private int getFocusedWindowId() {
3322            IBinder token = mWindowManagerService.getFocusedWindowToken();
3323            synchronized (mLock) {
3324                return findWindowIdLocked(token);
3325            }
3326        }
3327    }
3328
3329    private class UserState {
3330        public final int mUserId;
3331
3332        // Non-transient state.
3333
3334        public final RemoteCallbackList<IAccessibilityManagerClient> mClients =
3335            new RemoteCallbackList<IAccessibilityManagerClient>();
3336
3337        public final SparseArray<AccessibilityConnectionWrapper> mInteractionConnections =
3338                new SparseArray<AccessibilityConnectionWrapper>();
3339
3340        public final SparseArray<IBinder> mWindowTokens = new SparseArray<IBinder>();
3341
3342        // Transient state.
3343
3344        public final CopyOnWriteArrayList<Service> mBoundServices =
3345                new CopyOnWriteArrayList<Service>();
3346
3347        public final Map<ComponentName, Service> mComponentNameToServiceMap =
3348                new HashMap<ComponentName, Service>();
3349
3350        public final List<AccessibilityServiceInfo> mInstalledServices =
3351                new ArrayList<AccessibilityServiceInfo>();
3352
3353        public final Set<ComponentName> mBindingServices = new HashSet<ComponentName>();
3354
3355        public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
3356
3357        public final Set<ComponentName> mTouchExplorationGrantedServices =
3358                new HashSet<ComponentName>();
3359
3360        public int mHandledFeedbackTypes = 0;
3361
3362        public int mLastSentClientState = -1;
3363
3364        public boolean mIsAccessibilityEnabled;
3365        public boolean mIsTouchExplorationEnabled;
3366        public boolean mIsEnhancedWebAccessibilityEnabled;
3367        public boolean mIsDisplayMagnificationEnabled;
3368        public boolean mIsFilterKeyEventsEnabled;
3369        public boolean mHasDisplayColorAdjustment;
3370
3371        private Service mUiAutomationService;
3372        private IAccessibilityServiceClient mUiAutomationServiceClient;
3373
3374        private IBinder mUiAutomationServiceOwner;
3375        private final DeathRecipient mUiAutomationSerivceOnwerDeathRecipient =
3376                new DeathRecipient() {
3377            @Override
3378            public void binderDied() {
3379                mUiAutomationServiceOwner.unlinkToDeath(
3380                        mUiAutomationSerivceOnwerDeathRecipient, 0);
3381                mUiAutomationServiceOwner = null;
3382                if (mUiAutomationService != null) {
3383                    mUiAutomationService.binderDied();
3384                }
3385            }
3386        };
3387
3388        public UserState(int userId) {
3389            mUserId = userId;
3390        }
3391
3392        public int getClientState() {
3393            int clientState = 0;
3394            if (mIsAccessibilityEnabled) {
3395                clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
3396            }
3397            // Touch exploration relies on enabled accessibility.
3398            if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) {
3399                clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
3400            }
3401            return clientState;
3402        }
3403
3404        public void onSwitchToAnotherUser() {
3405            // Clear UI test automation state.
3406            if (mUiAutomationService != null) {
3407                mUiAutomationService.binderDied();
3408            }
3409
3410            // Unbind all services.
3411            unbindAllServicesLocked(this);
3412
3413            // Clear service management state.
3414            mBoundServices.clear();
3415            mBindingServices.clear();
3416
3417            // Clear event management state.
3418            mHandledFeedbackTypes = 0;
3419            mLastSentClientState = -1;
3420
3421            // Clear state persisted in settings.
3422            mEnabledServices.clear();
3423            mTouchExplorationGrantedServices.clear();
3424            mIsAccessibilityEnabled = false;
3425            mIsTouchExplorationEnabled = false;
3426            mIsEnhancedWebAccessibilityEnabled = false;
3427            mIsDisplayMagnificationEnabled = false;
3428        }
3429
3430        public void destroyUiAutomationService() {
3431            mUiAutomationService = null;
3432            mUiAutomationServiceClient = null;
3433            if (mUiAutomationServiceOwner != null) {
3434                mUiAutomationServiceOwner.unlinkToDeath(
3435                        mUiAutomationSerivceOnwerDeathRecipient, 0);
3436                mUiAutomationServiceOwner = null;
3437            }
3438        }
3439    }
3440
3441    private final class AccessibilityContentObserver extends ContentObserver {
3442
3443        private final Uri mAccessibilityEnabledUri = Settings.Secure.getUriFor(
3444                Settings.Secure.ACCESSIBILITY_ENABLED);
3445
3446        private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor(
3447                Settings.Secure.TOUCH_EXPLORATION_ENABLED);
3448
3449        private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor(
3450                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
3451
3452        private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor(
3453                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
3454
3455        private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
3456                .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
3457
3458        private final Uri mEnhancedWebAccessibilityUri = Settings.Secure
3459                .getUriFor(Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION);
3460
3461        private final Uri mDisplayContrastEnabledUri = Settings.Secure.getUriFor(
3462                Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED);
3463        private final Uri mDisplayContrastUri = Settings.Secure.getUriFor(
3464                Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST);
3465        private final Uri mDisplayBrightnessUri = Settings.Secure.getUriFor(
3466                Settings.Secure.ACCESSIBILITY_DISPLAY_BRIGHTNESS);
3467
3468        private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor(
3469                Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
3470        private final Uri mDisplayInversionUri = Settings.Secure.getUriFor(
3471                Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION);
3472
3473        private final Uri mDisplayDaltonizerEnabledUri = Settings.Secure.getUriFor(
3474                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
3475        private final Uri mDisplayDaltonizerUri = Settings.Secure.getUriFor(
3476                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER);
3477
3478        public AccessibilityContentObserver(Handler handler) {
3479            super(handler);
3480        }
3481
3482        public void register(ContentResolver contentResolver) {
3483            contentResolver.registerContentObserver(mAccessibilityEnabledUri,
3484                    false, this, UserHandle.USER_ALL);
3485            contentResolver.registerContentObserver(mTouchExplorationEnabledUri,
3486                    false, this, UserHandle.USER_ALL);
3487            contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri,
3488                    false, this, UserHandle.USER_ALL);
3489            contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri,
3490                    false, this, UserHandle.USER_ALL);
3491            contentResolver.registerContentObserver(
3492                    mTouchExplorationGrantedAccessibilityServicesUri,
3493                    false, this, UserHandle.USER_ALL);
3494            contentResolver.registerContentObserver(mEnhancedWebAccessibilityUri,
3495                    false, this, UserHandle.USER_ALL);
3496            contentResolver.registerContentObserver(
3497                    mDisplayContrastEnabledUri, false, this, UserHandle.USER_ALL);
3498            contentResolver.registerContentObserver(
3499                    mDisplayContrastUri, false, this, UserHandle.USER_ALL);
3500            contentResolver.registerContentObserver(
3501                    mDisplayBrightnessUri, false, this, UserHandle.USER_ALL);
3502            contentResolver.registerContentObserver(
3503                    mDisplayInversionEnabledUri, false, this, UserHandle.USER_ALL);
3504            contentResolver.registerContentObserver(
3505                    mDisplayInversionUri, false, this, UserHandle.USER_ALL);
3506            contentResolver.registerContentObserver(
3507                    mDisplayDaltonizerEnabledUri, false, this, UserHandle.USER_ALL);
3508            contentResolver.registerContentObserver(
3509                    mDisplayDaltonizerUri, false, this, UserHandle.USER_ALL);
3510        }
3511
3512        @Override
3513        public void onChange(boolean selfChange, Uri uri) {
3514            if (mAccessibilityEnabledUri.equals(uri)) {
3515                synchronized (mLock) {
3516                    // We will update when the automation service dies.
3517                    UserState userState = getCurrentUserStateLocked();
3518                    if (userState.mUiAutomationService == null) {
3519                        if (readAccessibilityEnabledSettingLocked(userState)) {
3520                            onUserStateChangedLocked(userState);
3521                        }
3522                    }
3523                }
3524            } else if (mTouchExplorationEnabledUri.equals(uri)) {
3525                synchronized (mLock) {
3526                    // We will update when the automation service dies.
3527                    UserState userState = getCurrentUserStateLocked();
3528                    if (userState.mUiAutomationService == null) {
3529                        if (readTouchExplorationEnabledSettingLocked(userState)) {
3530                            onUserStateChangedLocked(userState);
3531                        }
3532                    }
3533                }
3534            } else if (mDisplayMagnificationEnabledUri.equals(uri)) {
3535                synchronized (mLock) {
3536                    // We will update when the automation service dies.
3537                    UserState userState = getCurrentUserStateLocked();
3538                    if (userState.mUiAutomationService == null) {
3539                        if (readDisplayMagnificationEnabledSettingLocked(userState)) {
3540                            onUserStateChangedLocked(userState);
3541                        }
3542                    }
3543                }
3544            } else if (mEnabledAccessibilityServicesUri.equals(uri)) {
3545                synchronized (mLock) {
3546                    // We will update when the automation service dies.
3547                    UserState userState = getCurrentUserStateLocked();
3548                    if (userState.mUiAutomationService == null) {
3549                        if (readEnabledAccessibilityServicesLocked(userState)) {
3550                            onUserStateChangedLocked(userState);
3551                        }
3552                    }
3553                }
3554            } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
3555                synchronized (mLock) {
3556                    // We will update when the automation service dies.
3557                    UserState userState = getCurrentUserStateLocked();
3558                    if (userState.mUiAutomationService == null) {
3559                        if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) {
3560                            onUserStateChangedLocked(userState);
3561                        }
3562                    }
3563                }
3564            } else if (mEnhancedWebAccessibilityUri.equals(uri)) {
3565                synchronized (mLock) {
3566                    // We will update when the automation service dies.
3567                    UserState userState = getCurrentUserStateLocked();
3568                    if (userState.mUiAutomationService == null) {
3569                        if (readEnhancedWebAccessibilityEnabledChangedLocked(userState)) {
3570                            onUserStateChangedLocked(userState);
3571                        }
3572                    }
3573                }
3574            } else if (mDisplayContrastEnabledUri.equals(uri)
3575                    || mDisplayInversionEnabledUri.equals(uri)
3576                    || mDisplayDaltonizerEnabledUri.equals(uri)
3577                    || mDisplayContrastUri.equals(uri)
3578                    || mDisplayBrightnessUri.equals(uri)
3579                    || mDisplayInversionUri.equals(uri)
3580                    || mDisplayDaltonizerUri.equals(uri)) {
3581                synchronized (mLock) {
3582                    // We will update when the automation service dies.
3583                    UserState userState = getCurrentUserStateLocked();
3584                    if (userState.mUiAutomationService == null) {
3585                        if (readDisplayColorAdjustmentSettingsLocked(userState)) {
3586                            updateDisplayColorAdjustmentSettingsLocked(userState);
3587                        }
3588                    }
3589                }
3590            }
3591        }
3592    }
3593}
3594