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