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