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