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