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