AccessibilityManagerService.java revision 11cf178100e71d3f9f34ab5865e03a277c5eadaa
1/*
2 ** Copyright 2009, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 **     http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17package com.android.server.accessibility;
18
19import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT;
20import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
21
22import android.Manifest;
23import android.accessibilityservice.AccessibilityService;
24import android.accessibilityservice.AccessibilityServiceInfo;
25import android.accessibilityservice.IAccessibilityServiceClient;
26import android.accessibilityservice.IAccessibilityServiceConnection;
27import android.app.AlertDialog;
28import android.app.PendingIntent;
29import android.app.StatusBarManager;
30import android.content.BroadcastReceiver;
31import android.content.ComponentName;
32import android.content.ContentResolver;
33import android.content.Context;
34import android.content.DialogInterface;
35import android.content.DialogInterface.OnClickListener;
36import android.content.Intent;
37import android.content.IntentFilter;
38import android.content.ServiceConnection;
39import android.content.pm.PackageManager;
40import android.content.pm.ResolveInfo;
41import android.content.pm.ServiceInfo;
42import android.database.ContentObserver;
43import android.graphics.Rect;
44import android.hardware.input.InputManager;
45import android.net.Uri;
46import android.os.Binder;
47import android.os.Build;
48import android.os.Bundle;
49import android.os.Handler;
50import android.os.IBinder;
51import android.os.Looper;
52import android.os.Message;
53import android.os.Process;
54import android.os.RemoteCallbackList;
55import android.os.RemoteException;
56import android.os.ServiceManager;
57import android.os.SystemClock;
58import android.os.UserHandle;
59import android.provider.Settings;
60import android.text.TextUtils;
61import android.text.TextUtils.SimpleStringSplitter;
62import android.util.Slog;
63import android.util.SparseArray;
64import android.view.IWindow;
65import android.view.IWindowManager;
66import android.view.InputDevice;
67import android.view.KeyCharacterMap;
68import android.view.KeyEvent;
69import android.view.WindowInfo;
70import android.view.WindowManager;
71import android.view.accessibility.AccessibilityEvent;
72import android.view.accessibility.AccessibilityInteractionClient;
73import android.view.accessibility.AccessibilityManager;
74import android.view.accessibility.AccessibilityNodeInfo;
75import android.view.accessibility.IAccessibilityInteractionConnection;
76import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
77import android.view.accessibility.IAccessibilityManager;
78import android.view.accessibility.IAccessibilityManagerClient;
79
80import com.android.internal.R;
81import com.android.internal.content.PackageMonitor;
82import com.android.internal.statusbar.IStatusBarService;
83
84import org.xmlpull.v1.XmlPullParserException;
85
86import java.io.IOException;
87import java.util.ArrayList;
88import java.util.Arrays;
89import java.util.HashMap;
90import java.util.HashSet;
91import java.util.Iterator;
92import java.util.List;
93import java.util.Map;
94import java.util.Set;
95import java.util.concurrent.CopyOnWriteArrayList;
96
97/**
98 * This class is instantiated by the system as a system level service and can be
99 * accessed only by the system. The task of this service is to be a centralized
100 * event dispatch for {@link AccessibilityEvent}s generated across all processes
101 * on the device. Events are dispatched to {@link AccessibilityService}s.
102 *
103 * @hide
104 */
105public class AccessibilityManagerService extends IAccessibilityManager.Stub {
106
107    private static final boolean DEBUG = false;
108
109    private static final String LOG_TAG = "AccessibilityManagerService";
110
111    private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE =
112        "registerUiTestAutomationService";
113
114    private static final char COMPONENT_NAME_SEPARATOR = ':';
115
116    private static final int OWN_PROCESS_ID = android.os.Process.myPid();
117
118    private static int sIdCounter = 0;
119
120    private static int sNextWindowId;
121
122    private final Context mContext;
123
124    private final Object mLock = new Object();
125
126    private final SimpleStringSplitter mStringColonSplitter =
127            new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
128
129    private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList =
130            new ArrayList<AccessibilityServiceInfo>();
131
132    private final PackageManager mPackageManager;
133
134    private final IWindowManager mWindowManagerService;
135
136    private final SecurityPolicy mSecurityPolicy;
137
138    private final MainHandler mMainHandler;
139
140    private Service mUiAutomationService;
141
142    private Service mQueryBridge;
143
144    private AlertDialog mEnableTouchExplorationDialog;
145
146    private AccessibilityInputFilter mInputFilter;
147
148    private boolean mHasInputFilter;
149
150    private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
151            new RemoteCallbackList<IAccessibilityManagerClient>();
152
153    private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections =
154            new SparseArray<AccessibilityConnectionWrapper>();
155
156    private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<IBinder>();
157
158    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
159
160    private int mCurrentUserId = UserHandle.USER_OWNER;
161
162    private UserState getCurrentUserStateLocked() {
163        return getUserStateLocked(mCurrentUserId);
164    }
165
166    private UserState getUserStateLocked(int userId) {
167        UserState state = mUserStates.get(userId);
168        if (state == null) {
169            state = new UserState(userId);
170            mUserStates.put(userId, state);
171        }
172        return state;
173    }
174
175    /**
176     * Creates a new instance.
177     *
178     * @param context A {@link Context} instance.
179     */
180    public AccessibilityManagerService(Context context) {
181        mContext = context;
182        mPackageManager = mContext.getPackageManager();
183        mWindowManagerService = (IWindowManager) ServiceManager.getService(Context.WINDOW_SERVICE);
184        mSecurityPolicy = new SecurityPolicy();
185        mMainHandler = new MainHandler(mContext.getMainLooper());
186        registerBroadcastReceivers();
187        new AccessibilityContentObserver(mMainHandler).register(
188                context.getContentResolver());
189    }
190
191    private void registerBroadcastReceivers() {
192        PackageMonitor monitor = new PackageMonitor() {
193            @Override
194            public void onSomePackagesChanged() {
195                synchronized (mLock) {
196                    if (getChangingUserId() != mCurrentUserId) {
197                        return;
198                    }
199                    // We will update when the automation service dies.
200                    if (mUiAutomationService == null) {
201                        UserState userState = getCurrentUserStateLocked();
202                        populateInstalledAccessibilityServiceLocked(userState);
203                        manageServicesLocked(userState);
204                    }
205                }
206            }
207
208            @Override
209            public void onPackageRemoved(String packageName, int uid) {
210                synchronized (mLock) {
211                    final int userId = getChangingUserId();
212                    if (userId != mCurrentUserId) {
213                        return;
214                    }
215                    UserState state = getUserStateLocked(userId);
216                    Iterator<ComponentName> it = state.mEnabledServices.iterator();
217                    while (it.hasNext()) {
218                        ComponentName comp = it.next();
219                        String compPkg = comp.getPackageName();
220                        if (compPkg.equals(packageName)) {
221                            it.remove();
222                            // Update the enabled services setting.
223                            persistComponentNamesToSettingLocked(
224                                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
225                                    state.mEnabledServices, userId);
226                            // Update the touch exploration granted services setting.
227                            state.mTouchExplorationGrantedServices.remove(comp);
228                            persistComponentNamesToSettingLocked(
229                                    Settings.Secure.
230                                            TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
231                                    state.mEnabledServices, userId);
232                            return;
233                        }
234                    }
235                }
236            }
237
238            @Override
239            public boolean onHandleForceStop(Intent intent, String[] packages,
240                    int uid, boolean doit) {
241                synchronized (mLock) {
242                    final int userId = getChangingUserId();
243                    if (userId != mCurrentUserId) {
244                        return false;
245                    }
246                    UserState state = getUserStateLocked(userId);
247                    Iterator<ComponentName> it = state.mEnabledServices.iterator();
248                    while (it.hasNext()) {
249                        ComponentName comp = it.next();
250                        String compPkg = comp.getPackageName();
251                        for (String pkg : packages) {
252                            if (compPkg.equals(pkg)) {
253                                if (!doit) {
254                                    return true;
255                                }
256                                it.remove();
257                                persistComponentNamesToSettingLocked(
258                                        Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
259                                        state.mEnabledServices, userId);
260                            }
261                        }
262                    }
263                    return false;
264                }
265            }
266        };
267
268        // package changes
269        monitor.register(mContext, null,  UserHandle.ALL, true);
270
271        // user change
272        IntentFilter userFilter = new IntentFilter();
273        userFilter.addAction(Intent.ACTION_USER_SWITCHED);
274        userFilter.addAction(Intent.ACTION_USER_REMOVED);
275
276        mContext.registerReceiver(new BroadcastReceiver() {
277            @Override
278            public void onReceive(Context context, Intent intent) {
279                String action = intent.getAction();
280                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
281                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
282                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
283                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
284                }
285            }
286        }, userFilter);
287    }
288
289    public int addClient(IAccessibilityManagerClient client, int userId) {
290        synchronized (mLock) {
291            final int resolvedUserId = mSecurityPolicy
292                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
293            // If the client is from a process that runs across users such as
294            // the system UI or the system we add it to the global state that
295            // is shared across users.
296            UserState userState = getUserStateLocked(resolvedUserId);
297            if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
298                mGlobalClients.register(client);
299                if (DEBUG) {
300                    Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid());
301                }
302                return getClientState(userState);
303            } else {
304                userState.mClients.register(client);
305                // If this client is not for the current user we do not
306                // return a state since it is not for the foreground user.
307                // We will send the state to the client on a user switch.
308                if (DEBUG) {
309                    Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid()
310                            + " and userId:" + mCurrentUserId);
311                }
312                return (resolvedUserId == mCurrentUserId) ? getClientState(userState) : 0;
313            }
314        }
315    }
316
317    public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) {
318        synchronized (mLock) {
319            final int resolvedUserId = mSecurityPolicy
320                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
321            // This method does nothing for a background user.
322            if (resolvedUserId != mCurrentUserId) {
323                return true; // yes, recycle the event
324            }
325            if (mSecurityPolicy.canDispatchAccessibilityEvent(event)) {
326                mSecurityPolicy.updateEventSourceLocked(event);
327                mMainHandler.obtainMessage(MainHandler.MSG_UPDATE_ACTIVE_WINDOW,
328                        event.getWindowId(), event.getEventType()).sendToTarget();
329                notifyAccessibilityServicesDelayedLocked(event, false);
330                notifyAccessibilityServicesDelayedLocked(event, true);
331            }
332            if (mHasInputFilter && mInputFilter != null) {
333                mMainHandler.obtainMessage(MainHandler.MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER,
334                        AccessibilityEvent.obtain(event)).sendToTarget();
335            }
336            event.recycle();
337            getUserStateLocked(resolvedUserId).mHandledFeedbackTypes = 0;
338        }
339        return (OWN_PROCESS_ID != Binder.getCallingPid());
340    }
341
342    public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
343        synchronized (mLock) {
344            final int resolvedUserId = mSecurityPolicy
345                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
346            return getUserStateLocked(resolvedUserId).mInstalledServices;
347        }
348    }
349
350    public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,
351            int userId) {
352        List<AccessibilityServiceInfo> result = null;
353        synchronized (mLock) {
354            final int resolvedUserId = mSecurityPolicy
355                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
356            result = mEnabledServicesForFeedbackTempList;
357            result.clear();
358            List<Service> services = getUserStateLocked(resolvedUserId).mServices;
359            while (feedbackType != 0) {
360                final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType));
361                feedbackType &= ~feedbackTypeBit;
362                final int serviceCount = services.size();
363                for (int i = 0; i < serviceCount; i++) {
364                    Service service = services.get(i);
365                    if ((service.mFeedbackType & feedbackTypeBit) != 0) {
366                        result.add(service.mAccessibilityServiceInfo);
367                    }
368                }
369            }
370        }
371        return result;
372    }
373
374    public void interrupt(int userId) {
375        CopyOnWriteArrayList<Service> services;
376        synchronized (mLock) {
377            final int resolvedUserId = mSecurityPolicy
378                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
379            // This method does nothing for a background user.
380            if (resolvedUserId != mCurrentUserId) {
381                return;
382            }
383            services = getUserStateLocked(resolvedUserId).mServices;
384        }
385        for (int i = 0, count = services.size(); i < count; i++) {
386            Service service = services.get(i);
387            try {
388                service.mServiceInterface.onInterrupt();
389            } catch (RemoteException re) {
390                Slog.e(LOG_TAG, "Error during sending interrupt request to "
391                    + service.mService, re);
392            }
393        }
394    }
395
396    public int addAccessibilityInteractionConnection(IWindow windowToken,
397            IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
398        synchronized (mLock) {
399            final int resolvedUserId = mSecurityPolicy
400                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
401            final int windowId = sNextWindowId++;
402            // If the window is from a process that runs across users such as
403            // the system UI or the system we add it to the global state that
404            // is shared across users.
405            if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
406                AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
407                        windowId, connection, UserHandle.USER_ALL);
408                wrapper.linkToDeath();
409                mGlobalInteractionConnections.put(windowId, wrapper);
410                mGlobalWindowTokens.put(windowId, windowToken.asBinder());
411                if (DEBUG) {
412                    Slog.i(LOG_TAG, "Added global connection for pid:" + Binder.getCallingPid()
413                            + " with windowId: " + windowId);
414                }
415            } else {
416                AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
417                        windowId, connection, resolvedUserId);
418                wrapper.linkToDeath();
419                UserState userState = getUserStateLocked(resolvedUserId);
420                userState.mInteractionConnections.put(windowId, wrapper);
421                userState.mWindowTokens.put(windowId, windowToken.asBinder());
422                if (DEBUG) {
423                    Slog.i(LOG_TAG, "Added user connection for pid:" + Binder.getCallingPid()
424                            + " with windowId: " + windowId + " and userId:" + mCurrentUserId);
425                }
426            }
427            if (DEBUG) {
428                Slog.i(LOG_TAG, "Adding interaction connection to windowId: " + windowId);
429            }
430            return windowId;
431        }
432    }
433
434    public void removeAccessibilityInteractionConnection(IWindow window) {
435        synchronized (mLock) {
436            mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
437                    UserHandle.getCallingUserId());
438            IBinder token = window.asBinder();
439            final int removedWindowId = removeAccessibilityInteractionConnectionInternalLocked(
440                    token, mGlobalWindowTokens, mGlobalInteractionConnections);
441            if (removedWindowId >= 0) {
442                if (DEBUG) {
443                    Slog.i(LOG_TAG, "Removed global connection for pid:" + Binder.getCallingPid()
444                            + " with windowId: " + removedWindowId);
445                }
446                return;
447            }
448            final int userCount = mUserStates.size();
449            for (int i = 0; i < userCount; i++) {
450                UserState userState = mUserStates.valueAt(i);
451                final int removedWindowIdForUser =
452                        removeAccessibilityInteractionConnectionInternalLocked(
453                        token, userState.mWindowTokens, userState.mInteractionConnections);
454                if (removedWindowIdForUser >= 0) {
455                    if (DEBUG) {
456                        Slog.i(LOG_TAG, "Removed user connection for pid:" + Binder.getCallingPid()
457                                + " with windowId: " + removedWindowIdForUser + " and userId:"
458                                + mUserStates.keyAt(i));
459                    }
460                    return;
461                }
462            }
463        }
464    }
465
466    private int removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken,
467            SparseArray<IBinder> windowTokens,
468            SparseArray<AccessibilityConnectionWrapper> interactionConnections) {
469        final int count = windowTokens.size();
470        for (int i = 0; i < count; i++) {
471            if (windowTokens.valueAt(i) == windowToken) {
472                final int windowId = windowTokens.keyAt(i);
473                windowTokens.removeAt(i);
474                AccessibilityConnectionWrapper wrapper = interactionConnections.get(windowId);
475                wrapper.unlinkToDeath();
476                interactionConnections.remove(windowId);
477                return windowId;
478            }
479        }
480        return -1;
481    }
482
483    public void registerUiTestAutomationService(IAccessibilityServiceClient serviceClient,
484            AccessibilityServiceInfo accessibilityServiceInfo) {
485        mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
486                FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
487        ComponentName componentName = new ComponentName("foo.bar",
488                "AutomationAccessibilityService");
489        synchronized (mLock) {
490            // If an automation services is connected to the system all services are stopped
491            // so the automation one is the only one running. Settings are not changed so when
492            // the automation service goes away the state is restored from the settings.
493            UserState userState = getCurrentUserStateLocked();
494            unbindAllServicesLocked(userState);
495
496            // If necessary enable accessibility and announce that.
497            if (!userState.mIsAccessibilityEnabled) {
498                userState.mIsAccessibilityEnabled = true;
499            }
500            // No touch exploration.
501            userState.mIsTouchExplorationEnabled = false;
502
503            // Hook the automation service up.
504            mUiAutomationService = new Service(mCurrentUserId, componentName,
505                    accessibilityServiceInfo, true);
506            mUiAutomationService.onServiceConnected(componentName, serviceClient.asBinder());
507
508            updateInputFilterLocked(userState);
509            scheduleSendStateToClientsLocked(userState);
510        }
511    }
512
513    public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
514        synchronized (mLock) {
515            // Automation service is not bound, so pretend it died to perform clean up.
516            if (mUiAutomationService != null
517                    && mUiAutomationService.mServiceInterface == serviceClient) {
518                mUiAutomationService.binderDied();
519            }
520        }
521    }
522
523    boolean onGesture(int gestureId) {
524        synchronized (mLock) {
525            boolean handled = notifyGestureLocked(gestureId, false);
526            if (!handled) {
527                handled = notifyGestureLocked(gestureId, true);
528            }
529            return handled;
530        }
531    }
532
533    /**
534     * Gets the bounds of the accessibility focus in the active window.
535     *
536     * @param outBounds The output to which to write the focus bounds.
537     * @return Whether accessibility focus was found and the bounds are populated.
538     */
539    boolean getAccessibilityFocusBoundsInActiveWindow(Rect outBounds) {
540        // Instead of keeping track of accessibility focus events per
541        // window to be able to find the focus in the active window,
542        // we take a stateless approach and look it up. This is fine
543        // since we do this only when the user clicks/long presses.
544        Service service = getQueryBridge();
545        final int connectionId = service.mId;
546        AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
547        client.addConnection(connectionId, service);
548        try {
549            AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance()
550                    .getRootInActiveWindow(connectionId);
551            if (root == null) {
552                return false;
553            }
554            AccessibilityNodeInfo focus = root.findFocus(
555                    AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
556            if (focus == null) {
557                return false;
558            }
559            focus.getBoundsInScreen(outBounds);
560            return true;
561        } finally {
562            client.removeConnection(connectionId);
563        }
564    }
565
566    /**
567     * Gets the bounds of the active window.
568     *
569     * @param outBounds The output to which to write the bounds.
570     */
571    boolean getActiveWindowBounds(Rect outBounds) {
572        IBinder token;
573        synchronized (mLock) {
574            final int windowId = mSecurityPolicy.mActiveWindowId;
575            token = mGlobalWindowTokens.get(windowId);
576            if (token == null) {
577                token = getCurrentUserStateLocked().mWindowTokens.get(windowId);
578            }
579        }
580        WindowInfo info = null;
581        try {
582            info = mWindowManagerService.getWindowInfo(token);
583            if (info != null) {
584                outBounds.set(info.frame);
585                return true;
586            }
587        } catch (RemoteException re) {
588            /* ignore */
589        } finally {
590            if (info != null) {
591                info.recycle();
592            }
593        }
594        return false;
595    }
596
597    int getActiveWindowId() {
598        return mSecurityPolicy.mActiveWindowId;
599    }
600
601    private void switchUser(int userId) {
602        synchronized (mLock) {
603            if (userId == mCurrentUserId) {
604                return;
605            }
606
607            // Disconnect from services for the old user.
608            UserState oldUserState = getUserStateLocked(mCurrentUserId);
609            unbindAllServicesLocked(oldUserState);
610
611            // Disable the local managers for the old user.
612            if (oldUserState.mClients.getRegisteredCallbackCount() > 0) {
613                mMainHandler.obtainMessage(MainHandler.MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER,
614                        oldUserState.mUserId, 0).sendToTarget();
615            }
616
617            // The user changed.
618            mCurrentUserId = userId;
619
620            // Recreate the internal state for the new user.
621            mMainHandler.obtainMessage(MainHandler.MSG_SEND_RECREATE_INTERNAL_STATE,
622                    mCurrentUserId, 0).sendToTarget();
623        }
624    }
625
626    private void removeUser(int userId) {
627        synchronized (mLock) {
628            mUserStates.remove(userId);
629        }
630    }
631
632    private Service getQueryBridge() {
633        if (mQueryBridge == null) {
634            AccessibilityServiceInfo info = new AccessibilityServiceInfo();
635            mQueryBridge = new Service(UserHandle.USER_NULL, null, info, true);
636        }
637        return mQueryBridge;
638    }
639
640    private boolean notifyGestureLocked(int gestureId, boolean isDefault) {
641        // TODO: Now we are giving the gestures to the last enabled
642        //       service that can handle them which is the last one
643        //       in our list since we write the last enabled as the
644        //       last record in the enabled services setting. Ideally,
645        //       the user should make the call which service handles
646        //       gestures. However, only one service should handle
647        //       gestures to avoid user frustration when different
648        //       behavior is observed from different combinations of
649        //       enabled accessibility services.
650        UserState state = getCurrentUserStateLocked();
651        for (int i = state.mServices.size() - 1; i >= 0; i--) {
652            Service service = state.mServices.get(i);
653            if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) {
654                service.notifyGesture(gestureId);
655                return true;
656            }
657        }
658        return false;
659    }
660
661    /**
662     * Removes an AccessibilityInteractionConnection.
663     *
664     * @param windowId The id of the window to which the connection is targeted.
665     * @param userId The id of the user owning the connection. UserHandle.USER_ALL
666     *     if global.
667     */
668    private void removeAccessibilityInteractionConnectionLocked(int windowId, int userId) {
669        if (userId == UserHandle.USER_ALL) {
670            mGlobalWindowTokens.remove(windowId);
671            mGlobalInteractionConnections.remove(windowId);
672        } else {
673            UserState userState = getCurrentUserStateLocked();
674            userState.mWindowTokens.remove(windowId);
675            userState.mInteractionConnections.remove(windowId);
676        }
677        if (DEBUG) {
678            Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId);
679        }
680    }
681
682    private void populateInstalledAccessibilityServiceLocked(UserState userState) {
683        userState.mInstalledServices.clear();
684
685        List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
686                new Intent(AccessibilityService.SERVICE_INTERFACE),
687                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
688                mCurrentUserId);
689
690        for (int i = 0, count = installedServices.size(); i < count; i++) {
691            ResolveInfo resolveInfo = installedServices.get(i);
692            ServiceInfo serviceInfo = resolveInfo.serviceInfo;
693            if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals(
694                    serviceInfo.permission)) {
695                Slog.w(LOG_TAG, "Skipping accessibilty service " + new ComponentName(
696                        serviceInfo.packageName, serviceInfo.name).flattenToShortString()
697                        + ": it does not require the permission "
698                        + android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE);
699                continue;
700            }
701            AccessibilityServiceInfo accessibilityServiceInfo;
702            try {
703                accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
704                userState.mInstalledServices.add(accessibilityServiceInfo);
705            } catch (XmlPullParserException xppe) {
706                Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe);
707            } catch (IOException ioe) {
708                Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", ioe);
709            }
710        }
711    }
712
713    private void populateEnabledAccessibilityServicesLocked(UserState userState) {
714        populateComponentNamesFromSettingLocked(
715                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
716                userState.mUserId,
717                userState.mEnabledServices);
718    }
719
720    private void populateTouchExplorationGrantedAccessibilityServicesLocked(
721            UserState userState) {
722        populateComponentNamesFromSettingLocked(
723                Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
724                userState.mUserId,
725                userState.mTouchExplorationGrantedServices);
726    }
727
728    /**
729     * Performs {@link AccessibilityService}s delayed notification. The delay is configurable
730     * and denotes the period after the last event before notifying the service.
731     *
732     * @param event The event.
733     * @param isDefault True to notify default listeners, not default services.
734     */
735    private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event,
736            boolean isDefault) {
737        try {
738            UserState state = getCurrentUserStateLocked();
739            for (int i = 0, count = state.mServices.size(); i < count; i++) {
740                Service service = state.mServices.get(i);
741
742                if (service.mIsDefault == isDefault) {
743                    if (canDispathEventLocked(service, event, state.mHandledFeedbackTypes)) {
744                        state.mHandledFeedbackTypes |= service.mFeedbackType;
745                        service.notifyAccessibilityEvent(event);
746                    }
747                }
748            }
749        } catch (IndexOutOfBoundsException oobe) {
750            // An out of bounds exception can happen if services are going away
751            // as the for loop is running. If that happens, just bail because
752            // there are no more services to notify.
753            return;
754        }
755    }
756
757    /**
758     * Adds a service for a user.
759     *
760     * @param service The service to add.
761     * @param userId The user id.
762     */
763    private void tryAddServiceLocked(Service service, int userId) {
764        try {
765            UserState userState = getUserStateLocked(userId);
766            if (userState.mServices.contains(service) || !service.isConfigured()) {
767                return;
768            }
769            service.linkToOwnDeath();
770            userState.mServices.add(service);
771            userState.mComponentNameToServiceMap.put(service.mComponentName, service);
772            updateInputFilterLocked(userState);
773            tryEnableTouchExplorationLocked(service);
774        } catch (RemoteException e) {
775            /* do nothing */
776        }
777    }
778
779    /**
780     * Removes a service.
781     *
782     * @param service The service.
783     * @return True if the service was removed, false otherwise.
784     */
785    private boolean tryRemoveServiceLocked(Service service) {
786        UserState userState = getUserStateLocked(service.mUserId);
787        final boolean removed = userState.mServices.remove(service);
788        if (!removed) {
789            return false;
790        }
791        userState.mComponentNameToServiceMap.remove(service.mComponentName);
792        service.unlinkToOwnDeath();
793        service.dispose();
794        updateInputFilterLocked(userState);
795        tryDisableTouchExplorationLocked(service);
796        return removed;
797    }
798
799    /**
800     * Determines if given event can be dispatched to a service based on the package of the
801     * event source and already notified services for that event type. Specifically, a
802     * service is notified if it is interested in events from the package and no other service
803     * providing the same feedback type has been notified. Exception are services the
804     * provide generic feedback (feedback type left as a safety net for unforeseen feedback
805     * types) which are always notified.
806     *
807     * @param service The potential receiver.
808     * @param event The event.
809     * @param handledFeedbackTypes The feedback types for which services have been notified.
810     * @return True if the listener should be notified, false otherwise.
811     */
812    private boolean canDispathEventLocked(Service service, AccessibilityEvent event,
813            int handledFeedbackTypes) {
814
815        if (!service.isConfigured()) {
816            return false;
817        }
818
819        if (!event.isImportantForAccessibility()
820                && !service.mIncludeNotImportantViews) {
821            return false;
822        }
823
824        int eventType = event.getEventType();
825        if ((service.mEventTypes & eventType) != eventType) {
826            return false;
827        }
828
829        Set<String> packageNames = service.mPackageNames;
830        CharSequence packageName = event.getPackageName();
831
832        if (packageNames.isEmpty() || packageNames.contains(packageName)) {
833            int feedbackType = service.mFeedbackType;
834            if ((handledFeedbackTypes & feedbackType) != feedbackType
835                    || feedbackType == AccessibilityServiceInfo.FEEDBACK_GENERIC) {
836                return true;
837            }
838        }
839
840        return false;
841    }
842
843    /**
844     * Manages services by starting enabled ones and stopping disabled ones.
845     */
846    private void manageServicesLocked(UserState userState) {
847        final int enabledInstalledServicesCount = updateServicesStateLocked(userState);
848        // No enabled installed services => disable accessibility to avoid
849        // sending accessibility events with no recipient across processes.
850        if (userState.mIsAccessibilityEnabled && enabledInstalledServicesCount == 0) {
851            Settings.Secure.putIntForUser(mContext.getContentResolver(),
852                    Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
853        }
854    }
855
856    /**
857     * Unbinds all bound services for a user.
858     *
859     * @param userState The user state.
860     */
861    private void unbindAllServicesLocked(UserState userState) {
862        List<Service> services = userState.mServices;
863        for (int i = 0, count = services.size(); i < count; i++) {
864            Service service = services.get(i);
865            if (service.unbind()) {
866                i--;
867                count--;
868            }
869        }
870    }
871
872    /**
873     * Populates a set with the {@link ComponentName}s stored in a colon
874     * separated value setting for a given user.
875     *
876     * @param settingName The setting to parse.
877     * @param userId The user id.
878     * @param outComponentNames The output component names.
879     */
880    private void populateComponentNamesFromSettingLocked(String settingName, int userId,
881            Set<ComponentName> outComponentNames) {
882        String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
883                settingName, userId);
884        outComponentNames.clear();
885        if (settingValue != null) {
886            TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
887            splitter.setString(settingValue);
888            while (splitter.hasNext()) {
889                String str = splitter.next();
890                if (str == null || str.length() <= 0) {
891                    continue;
892                }
893                ComponentName enabledService = ComponentName.unflattenFromString(str);
894                if (enabledService != null) {
895                    outComponentNames.add(enabledService);
896                }
897            }
898        }
899    }
900
901    /**
902     * Persists the component names in the specified setting in a
903     * colon separated fashion.
904     *
905     * @param settingName The setting name.
906     * @param componentNames The component names.
907     */
908    private void persistComponentNamesToSettingLocked(String settingName,
909            Set<ComponentName> componentNames, int userId) {
910        StringBuilder builder = new StringBuilder();
911        for (ComponentName componentName : componentNames) {
912            if (builder.length() > 0) {
913                builder.append(COMPONENT_NAME_SEPARATOR);
914            }
915            builder.append(componentName.flattenToShortString());
916        }
917        Settings.Secure.putStringForUser(mContext.getContentResolver(),
918                settingName, builder.toString(), userId);
919    }
920
921    /**
922     * Updates the state of each service by starting (or keeping running) enabled ones and
923     * stopping the rest.
924     *
925     * @param userState The user state for which to do that.
926     * @return The number of enabled installed services.
927     */
928    private int updateServicesStateLocked(UserState userState) {
929        Map<ComponentName, Service> componentNameToServiceMap =
930                userState.mComponentNameToServiceMap;
931        boolean isEnabled = userState.mIsAccessibilityEnabled;
932
933        int enabledInstalledServices = 0;
934        for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
935            AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
936            ComponentName componentName = ComponentName.unflattenFromString(
937                    installedService.getId());
938            Service service = componentNameToServiceMap.get(componentName);
939
940            if (isEnabled) {
941                if (userState.mEnabledServices.contains(componentName)) {
942                    if (service == null) {
943                        service = new Service(userState.mUserId, componentName,
944                                installedService, false);
945                    }
946                    service.bind();
947                    enabledInstalledServices++;
948                } else {
949                    if (service != null) {
950                        service.unbind();
951                    }
952                }
953            } else {
954                if (service != null) {
955                    service.unbind();
956                }
957            }
958        }
959
960        return enabledInstalledServices;
961    }
962
963    private void scheduleSendStateToClientsLocked(UserState userState) {
964        if (mGlobalClients.getRegisteredCallbackCount() > 0
965                || userState.mClients.getRegisteredCallbackCount() > 0) {
966            final int clientState = getClientState(userState);
967            mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS,
968                    clientState, userState.mUserId) .sendToTarget();
969        }
970    }
971
972    private void updateInputFilterLocked(UserState userState) {
973        boolean setInputFilter = false;
974        AccessibilityInputFilter inputFilter = null;
975        synchronized (mLock) {
976            if ((userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled)
977                    || userState.mIsDisplayMagnificationEnabled) {
978                if (!mHasInputFilter) {
979                    mHasInputFilter = true;
980                    if (mInputFilter == null) {
981                        mInputFilter = new AccessibilityInputFilter(mContext,
982                                AccessibilityManagerService.this);
983                    }
984                    inputFilter = mInputFilter;
985                    setInputFilter = true;
986                }
987                int flags = 0;
988                if (userState.mIsDisplayMagnificationEnabled) {
989                    flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
990                }
991                if (userState.mIsTouchExplorationEnabled) {
992                    flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
993                }
994                mInputFilter.setEnabledFeatures(flags);
995            } else {
996                if (mHasInputFilter) {
997                    mHasInputFilter = false;
998                    mInputFilter.setEnabledFeatures(0);
999                    inputFilter = null;
1000                    setInputFilter = true;
1001                }
1002            }
1003        }
1004        if (setInputFilter) {
1005            try {
1006                mWindowManagerService.setInputFilter(inputFilter);
1007            } catch (RemoteException re) {
1008                /* ignore */
1009            }
1010        }
1011    }
1012
1013    private void showEnableTouchExplorationDialog(final Service service) {
1014        String label = service.mResolveInfo.loadLabel(
1015                mContext.getPackageManager()).toString();
1016        synchronized (mLock) {
1017            final UserState state = getCurrentUserStateLocked();
1018            if (state.mIsTouchExplorationEnabled) {
1019                return;
1020            }
1021            if (mEnableTouchExplorationDialog != null
1022                    && mEnableTouchExplorationDialog.isShowing()) {
1023                return;
1024            }
1025            mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext)
1026                .setIcon(android.R.drawable.ic_dialog_alert)
1027                .setPositiveButton(android.R.string.ok, new OnClickListener() {
1028                    @Override
1029                    public void onClick(DialogInterface dialog, int which) {
1030                        // The user allowed the service to toggle touch exploration.
1031                        state.mTouchExplorationGrantedServices.add(service.mComponentName);
1032                        persistComponentNamesToSettingLocked(
1033                                Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
1034                                       state.mTouchExplorationGrantedServices, state.mUserId);
1035                        // Enable touch exploration.
1036                        Settings.Secure.putIntForUser(mContext.getContentResolver(),
1037                                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1,
1038                                service.mUserId);
1039                    }
1040                })
1041                .setNegativeButton(android.R.string.cancel, new OnClickListener() {
1042                    @Override
1043                    public void onClick(DialogInterface dialog, int which) {
1044                        dialog.dismiss();
1045                    }
1046                })
1047                .setTitle(R.string.enable_explore_by_touch_warning_title)
1048                .setMessage(mContext.getString(
1049                        R.string.enable_explore_by_touch_warning_message, label))
1050                .create();
1051            mEnableTouchExplorationDialog.getWindow().setType(
1052                    WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
1053            mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true);
1054            mEnableTouchExplorationDialog.show();
1055        }
1056    }
1057
1058    private int getClientState(UserState userState) {
1059        int clientState = 0;
1060        if (userState.mIsAccessibilityEnabled) {
1061            clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
1062        }
1063        // Touch exploration relies on enabled accessibility.
1064        if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) {
1065            clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
1066        }
1067        return clientState;
1068    }
1069
1070    private void recreateInternalStateLocked(UserState userState) {
1071        populateInstalledAccessibilityServiceLocked(userState);
1072        populateEnabledAccessibilityServicesLocked(userState);
1073        populateTouchExplorationGrantedAccessibilityServicesLocked(userState);
1074
1075        handleTouchExplorationEnabledSettingChangedLocked(userState);
1076        handleDisplayMagnificationEnabledSettingChangedLocked(userState);
1077        handleAccessibilityEnabledSettingChangedLocked(userState);
1078
1079        updateInputFilterLocked(userState);
1080        scheduleSendStateToClientsLocked(userState);
1081    }
1082
1083    private void handleAccessibilityEnabledSettingChangedLocked(UserState userState) {
1084        userState.mIsAccessibilityEnabled = Settings.Secure.getIntForUser(
1085               mContext.getContentResolver(),
1086               Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1;
1087        if (userState.mIsAccessibilityEnabled ) {
1088            manageServicesLocked(userState);
1089        } else {
1090            unbindAllServicesLocked(userState);
1091        }
1092    }
1093
1094    private void handleTouchExplorationEnabledSettingChangedLocked(UserState userState) {
1095        userState.mIsTouchExplorationEnabled = Settings.Secure.getIntForUser(
1096                mContext.getContentResolver(),
1097                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1;
1098    }
1099
1100    private void handleDisplayMagnificationEnabledSettingChangedLocked(UserState userState) {
1101        userState.mIsDisplayMagnificationEnabled = Settings.Secure.getIntForUser(
1102                mContext.getContentResolver(),
1103                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
1104                0, userState.mUserId) == 1;
1105    }
1106
1107    private void handleTouchExplorationGrantedAccessibilityServicesChangedLocked(
1108            UserState userState) {
1109        final int serviceCount = userState.mServices.size();
1110        for (int i = 0; i < serviceCount; i++) {
1111            Service service = userState.mServices.get(i);
1112            if (service.mRequestTouchExplorationMode
1113                    && userState.mTouchExplorationGrantedServices.contains(
1114                            service.mComponentName)) {
1115                tryEnableTouchExplorationLocked(service);
1116                return;
1117            }
1118        }
1119        if (userState.mIsTouchExplorationEnabled) {
1120            Settings.Secure.putIntForUser(mContext.getContentResolver(),
1121                    Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId);
1122        }
1123    }
1124
1125    private void tryEnableTouchExplorationLocked(final Service service) {
1126        UserState userState = getUserStateLocked(service.mUserId);
1127        if (!userState.mIsTouchExplorationEnabled && service.mRequestTouchExplorationMode) {
1128            final boolean canToggleTouchExploration =
1129                    userState.mTouchExplorationGrantedServices.contains(service.mComponentName);
1130            if (!service.mIsAutomation && !canToggleTouchExploration) {
1131                showEnableTouchExplorationDialog(service);
1132            } else {
1133                Settings.Secure.putIntForUser(mContext.getContentResolver(),
1134                        Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, userState.mUserId);
1135            }
1136        }
1137    }
1138
1139    private void tryDisableTouchExplorationLocked(Service service) {
1140        UserState userState = getUserStateLocked(service.mUserId);
1141        if (userState.mIsTouchExplorationEnabled) {
1142            final int serviceCount = userState.mServices.size();
1143            for (int i = 0; i < serviceCount; i++) {
1144                Service other = userState.mServices.get(i);
1145                if (other != service && other.mRequestTouchExplorationMode) {
1146                    return;
1147                }
1148            }
1149            Settings.Secure.putIntForUser(mContext.getContentResolver(),
1150                    Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId);
1151        }
1152    }
1153
1154    private class AccessibilityConnectionWrapper implements DeathRecipient {
1155        private final int mWindowId;
1156        private final int mUserId;
1157        private final IAccessibilityInteractionConnection mConnection;
1158
1159        public AccessibilityConnectionWrapper(int windowId,
1160                IAccessibilityInteractionConnection connection, int userId) {
1161            mWindowId = windowId;
1162            mUserId = userId;
1163            mConnection = connection;
1164        }
1165
1166        public void linkToDeath() throws RemoteException {
1167            mConnection.asBinder().linkToDeath(this, 0);
1168        }
1169
1170        public void unlinkToDeath() {
1171            mConnection.asBinder().unlinkToDeath(this, 0);
1172        }
1173
1174        @Override
1175        public void binderDied() {
1176            unlinkToDeath();
1177            synchronized (mLock) {
1178                removeAccessibilityInteractionConnectionLocked(mWindowId, mUserId);
1179            }
1180        }
1181    }
1182
1183    private final class MainHandler extends Handler {
1184        public static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 1;
1185        public static final int MSG_SEND_STATE_TO_CLIENTS = 2;
1186        public static final int MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER = 3;
1187        public static final int MSG_SEND_RECREATE_INTERNAL_STATE = 4;
1188        public static final int MSG_UPDATE_ACTIVE_WINDOW = 5;
1189
1190        public MainHandler(Looper looper) {
1191            super(looper);
1192        }
1193
1194        @Override
1195        public void handleMessage(Message msg) {
1196            final int type = msg.what;
1197            switch (type) {
1198                case MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER: {
1199                    AccessibilityEvent event = (AccessibilityEvent) msg.obj;
1200                    synchronized (mLock) {
1201                        if (mHasInputFilter && mInputFilter != null) {
1202                            mInputFilter.notifyAccessibilityEvent(event);
1203                        }
1204                    }
1205                    event.recycle();
1206                } break;
1207                case MSG_SEND_STATE_TO_CLIENTS: {
1208                    final int clientState = msg.arg1;
1209                    final int userId = msg.arg2;
1210                    sendStateToClients(clientState, mGlobalClients);
1211                    sendStateToClientsForUser(clientState, userId);
1212                } break;
1213                case MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER: {
1214                    final int userId = msg.arg1;
1215                    sendStateToClientsForUser(0, userId);
1216                } break;
1217                case MSG_SEND_RECREATE_INTERNAL_STATE: {
1218                    final int userId = msg.arg1;
1219                    synchronized (mLock) {
1220                        UserState userState = getUserStateLocked(userId);
1221                        recreateInternalStateLocked(userState);
1222                    }
1223                } break;
1224                case MSG_UPDATE_ACTIVE_WINDOW: {
1225                    final int windowId = msg.arg1;
1226                    final int eventType = msg.arg2;
1227                    mSecurityPolicy.updateActiveWindow(windowId, eventType);
1228                } break;
1229            }
1230        }
1231
1232        private void sendStateToClientsForUser(int clientState, int userId) {
1233            final UserState userState;
1234            synchronized (mLock) {
1235                userState = getUserStateLocked(userId);
1236            }
1237            sendStateToClients(clientState, userState.mClients);
1238        }
1239
1240        private void sendStateToClients(int clientState,
1241                RemoteCallbackList<IAccessibilityManagerClient> clients) {
1242            try {
1243                final int userClientCount = clients.beginBroadcast();
1244                for (int i = 0; i < userClientCount; i++) {
1245                    IAccessibilityManagerClient client = clients.getBroadcastItem(i);
1246                    try {
1247                        client.setState(clientState);
1248                    } catch (RemoteException re) {
1249                        /* ignore */
1250                    }
1251                }
1252            } finally {
1253                clients.finishBroadcast();
1254            }
1255        }
1256    }
1257
1258    /**
1259     * This class represents an accessibility service. It stores all per service
1260     * data required for the service management, provides API for starting/stopping the
1261     * service and is responsible for adding/removing the service in the data structures
1262     * for service management. The class also exposes configuration interface that is
1263     * passed to the service it represents as soon it is bound. It also serves as the
1264     * connection for the service.
1265     */
1266    class Service extends IAccessibilityServiceConnection.Stub
1267            implements ServiceConnection, DeathRecipient {
1268
1269        // We pick the MSB to avoid collision since accessibility event types are
1270        // used as message types allowing us to remove messages per event type.
1271        private static final int MSG_ON_GESTURE = 0x80000000;
1272
1273        final int mUserId;
1274
1275        int mId = 0;
1276
1277        AccessibilityServiceInfo mAccessibilityServiceInfo;
1278
1279        IBinder mService;
1280
1281        IAccessibilityServiceClient mServiceInterface;
1282
1283        int mEventTypes;
1284
1285        int mFeedbackType;
1286
1287        Set<String> mPackageNames = new HashSet<String>();
1288
1289        boolean mIsDefault;
1290
1291        boolean mRequestTouchExplorationMode;
1292
1293        boolean mIncludeNotImportantViews;
1294
1295        long mNotificationTimeout;
1296
1297        ComponentName mComponentName;
1298
1299        Intent mIntent;
1300
1301        boolean mCanRetrieveScreenContent;
1302
1303        boolean mIsAutomation;
1304
1305        final Rect mTempBounds = new Rect();
1306
1307        final ResolveInfo mResolveInfo;
1308
1309        // the events pending events to be dispatched to this service
1310        final SparseArray<AccessibilityEvent> mPendingEvents =
1311            new SparseArray<AccessibilityEvent>();
1312
1313        /**
1314         * Handler for delayed event dispatch.
1315         */
1316        public Handler mHandler = new Handler(mMainHandler.getLooper()) {
1317            @Override
1318            public void handleMessage(Message message) {
1319                final int type = message.what;
1320                switch (type) {
1321                    case MSG_ON_GESTURE: {
1322                        final int gestureId = message.arg1;
1323                        notifyGestureInternal(gestureId);
1324                    } break;
1325                    default: {
1326                        final int eventType = type;
1327                        notifyAccessibilityEventInternal(eventType);
1328                    } break;
1329                }
1330            }
1331        };
1332
1333        public Service(int userId, ComponentName componentName,
1334                AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation) {
1335            mUserId = userId;
1336            mResolveInfo = accessibilityServiceInfo.getResolveInfo();
1337            mId = sIdCounter++;
1338            mComponentName = componentName;
1339            mAccessibilityServiceInfo = accessibilityServiceInfo;
1340            mIsAutomation = isAutomation;
1341            if (!isAutomation) {
1342                mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent();
1343                mRequestTouchExplorationMode =
1344                    (accessibilityServiceInfo.flags
1345                            & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
1346                mIntent = new Intent().setComponent(mComponentName);
1347                mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
1348                        com.android.internal.R.string.accessibility_binding_label);
1349                mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
1350                        mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
1351            } else {
1352                mCanRetrieveScreenContent = true;
1353            }
1354            setDynamicallyConfigurableProperties(accessibilityServiceInfo);
1355        }
1356
1357        public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) {
1358            mEventTypes = info.eventTypes;
1359            mFeedbackType = info.feedbackType;
1360            String[] packageNames = info.packageNames;
1361            if (packageNames != null) {
1362                mPackageNames.addAll(Arrays.asList(packageNames));
1363            }
1364            mNotificationTimeout = info.notificationTimeout;
1365            mIsDefault = (info.flags & DEFAULT) != 0;
1366
1367            if (mIsAutomation || info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion
1368                    >= Build.VERSION_CODES.JELLY_BEAN) {
1369                mIncludeNotImportantViews =
1370                    (info.flags & FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0;
1371            }
1372
1373            mRequestTouchExplorationMode = (info.flags
1374                    & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
1375
1376            // If this service is up and running we may have to enable touch
1377            // exploration, otherwise this will happen when the service connects.
1378            synchronized (mLock) {
1379                if (isConfigured()) {
1380                    if (mRequestTouchExplorationMode) {
1381                        tryEnableTouchExplorationLocked(this);
1382                    } else {
1383                        tryDisableTouchExplorationLocked(this);
1384                    }
1385                }
1386            }
1387        }
1388
1389        /**
1390         * Binds to the accessibility service.
1391         *
1392         * @return True if binding is successful.
1393         */
1394        public boolean bind() {
1395            if (!mIsAutomation && mService == null) {
1396                return mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE, mUserId);
1397            }
1398            return false;
1399        }
1400
1401        /**
1402         * Unbinds form the accessibility service and removes it from the data
1403         * structures for service management.
1404         *
1405         * @return True if unbinding is successful.
1406         */
1407        public boolean unbind() {
1408            if (mService != null) {
1409                synchronized (mLock) {
1410                    tryRemoveServiceLocked(this);
1411                }
1412                if (!mIsAutomation) {
1413                    mContext.unbindService(this);
1414                }
1415                return true;
1416            }
1417            return false;
1418        }
1419
1420        /**
1421         * Returns if the service is configured i.e. at least event types of interest
1422         * and feedback type must be set.
1423         *
1424         * @return True if the service is configured, false otherwise.
1425         */
1426        public boolean isConfigured() {
1427            return (mEventTypes != 0 && mFeedbackType != 0 && mService != null);
1428        }
1429
1430        @Override
1431        public AccessibilityServiceInfo getServiceInfo() {
1432            synchronized (mLock) {
1433                return mAccessibilityServiceInfo;
1434            }
1435        }
1436
1437        @Override
1438        public void setServiceInfo(AccessibilityServiceInfo info) {
1439            final long identity = Binder.clearCallingIdentity();
1440            try {
1441                synchronized (mLock) {
1442                    // If the XML manifest had data to configure the service its info
1443                    // should be already set. In such a case update only the dynamically
1444                    // configurable properties.
1445                    AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
1446                    if (oldInfo != null) {
1447                        oldInfo.updateDynamicallyConfigurableProperties(info);
1448                        setDynamicallyConfigurableProperties(oldInfo);
1449                    } else {
1450                        setDynamicallyConfigurableProperties(info);
1451                    }
1452                }
1453            } finally {
1454                Binder.restoreCallingIdentity(identity);
1455            }
1456        }
1457
1458        @Override
1459        public void onServiceConnected(ComponentName componentName, IBinder service) {
1460            mService = service;
1461            mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
1462            try {
1463                mServiceInterface.setConnection(this, mId);
1464                synchronized (mLock) {
1465                    tryAddServiceLocked(this, mUserId);
1466                }
1467            } catch (RemoteException re) {
1468                Slog.w(LOG_TAG, "Error while setting Controller for service: " + service, re);
1469            }
1470        }
1471
1472        @Override
1473        public float findAccessibilityNodeInfoByViewId(int accessibilityWindowId,
1474                long accessibilityNodeId, int viewId, int interactionId,
1475                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1476                throws RemoteException {
1477            final int resolvedWindowId;
1478            IAccessibilityInteractionConnection connection = null;
1479            synchronized (mLock) {
1480                final int resolvedUserId = mSecurityPolicy
1481                        .resolveCallingUserIdEnforcingPermissionsLocked(
1482                                UserHandle.getCallingUserId());
1483                if (resolvedUserId != mCurrentUserId) {
1484                    return -1;
1485                }
1486                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1487                final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
1488                if (!permissionGranted) {
1489                    return 0;
1490                } else {
1491                    resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1492                    connection = getConnectionLocked(resolvedWindowId);
1493                    if (connection == null) {
1494                        return 0;
1495                    }
1496                }
1497            }
1498            final int flags = (mIncludeNotImportantViews) ?
1499                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1500            final int interrogatingPid = Binder.getCallingPid();
1501            final long identityToken = Binder.clearCallingIdentity();
1502            try {
1503                connection.findAccessibilityNodeInfoByViewId(accessibilityNodeId, viewId,
1504                        interactionId, callback, flags, interrogatingPid, interrogatingTid);
1505                return getCompatibilityScale(resolvedWindowId);
1506            } catch (RemoteException re) {
1507                if (DEBUG) {
1508                    Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
1509                }
1510            } finally {
1511                Binder.restoreCallingIdentity(identityToken);
1512            }
1513            return 0;
1514        }
1515
1516        @Override
1517        public float findAccessibilityNodeInfosByText(int accessibilityWindowId,
1518                long accessibilityNodeId, String text, int interactionId,
1519                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1520                throws RemoteException {
1521            final int resolvedWindowId;
1522            IAccessibilityInteractionConnection connection = null;
1523            synchronized (mLock) {
1524                final int resolvedUserId = mSecurityPolicy
1525                        .resolveCallingUserIdEnforcingPermissionsLocked(
1526                        UserHandle.getCallingUserId());
1527                if (resolvedUserId != mCurrentUserId) {
1528                    return -1;
1529                }
1530                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1531                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1532                final boolean permissionGranted =
1533                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1534                if (!permissionGranted) {
1535                    return 0;
1536                } else {
1537                    connection = getConnectionLocked(resolvedWindowId);
1538                    if (connection == null) {
1539                        return 0;
1540                    }
1541                }
1542            }
1543            final int flags = (mIncludeNotImportantViews) ?
1544                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1545            final int interrogatingPid = Binder.getCallingPid();
1546            final long identityToken = Binder.clearCallingIdentity();
1547            try {
1548                connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
1549                        interactionId, callback, flags, interrogatingPid,
1550                        interrogatingTid);
1551                return getCompatibilityScale(resolvedWindowId);
1552            } catch (RemoteException re) {
1553                if (DEBUG) {
1554                    Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
1555                }
1556            } finally {
1557                Binder.restoreCallingIdentity(identityToken);
1558            }
1559            return 0;
1560        }
1561
1562        @Override
1563        public float findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
1564                long accessibilityNodeId, int interactionId,
1565                IAccessibilityInteractionConnectionCallback callback, int flags,
1566                long interrogatingTid) throws RemoteException {
1567            final int resolvedWindowId;
1568            IAccessibilityInteractionConnection connection = null;
1569            synchronized (mLock) {
1570                final int resolvedUserId = mSecurityPolicy
1571                        .resolveCallingUserIdEnforcingPermissionsLocked(
1572                        UserHandle.getCallingUserId());
1573                if (resolvedUserId != mCurrentUserId) {
1574                    return -1;
1575                }
1576                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1577                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1578                final boolean permissionGranted =
1579                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1580                if (!permissionGranted) {
1581                    return 0;
1582                } else {
1583                    connection = getConnectionLocked(resolvedWindowId);
1584                    if (connection == null) {
1585                        return 0;
1586                    }
1587                }
1588            }
1589            final int allFlags = flags | ((mIncludeNotImportantViews) ?
1590                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0);
1591            final int interrogatingPid = Binder.getCallingPid();
1592            final long identityToken = Binder.clearCallingIdentity();
1593            try {
1594                connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
1595                        interactionId, callback, allFlags, interrogatingPid, interrogatingTid);
1596                return getCompatibilityScale(resolvedWindowId);
1597            } catch (RemoteException re) {
1598                if (DEBUG) {
1599                    Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
1600                }
1601            } finally {
1602                Binder.restoreCallingIdentity(identityToken);
1603            }
1604            return 0;
1605        }
1606
1607        @Override
1608        public float findFocus(int accessibilityWindowId, long accessibilityNodeId,
1609                int focusType, int interactionId,
1610                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1611                throws RemoteException {
1612            final int resolvedWindowId;
1613            IAccessibilityInteractionConnection connection = null;
1614            synchronized (mLock) {
1615                final int resolvedUserId = mSecurityPolicy
1616                        .resolveCallingUserIdEnforcingPermissionsLocked(
1617                        UserHandle.getCallingUserId());
1618                if (resolvedUserId != mCurrentUserId) {
1619                    return -1;
1620                }
1621                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1622                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1623                final boolean permissionGranted =
1624                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1625                if (!permissionGranted) {
1626                    return 0;
1627                } else {
1628                    connection = getConnectionLocked(resolvedWindowId);
1629                    if (connection == null) {
1630                        return 0;
1631                    }
1632                }
1633            }
1634            final int flags = (mIncludeNotImportantViews) ?
1635                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1636            final int interrogatingPid = Binder.getCallingPid();
1637            final long identityToken = Binder.clearCallingIdentity();
1638            try {
1639                connection.findFocus(accessibilityNodeId, focusType, interactionId, callback,
1640                        flags, interrogatingPid, interrogatingTid);
1641                return getCompatibilityScale(resolvedWindowId);
1642            } catch (RemoteException re) {
1643                if (DEBUG) {
1644                    Slog.e(LOG_TAG, "Error calling findAccessibilityFocus()");
1645                }
1646            } finally {
1647                Binder.restoreCallingIdentity(identityToken);
1648            }
1649            return 0;
1650        }
1651
1652        @Override
1653        public float focusSearch(int accessibilityWindowId, long accessibilityNodeId,
1654                int direction, int interactionId,
1655                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1656                throws RemoteException {
1657            final int resolvedWindowId;
1658            IAccessibilityInteractionConnection connection = null;
1659            synchronized (mLock) {
1660                final int resolvedUserId = mSecurityPolicy
1661                        .resolveCallingUserIdEnforcingPermissionsLocked(
1662                        UserHandle.getCallingUserId());
1663                if (resolvedUserId != mCurrentUserId) {
1664                    return -1;
1665                }
1666                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1667                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1668                final boolean permissionGranted =
1669                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1670                if (!permissionGranted) {
1671                    return 0;
1672                } else {
1673                    connection = getConnectionLocked(resolvedWindowId);
1674                    if (connection == null) {
1675                        return 0;
1676                    }
1677                }
1678            }
1679            final int flags = (mIncludeNotImportantViews) ?
1680                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1681            final int interrogatingPid = Binder.getCallingPid();
1682            final long identityToken = Binder.clearCallingIdentity();
1683            try {
1684                connection.focusSearch(accessibilityNodeId, direction, interactionId, callback,
1685                        flags, interrogatingPid, interrogatingTid);
1686                return getCompatibilityScale(resolvedWindowId);
1687            } catch (RemoteException re) {
1688                if (DEBUG) {
1689                    Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
1690                }
1691            } finally {
1692                Binder.restoreCallingIdentity(identityToken);
1693            }
1694            return 0;
1695        }
1696
1697        @Override
1698        public boolean performAccessibilityAction(int accessibilityWindowId,
1699                long accessibilityNodeId, int action, Bundle arguments, int interactionId,
1700                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1701                throws RemoteException {
1702            final int resolvedWindowId;
1703            IAccessibilityInteractionConnection connection = null;
1704            synchronized (mLock) {
1705                final int resolvedUserId = mSecurityPolicy
1706                        .resolveCallingUserIdEnforcingPermissionsLocked(
1707                        UserHandle.getCallingUserId());
1708                if (resolvedUserId != mCurrentUserId) {
1709                    return false;
1710                }
1711                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1712                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1713                final boolean permissionGranted = mSecurityPolicy.canPerformActionLocked(this,
1714                        resolvedWindowId, action, arguments);
1715                if (!permissionGranted) {
1716                    return false;
1717                } else {
1718                    connection = getConnectionLocked(resolvedWindowId);
1719                    if (connection == null) {
1720                        return false;
1721                    }
1722                }
1723            }
1724            final int flags = (mIncludeNotImportantViews) ?
1725                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1726            final int interrogatingPid = Binder.getCallingPid();
1727            final long identityToken = Binder.clearCallingIdentity();
1728            try {
1729                connection.performAccessibilityAction(accessibilityNodeId, action, arguments,
1730                        interactionId, callback, flags, interrogatingPid, interrogatingTid);
1731            } catch (RemoteException re) {
1732                if (DEBUG) {
1733                    Slog.e(LOG_TAG, "Error calling performAccessibilityAction()");
1734                }
1735            } finally {
1736                Binder.restoreCallingIdentity(identityToken);
1737            }
1738            return true;
1739        }
1740
1741        public boolean performGlobalAction(int action) {
1742            synchronized (mLock) {
1743                final int resolvedUserId = mSecurityPolicy
1744                        .resolveCallingUserIdEnforcingPermissionsLocked(
1745                        UserHandle.getCallingUserId());
1746                if (resolvedUserId != mCurrentUserId) {
1747                    return false;
1748                }
1749            }
1750            final long identity = Binder.clearCallingIdentity();
1751            try {
1752                switch (action) {
1753                    case AccessibilityService.GLOBAL_ACTION_BACK: {
1754                        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK);
1755                    } return true;
1756                    case AccessibilityService.GLOBAL_ACTION_HOME: {
1757                        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME);
1758                    } return true;
1759                    case AccessibilityService.GLOBAL_ACTION_RECENTS: {
1760                        openRecents();
1761                    } return true;
1762                    case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: {
1763                        expandNotifications();
1764                    } return true;
1765                    case AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS: {
1766                        expandQuickSettings();
1767                    } return true;
1768                }
1769                return false;
1770            } finally {
1771                Binder.restoreCallingIdentity(identity);
1772            }
1773        }
1774
1775        public void onServiceDisconnected(ComponentName componentName) {
1776            /* do nothing - #binderDied takes care */
1777        }
1778
1779        public void linkToOwnDeath() throws RemoteException {
1780            mService.linkToDeath(this, 0);
1781        }
1782
1783        public void unlinkToOwnDeath() {
1784            mService.unlinkToDeath(this, 0);
1785        }
1786
1787        public void dispose() {
1788            try {
1789                // Clear the proxy in the other process so this
1790                // IAccessibilityServiceConnection can be garbage collected.
1791                mServiceInterface.setConnection(null, mId);
1792            } catch (RemoteException re) {
1793                /* ignore */
1794            }
1795            mService = null;
1796            mServiceInterface = null;
1797        }
1798
1799        public void binderDied() {
1800            synchronized (mLock) {
1801                // The death recipient is unregistered in tryRemoveServiceLocked
1802                tryRemoveServiceLocked(this);
1803                // We no longer have an automation service, so restore
1804                // the state based on values in the settings database.
1805                if (mIsAutomation) {
1806                    mUiAutomationService = null;
1807                    recreateInternalStateLocked(getUserStateLocked(mUserId));
1808                }
1809            }
1810        }
1811
1812        /**
1813         * Performs a notification for an {@link AccessibilityEvent}.
1814         *
1815         * @param event The event.
1816         */
1817        public void notifyAccessibilityEvent(AccessibilityEvent event) {
1818            synchronized (mLock) {
1819                final int eventType = event.getEventType();
1820                // Make a copy since during dispatch it is possible the event to
1821                // be modified to remove its source if the receiving service does
1822                // not have permission to access the window content.
1823                AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
1824                AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
1825                mPendingEvents.put(eventType, newEvent);
1826
1827                final int what = eventType;
1828                if (oldEvent != null) {
1829                    mHandler.removeMessages(what);
1830                    oldEvent.recycle();
1831                }
1832
1833                Message message = mHandler.obtainMessage(what);
1834                mHandler.sendMessageDelayed(message, mNotificationTimeout);
1835            }
1836        }
1837
1838        /**
1839         * Notifies an accessibility service client for a scheduled event given the event type.
1840         *
1841         * @param eventType The type of the event to dispatch.
1842         */
1843        private void notifyAccessibilityEventInternal(int eventType) {
1844            IAccessibilityServiceClient listener;
1845            AccessibilityEvent event;
1846
1847            synchronized (mLock) {
1848                listener = mServiceInterface;
1849
1850                // If the service died/was disabled while the message for dispatching
1851                // the accessibility event was propagating the listener may be null.
1852                if (listener == null) {
1853                    return;
1854                }
1855
1856                event = mPendingEvents.get(eventType);
1857
1858                // Check for null here because there is a concurrent scenario in which this
1859                // happens: 1) A binder thread calls notifyAccessibilityServiceDelayedLocked
1860                // which posts a message for dispatching an event. 2) The message is pulled
1861                // from the queue by the handler on the service thread and the latter is
1862                // just about to acquire the lock and call this method. 3) Now another binder
1863                // thread acquires the lock calling notifyAccessibilityServiceDelayedLocked
1864                // so the service thread waits for the lock; 4) The binder thread replaces
1865                // the event with a more recent one (assume the same event type) and posts a
1866                // dispatch request releasing the lock. 5) Now the main thread is unblocked and
1867                // dispatches the event which is removed from the pending ones. 6) And ... now
1868                // the service thread handles the last message posted by the last binder call
1869                // but the event is already dispatched and hence looking it up in the pending
1870                // ones yields null. This check is much simpler that keeping count for each
1871                // event type of each service to catch such a scenario since only one message
1872                // is processed at a time.
1873                if (event == null) {
1874                    return;
1875                }
1876
1877                mPendingEvents.remove(eventType);
1878                if (mSecurityPolicy.canRetrieveWindowContent(this)) {
1879                    event.setConnectionId(mId);
1880                } else {
1881                    event.setSource(null);
1882                }
1883                event.setSealed(true);
1884            }
1885
1886            try {
1887                listener.onAccessibilityEvent(event);
1888                if (DEBUG) {
1889                    Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
1890                }
1891            } catch (RemoteException re) {
1892                Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re);
1893            } finally {
1894                event.recycle();
1895            }
1896        }
1897
1898        public void notifyGesture(int gestureId) {
1899            mHandler.obtainMessage(MSG_ON_GESTURE, gestureId, 0).sendToTarget();
1900        }
1901
1902        private void notifyGestureInternal(int gestureId) {
1903            IAccessibilityServiceClient listener = mServiceInterface;
1904            if (listener != null) {
1905                try {
1906                    listener.onGesture(gestureId);
1907                } catch (RemoteException re) {
1908                    Slog.e(LOG_TAG, "Error during sending gesture " + gestureId
1909                            + " to " + mService, re);
1910                }
1911            }
1912        }
1913
1914        private void sendDownAndUpKeyEvents(int keyCode) {
1915            final long token = Binder.clearCallingIdentity();
1916
1917            // Inject down.
1918            final long downTime = SystemClock.uptimeMillis();
1919            KeyEvent down = KeyEvent.obtain(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
1920                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
1921                    InputDevice.SOURCE_KEYBOARD, null);
1922            InputManager.getInstance().injectInputEvent(down,
1923                    InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
1924            down.recycle();
1925
1926            // Inject up.
1927            final long upTime = SystemClock.uptimeMillis();
1928            KeyEvent up = KeyEvent.obtain(downTime, upTime, KeyEvent.ACTION_UP, keyCode, 0, 0,
1929                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
1930                    InputDevice.SOURCE_KEYBOARD, null);
1931            InputManager.getInstance().injectInputEvent(up,
1932                    InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
1933            up.recycle();
1934
1935            Binder.restoreCallingIdentity(token);
1936        }
1937
1938        private void expandNotifications() {
1939            final long token = Binder.clearCallingIdentity();
1940
1941            StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
1942                    android.app.Service.STATUS_BAR_SERVICE);
1943            statusBarManager.expandNotificationsPanel();
1944
1945            Binder.restoreCallingIdentity(token);
1946        }
1947
1948        private void expandQuickSettings() {
1949            final long token = Binder.clearCallingIdentity();
1950
1951            StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
1952                    android.app.Service.STATUS_BAR_SERVICE);
1953            statusBarManager.expandSettingsPanel();
1954
1955            Binder.restoreCallingIdentity(token);
1956        }
1957
1958        private void openRecents() {
1959            final long token = Binder.clearCallingIdentity();
1960
1961            IStatusBarService statusBarService = IStatusBarService.Stub.asInterface(
1962                    ServiceManager.getService("statusbar"));
1963            try {
1964                statusBarService.toggleRecentApps();
1965            } catch (RemoteException e) {
1966                Slog.e(LOG_TAG, "Error toggling recent apps.");
1967            }
1968
1969            Binder.restoreCallingIdentity(token);
1970        }
1971
1972        private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
1973            if (DEBUG) {
1974                Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
1975            }
1976            AccessibilityConnectionWrapper wrapper = mGlobalInteractionConnections.get(windowId);
1977            if (wrapper == null) {
1978                wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId);
1979            }
1980            if (wrapper != null && wrapper.mConnection != null) {
1981                return wrapper.mConnection;
1982            }
1983            if (DEBUG) {
1984                Slog.e(LOG_TAG, "No interaction connection to window: " + windowId);
1985            }
1986            return null;
1987        }
1988
1989        private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) {
1990            if (accessibilityWindowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) {
1991                return mSecurityPolicy.mActiveWindowId;
1992            }
1993            return accessibilityWindowId;
1994        }
1995
1996        private float getCompatibilityScale(int windowId) {
1997            try {
1998                IBinder windowToken = mGlobalWindowTokens.get(windowId);
1999                if (windowToken != null) {
2000                    return mWindowManagerService.getWindowCompatibilityScale(windowToken);
2001                }
2002                windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
2003                if (windowToken != null) {
2004                    return mWindowManagerService.getWindowCompatibilityScale(windowToken);
2005                }
2006            } catch (RemoteException re) {
2007                /* ignore */
2008            }
2009            return 1.0f;
2010        }
2011    }
2012
2013    final class SecurityPolicy {
2014        private static final int VALID_ACTIONS =
2015            AccessibilityNodeInfo.ACTION_CLICK
2016            | AccessibilityNodeInfo.ACTION_LONG_CLICK
2017            | AccessibilityNodeInfo.ACTION_FOCUS
2018            | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS
2019            | AccessibilityNodeInfo.ACTION_SELECT
2020            | AccessibilityNodeInfo.ACTION_CLEAR_SELECTION
2021            | AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS
2022            | AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS
2023            | AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2024            | AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2025            | AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT
2026            | AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT
2027            | AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
2028            | AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD;
2029
2030        private static final int RETRIEVAL_ALLOWING_EVENT_TYPES =
2031            AccessibilityEvent.TYPE_VIEW_CLICKED
2032            | AccessibilityEvent.TYPE_VIEW_FOCUSED
2033            | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
2034            | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
2035            | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED
2036            | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
2037            | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
2038            | AccessibilityEvent.TYPE_VIEW_SELECTED
2039            | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
2040            | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
2041            | AccessibilityEvent.TYPE_VIEW_SCROLLED
2042            | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
2043            | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED;
2044
2045        private int mActiveWindowId;
2046
2047        private boolean canDispatchAccessibilityEvent(AccessibilityEvent event) {
2048            // Send window changed event only for the retrieval allowing window.
2049            return (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
2050                    || event.getWindowId() == mActiveWindowId);
2051        }
2052
2053        public void updateEventSourceLocked(AccessibilityEvent event) {
2054            if ((event.getEventType() & RETRIEVAL_ALLOWING_EVENT_TYPES) == 0) {
2055                event.setSource(null);
2056            }
2057        }
2058
2059        public void updateActiveWindow(int windowId, int eventType) {
2060            // The active window is either the window that has input focus or
2061            // the window that the user is currently touching. If the user is
2062            // touching a window that does not have input focus as soon as the
2063            // the user stops touching that window the focused window becomes
2064            // the active one.
2065            switch (eventType) {
2066                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
2067                    if (getFocusedWindowId() == windowId) {
2068                        mActiveWindowId = windowId;
2069                    }
2070                } break;
2071                case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
2072                case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
2073                    mActiveWindowId = windowId;
2074                } break;
2075                case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END: {
2076                    mActiveWindowId = getFocusedWindowId();
2077                } break;
2078            }
2079        }
2080
2081        public int getRetrievalAllowingWindowLocked() {
2082            return mActiveWindowId;
2083        }
2084
2085        public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) {
2086            return canRetrieveWindowContent(service) && isRetrievalAllowingWindow(windowId);
2087        }
2088
2089        public boolean canPerformActionLocked(Service service, int windowId, int action,
2090                Bundle arguments) {
2091            return canRetrieveWindowContent(service)
2092                && isRetrievalAllowingWindow(windowId)
2093                && isActionPermitted(action);
2094        }
2095
2096        public boolean canRetrieveWindowContent(Service service) {
2097            return service.mCanRetrieveScreenContent;
2098        }
2099
2100        public void enforceCanRetrieveWindowContent(Service service) throws RemoteException {
2101            // This happens due to incorrect registration so make it apparent.
2102            if (!canRetrieveWindowContent(service)) {
2103                Slog.e(LOG_TAG, "Accessibility serivce " + service.mComponentName + " does not " +
2104                        "declare android:canRetrieveWindowContent.");
2105                throw new RemoteException();
2106            }
2107        }
2108
2109        public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) {
2110            final int callingUid = Binder.getCallingUid();
2111            if (callingUid == Process.SYSTEM_UID
2112                    || callingUid == Process.SHELL_UID) {
2113                return mCurrentUserId;
2114            }
2115            final int callingUserId = UserHandle.getUserId(callingUid);
2116            if (callingUserId == userId) {
2117                return userId;
2118            }
2119            if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS)
2120                    && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) {
2121                throw new SecurityException("Call from user " + callingUserId + " as user "
2122                        + userId + " without permission INTERACT_ACROSS_USERS or "
2123                        + "INTERACT_ACROSS_USERS_FULL not allowed.");
2124            }
2125            if (userId == UserHandle.USER_CURRENT
2126                    || userId == UserHandle.USER_CURRENT_OR_SELF) {
2127                return mCurrentUserId;
2128            }
2129            throw new IllegalArgumentException("Calling user can be changed to only "
2130                    + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
2131        }
2132
2133        public boolean isCallerInteractingAcrossUsers(int userId) {
2134            final int callingUid = Binder.getCallingUid();
2135            return (Binder.getCallingPid() == android.os.Process.myPid()
2136                    || callingUid == Process.SHELL_UID
2137                    || userId == UserHandle.USER_CURRENT
2138                    || userId == UserHandle.USER_CURRENT_OR_SELF);
2139        }
2140
2141        private boolean isRetrievalAllowingWindow(int windowId) {
2142            return (mActiveWindowId == windowId);
2143        }
2144
2145        private boolean isActionPermitted(int action) {
2146             return (VALID_ACTIONS & action) != 0;
2147        }
2148
2149        private void enforceCallingPermission(String permission, String function) {
2150            if (OWN_PROCESS_ID == Binder.getCallingPid()) {
2151                return;
2152            }
2153            if (!hasPermission(permission)) {
2154                throw new SecurityException("You do not have " + permission
2155                        + " required to call " + function);
2156            }
2157        }
2158
2159        private boolean hasPermission(String permission) {
2160            return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
2161        }
2162
2163        private int getFocusedWindowId() {
2164            try {
2165                // We call this only on window focus change or after touch
2166                // exploration gesture end and the shown windows are not that
2167                // many, so the linear look up is just fine.
2168                IBinder token = mWindowManagerService.getFocusedWindowToken();
2169                if (token != null) {
2170                    synchronized (mLock) {
2171                        int windowId = getFocusedWindowIdLocked(token, mGlobalWindowTokens);
2172                        if (windowId < 0) {
2173                            windowId = getFocusedWindowIdLocked(token,
2174                                    getCurrentUserStateLocked().mWindowTokens);
2175                        }
2176                        return windowId;
2177                    }
2178                }
2179            } catch (RemoteException re) {
2180                /* ignore */
2181            }
2182            return -1;
2183        }
2184
2185        private int getFocusedWindowIdLocked(IBinder token, SparseArray<IBinder> windows) {
2186            final int windowCount = windows.size();
2187            for (int i = 0; i < windowCount; i++) {
2188                if (windows.valueAt(i) == token) {
2189                    return windows.keyAt(i);
2190                }
2191            }
2192            return -1;
2193        }
2194    }
2195
2196    private class UserState {
2197        public final int mUserId;
2198
2199        public final CopyOnWriteArrayList<Service> mServices = new CopyOnWriteArrayList<Service>();
2200
2201        public final RemoteCallbackList<IAccessibilityManagerClient> mClients =
2202            new RemoteCallbackList<IAccessibilityManagerClient>();
2203
2204        public final Map<ComponentName, Service> mComponentNameToServiceMap =
2205                new HashMap<ComponentName, Service>();
2206
2207        public final List<AccessibilityServiceInfo> mInstalledServices =
2208                new ArrayList<AccessibilityServiceInfo>();
2209
2210        public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
2211
2212        public final Set<ComponentName> mTouchExplorationGrantedServices =
2213                new HashSet<ComponentName>();
2214
2215        public final SparseArray<AccessibilityConnectionWrapper>
2216                mInteractionConnections =
2217                new SparseArray<AccessibilityConnectionWrapper>();
2218
2219        public final SparseArray<IBinder> mWindowTokens = new SparseArray<IBinder>();
2220
2221        public int mHandledFeedbackTypes = 0;
2222
2223        public boolean mIsAccessibilityEnabled;
2224        public boolean mIsTouchExplorationEnabled;
2225        public boolean mIsDisplayMagnificationEnabled;
2226
2227        public UserState(int userId) {
2228            mUserId = userId;
2229        }
2230    }
2231
2232    private final class AccessibilityContentObserver extends ContentObserver {
2233
2234        private final Uri mAccessibilityEnabledUri = Settings.Secure.getUriFor(
2235                Settings.Secure.ACCESSIBILITY_ENABLED);
2236
2237        private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor(
2238                Settings.Secure.TOUCH_EXPLORATION_ENABLED);
2239
2240        private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor(
2241                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
2242
2243        private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor(
2244                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
2245
2246        private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
2247                .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
2248
2249        public AccessibilityContentObserver(Handler handler) {
2250            super(handler);
2251        }
2252
2253        public void register(ContentResolver contentResolver) {
2254            contentResolver.registerContentObserver(mAccessibilityEnabledUri,
2255                    false, this, UserHandle.USER_ALL);
2256            contentResolver.registerContentObserver(mTouchExplorationEnabledUri,
2257                    false, this, UserHandle.USER_ALL);
2258            contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri,
2259                    false, this, UserHandle.USER_ALL);
2260            contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri,
2261                    false, this, UserHandle.USER_ALL);
2262            contentResolver.registerContentObserver(
2263                    mTouchExplorationGrantedAccessibilityServicesUri,
2264                    false, this, UserHandle.USER_ALL);
2265        }
2266
2267        @Override
2268        public void onChange(boolean selfChange, Uri uri) {
2269            if (mAccessibilityEnabledUri.equals(uri)) {
2270                synchronized (mLock) {
2271                    // We will update when the automation service dies.
2272                    if (mUiAutomationService == null) {
2273                        UserState userState = getCurrentUserStateLocked();
2274                        handleAccessibilityEnabledSettingChangedLocked(userState);
2275                        updateInputFilterLocked(userState);
2276                        scheduleSendStateToClientsLocked(userState);
2277                    }
2278                }
2279            } else if (mTouchExplorationEnabledUri.equals(uri)) {
2280                synchronized (mLock) {
2281                    // We will update when the automation service dies.
2282                    if (mUiAutomationService == null) {
2283                        UserState userState = getCurrentUserStateLocked();
2284                        handleTouchExplorationEnabledSettingChangedLocked(userState);
2285                        updateInputFilterLocked(userState);
2286                        scheduleSendStateToClientsLocked(userState);
2287                    }
2288                }
2289            } else if (mDisplayMagnificationEnabledUri.equals(uri)) {
2290                synchronized (mLock) {
2291                    // We will update when the automation service dies.
2292                    if (mUiAutomationService == null) {
2293                        UserState userState = getCurrentUserStateLocked();
2294                        handleDisplayMagnificationEnabledSettingChangedLocked(userState);
2295                        updateInputFilterLocked(userState);
2296                        scheduleSendStateToClientsLocked(userState);
2297                    }
2298                }
2299            } else if (mEnabledAccessibilityServicesUri.equals(uri)) {
2300                synchronized (mLock) {
2301                    // We will update when the automation service dies.
2302                    if (mUiAutomationService == null) {
2303                        UserState userState = getCurrentUserStateLocked();
2304                        populateEnabledAccessibilityServicesLocked(userState);
2305                        manageServicesLocked(userState);
2306                    }
2307                }
2308            } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
2309                synchronized (mLock) {
2310                    // We will update when the automation service dies.
2311                    if (mUiAutomationService == null) {
2312                        UserState userState = getCurrentUserStateLocked();
2313                        populateTouchExplorationGrantedAccessibilityServicesLocked(userState);
2314                        handleTouchExplorationGrantedAccessibilityServicesChangedLocked(userState);
2315                    }
2316                }
2317            }
2318        }
2319    }
2320}
2321