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