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