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