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