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