From 57bf88508e0491caced22c4c592d33aba6d88129 Mon Sep 17 00:00:00 2001 From: Svetoslav Date: Thu, 7 Feb 2013 19:21:42 -0800 Subject: [PATCH] Refactoring of the Accessibility. 1. The accessibility manager service updates its internal state based on which settings are enabled, what accessibility services are installed and what features are requested by the enabled services. It was trying to do the minimal amount of work to react to contextual changes like these which resulted in missed cases and complex code. Now there is a single method that reads the contextual information and single method that reacts to contextual changes. This makes the code much easier to maintain. 2. The accessibility manager service was not updating its internal state when requested features from accessibility services change. It was relying on changing system settings and reacting to the settings change. This is problematic since the internal state is not updated atomically which leads to race condition bugs. For example, if touch exploration is enabled and a service requests it is disabled, the internal state will not be updated but a request for a settings change will be made. Now while the settings change is propagating another request form the same service comes to enable touch exploration but the system incorrectly thinks touch exploration is enabled. At the end the feature is disabled even though it was requested. 3. Fixed a potential NPE if the accessibility input filter's event handler was nullified between processing two event batches. 4. Fixed a bug where, if magnification is enabled, it does not work on the settings screen since the magnified bounds are not pushed from the window manager to the accessibility manager. Change-Id: Idf629a06480e12f0d88372762df6c024fe0d7856 --- .../AccessibilityServiceInfo.java | 34 + .../AccessibilityInputFilter.java | 14 +- .../AccessibilityManagerService.java | 841 +++++++++--------- .../android/server/wm/DisplayMagnifier.java | 3 +- 4 files changed, 441 insertions(+), 451 deletions(-) diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index 033a5981f4a1c..d82b9a38390c3 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -398,6 +398,13 @@ public class AccessibilityServiceInfo implements Parcelable { flags = other.flags; } + /** + * @hide + */ + public void setComponentName(ComponentName component) { + mId = component.flattenToShortString(); + } + /** * The accessibility service id. *

@@ -514,6 +521,33 @@ public class AccessibilityServiceInfo implements Parcelable { mNonLocalizedDescription = parcel.readString(); } + @Override + public int hashCode() { + return 31 * 1 + ((mId == null) ? 0 : mId.hashCode()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj; + if (mId == null) { + if (other.mId != null) { + return false; + } + } else if (!mId.equals(other.mId)) { + return false; + } + return true; + } + @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java index c37f51f12db1e..179db1235b21e 100644 --- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -174,7 +174,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo mMotionEventSequenceStarted = true; } } else { - // Wait for an enter hover event to start processing. + // Wait for an enter hover event to start processing. if (!mHoverEventSequenceStarted) { if (motionEvent.getActionMasked() != MotionEvent.ACTION_HOVER_ENTER) { return; @@ -234,10 +234,14 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo if (DEBUG) { Slog.i(TAG, "Handling batched event: " + event + ", policyFlags: " + policyFlags); } - mPm.userActivity(event.getEventTime(), false); - MotionEvent transformedEvent = MotionEvent.obtain(event); - mEventHandler.onMotionEvent(transformedEvent, event, policyFlags); - transformedEvent.recycle(); + // Since we do batch processing it is possible that by the time the + // next batch is processed the event handle had been set to null. + if (mEventHandler != null) { + mPm.userActivity(event.getEventTime(), false); + MotionEvent transformedEvent = MotionEvent.obtain(event); + mEventHandler.onMotionEvent(transformedEvent, event, policyFlags); + transformedEvent.recycle(); + } } @Override diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index bb040bffd6f2f..aadb790dbae14 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -123,6 +123,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private static final String TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED = "temporaryEnableAccessibilityStateUntilKeyguardRemoved"; + private static final ComponentName sFakeAccessibilityServiceComponentName = + new ComponentName("foo.bar", "FakeService"); + private static final String FUNCTION_DUMP = "dump"; private static final char COMPONENT_NAME_SEPARATOR = ':'; @@ -157,8 +160,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private final MainHandler mMainHandler; - private Service mUiAutomationService; - private Service mQueryBridge; private AlertDialog mEnableTouchExplorationDialog; @@ -167,6 +168,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private boolean mHasInputFilter; + private final Set mTempComponentNameSet = new HashSet(); + + private final List mTempAccessibilityServiceInfoList = + new ArrayList(); + private final RemoteCallbackList mGlobalClients = new RemoteCallbackList(); @@ -177,9 +183,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private final SparseArray mUserStates = new SparseArray(); - private final TempUserStateChangeMemento mTempStateChangeForCurrentUserMemento = - new TempUserStateChangeMemento(); - private int mCurrentUserId = UserHandle.USER_OWNER; private UserState getCurrentUserStateLocked() { @@ -224,10 +227,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return; } // We will update when the automation service dies. - if (mUiAutomationService == null) { - UserState userState = getCurrentUserStateLocked(); - populateInstalledAccessibilityServiceLocked(userState); - manageServicesLocked(userState); + UserState userState = getCurrentUserStateLocked(); + if (userState.mUiAutomationService == null) { + if (readConfigurationForUserStateLocked(userState)) { + onUserStateChangedLocked(userState); + } } } } @@ -239,8 +243,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (userId != mCurrentUserId) { return; } - UserState state = getUserStateLocked(userId); - Iterator it = state.mEnabledServices.iterator(); + UserState userState = getUserStateLocked(userId); + Iterator it = userState.mEnabledServices.iterator(); while (it.hasNext()) { ComponentName comp = it.next(); String compPkg = comp.getPackageName(); @@ -249,13 +253,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // Update the enabled services setting. persistComponentNamesToSettingLocked( Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, - state.mEnabledServices, userId); + userState.mEnabledServices, userId); // Update the touch exploration granted services setting. - state.mTouchExplorationGrantedServices.remove(comp); + userState.mTouchExplorationGrantedServices.remove(comp); persistComponentNamesToSettingLocked( Settings.Secure. TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, - state.mEnabledServices, userId); + userState.mTouchExplorationGrantedServices, userId); + // We will update when the automation service dies. + if (userState.mUiAutomationService == null) { + onUserStateChangedLocked(userState); + } return; } } @@ -270,8 +278,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (userId != mCurrentUserId) { return false; } - UserState state = getUserStateLocked(userId); - Iterator it = state.mEnabledServices.iterator(); + UserState userState = getUserStateLocked(userId); + Iterator it = userState.mEnabledServices.iterator(); while (it.hasNext()) { ComponentName comp = it.next(); String compPkg = comp.getPackageName(); @@ -283,7 +291,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { it.remove(); persistComponentNamesToSettingLocked( Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, - state.mEnabledServices, userId); + userState.mEnabledServices, userId); + // We will update when the automation service dies. + if (userState.mUiAutomationService == null) { + onUserStateChangedLocked(userState); + } } } } @@ -310,7 +322,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } else if (Intent.ACTION_USER_REMOVED.equals(action)) { removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); } else if (Intent.ACTION_USER_PRESENT.equals(action)) { - restoreStateFromMementoIfNeeded(); + // We will update when the automation service dies. + UserState userState = getCurrentUserStateLocked(); + if (userState.mUiAutomationService == null) { + if (readConfigurationForUserStateLocked(userState)) { + onUserStateChangedLocked(userState); + } + } } } }, UserHandle.ALL, intentFilter, null, null); @@ -329,7 +347,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (DEBUG) { Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid()); } - return getClientState(userState); + return userState.getClientState(); } else { userState.mClients.register(client); // If this client is not for the current user we do not @@ -339,7 +357,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid() + " and userId:" + mCurrentUserId); } - return (resolvedUserId == mCurrentUserId) ? getClientState(userState) : 0; + return (resolvedUserId == mCurrentUserId) ? userState.getClientState() : 0; } } } @@ -385,7 +403,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { .resolveCallingUserIdEnforcingPermissionsLocked(userId); result = mEnabledServicesForFeedbackTempList; result.clear(); - List services = getUserStateLocked(resolvedUserId).mServices; + List services = getUserStateLocked(resolvedUserId).mBoundServices; while (feedbackType != 0) { final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType)); feedbackType &= ~feedbackTypeBit; @@ -410,7 +428,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (resolvedUserId != mCurrentUserId) { return; } - services = getUserStateLocked(resolvedUserId).mServices; + services = getUserStateLocked(resolvedUserId).mBoundServices; } for (int i = 0, count = services.size(); i < count; i++) { Service service = services.get(i); @@ -514,36 +532,48 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { AccessibilityServiceInfo accessibilityServiceInfo) { mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT, FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE); - ComponentName componentName = new ComponentName("foo.bar", - "AutomationAccessibilityService"); + + accessibilityServiceInfo.setComponentName(sFakeAccessibilityServiceComponentName); + synchronized (mLock) { - if (mUiAutomationService != null) { + UserState userState = getCurrentUserStateLocked(); + + if (userState.mUiAutomationService != null) { throw new IllegalStateException("UiAutomationService " + serviceClient + "already registered!"); } - // If an automation services is connected to the system all services are stopped - // so the automation one is the only one running. Settings are not changed so when - // the automation service goes away the state is restored from the settings. - UserState userState = getCurrentUserStateLocked(); - unbindAllServicesLocked(userState); - // If necessary enable accessibility and announce that. - if (!userState.mIsAccessibilityEnabled) { - userState.mIsAccessibilityEnabled = true; - } - // No touch exploration. + userState.mUiAutomationServiceClient = serviceClient; + + // Set the temporary state. + userState.mIsAccessibilityEnabled = true; userState.mIsTouchExplorationEnabled = false; - - // No touch enhanced web accessibility. userState.mIsEnhancedWebAccessibilityEnabled = false; + userState.mIsDisplayMagnificationEnabled = false; + userState.mInstalledServices.add(accessibilityServiceInfo); + userState.mEnabledServices.clear(); + userState.mEnabledServices.add(sFakeAccessibilityServiceComponentName); + userState.mTouchExplorationGrantedServices.add(sFakeAccessibilityServiceComponentName); - // Hook the automation service up. - mUiAutomationService = new Service(mCurrentUserId, componentName, - accessibilityServiceInfo, true); - mUiAutomationService.onServiceConnected(componentName, serviceClient.asBinder()); + // Use the new state instead of settings. + onUserStateChangedLocked(userState); + } + } - scheduleUpdateInputFilter(userState); - scheduleSendStateToClientsLocked(userState); + public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) { + synchronized (mLock) { + UserState userState = getCurrentUserStateLocked(); + // Automation service is not bound, so pretend it died to perform clean up. + if (userState.mUiAutomationService != null + && userState.mUiAutomationService.mServiceInterface != null + && serviceClient != null + && userState.mUiAutomationService.mServiceInterface.asBinder() + == serviceClient.asBinder()) { + userState.mUiAutomationService.binderDied(); + } else { + throw new IllegalStateException("UiAutomationService " + serviceClient + + " not registered!"); + } } } @@ -560,36 +590,26 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return; } synchronized (mLock) { - UserState userState = getCurrentUserStateLocked(); - // Stash the old state so we can restore it when the keyguard is gone. - mTempStateChangeForCurrentUserMemento.initialize(getCurrentUserStateLocked()); // Set the temporary state. + UserState userState = getCurrentUserStateLocked(); + + // This is a nop if UI automation is enabled. + if (userState.mUiAutomationService != null) { + return; + } + userState.mIsAccessibilityEnabled = true; userState.mIsTouchExplorationEnabled = touchExplorationEnabled; userState.mIsEnhancedWebAccessibilityEnabled = false; userState.mIsDisplayMagnificationEnabled = false; userState.mEnabledServices.clear(); userState.mEnabledServices.add(service); + userState.mBindingServices.clear(); userState.mTouchExplorationGrantedServices.clear(); userState.mTouchExplorationGrantedServices.add(service); - // Update the internal state. - performServiceManagementLocked(userState); - scheduleUpdateInputFilter(userState); - scheduleSendStateToClientsLocked(userState); - } - } - public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) { - synchronized (mLock) { - // Automation service is not bound, so pretend it died to perform clean up. - if (mUiAutomationService != null && mUiAutomationService.mServiceInterface != null - && serviceClient != null && mUiAutomationService.mServiceInterface - .asBinder() == serviceClient.asBinder()) { - mUiAutomationService.binderDied(); - } else { - throw new IllegalStateException("UiAutomationService " + serviceClient - + " not registered!"); - } + // User the current state instead settings. + onUserStateChangedLocked(userState); } } @@ -695,10 +715,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private void switchUser(int userId) { synchronized (mLock) { - // The user switched so we do not need to restore the current user - // state since we will fully rebuild it when he becomes current again. - mTempStateChangeForCurrentUserMemento.clear(); - // Disconnect from services for the old user. UserState oldUserState = getUserStateLocked(mCurrentUserId); unbindAllServicesLocked(oldUserState); @@ -716,9 +732,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // The user changed. mCurrentUserId = userId; - // Recreate the internal state for the new user. - mMainHandler.obtainMessage(MainHandler.MSG_SEND_RECREATE_INTERNAL_STATE, - mCurrentUserId, 0).sendToTarget(); + UserState userState = getCurrentUserStateLocked(); + if (userState.mUiAutomationService != null) { + // Switching users disables the UI automation service. + userState.mUiAutomationService.binderDied(); + } else if (readConfigurationForUserStateLocked(userState)) { + // Update the user state if needed. + onUserStateChangedLocked(userState); + } if (announceNewUser) { // Schedule announcement of the current user if needed. @@ -734,25 +755,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } - private void restoreStateFromMementoIfNeeded() { - synchronized (mLock) { - if (mTempStateChangeForCurrentUserMemento.mUserId != UserHandle.USER_NULL) { - UserState userState = getCurrentUserStateLocked(); - // Restore the state from the memento. - mTempStateChangeForCurrentUserMemento.applyTo(userState); - mTempStateChangeForCurrentUserMemento.clear(); - // Update the internal state. - performServiceManagementLocked(userState); - scheduleUpdateInputFilter(userState); - scheduleSendStateToClientsLocked(userState); - } - } - } - private Service getQueryBridge() { if (mQueryBridge == null) { AccessibilityServiceInfo info = new AccessibilityServiceInfo(); - mQueryBridge = new Service(UserHandle.USER_NULL, null, info, true); + mQueryBridge = new Service(UserHandle.USER_NULL, + sFakeAccessibilityServiceComponentName, info); } return mQueryBridge; } @@ -768,8 +775,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // behavior is observed from different combinations of // enabled accessibility services. UserState state = getCurrentUserStateLocked(); - for (int i = state.mServices.size() - 1; i >= 0; i--) { - Service service = state.mServices.get(i); + for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { + Service service = state.mBoundServices.get(i); if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) { service.notifyGesture(gestureId); return true; @@ -780,8 +787,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private void notifyClearAccessibilityNodeInfoCacheLocked() { UserState state = getCurrentUserStateLocked(); - for (int i = state.mServices.size() - 1; i >= 0; i--) { - Service service = state.mServices.get(i); + for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { + Service service = state.mBoundServices.get(i); service.notifyClearAccessibilityNodeInfoCache(); } } @@ -807,8 +814,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } - private void populateInstalledAccessibilityServiceLocked(UserState userState) { - userState.mInstalledServices.clear(); + private boolean readInstalledAccessibilityServiceLocked(UserState userState) { + mTempAccessibilityServiceInfoList.clear(); List installedServices = mPackageManager.queryIntentServicesAsUser( new Intent(AccessibilityService.SERVICE_INTERFACE), @@ -829,26 +836,53 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { AccessibilityServiceInfo accessibilityServiceInfo; try { accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext); - userState.mInstalledServices.add(accessibilityServiceInfo); + mTempAccessibilityServiceInfoList.add(accessibilityServiceInfo); } catch (XmlPullParserException xppe) { Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe); } catch (IOException ioe) { Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", ioe); } } + + if (!mTempAccessibilityServiceInfoList.equals(userState.mInstalledServices)) { + userState.mInstalledServices.clear(); + userState.mInstalledServices.addAll(mTempAccessibilityServiceInfoList); + mTempAccessibilityServiceInfoList.clear(); + return true; + } + + mTempAccessibilityServiceInfoList.clear(); + return false; } - private void populateEnabledAccessibilityServicesLocked(UserState userState) { - populateComponentNamesFromSettingLocked( - Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, - userState.mUserId, - userState.mEnabledServices); + private boolean readEnabledAccessibilityServicesLocked(UserState userState) { + mTempComponentNameSet.clear(); + readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + userState.mUserId, mTempComponentNameSet); + if (!mTempComponentNameSet.equals(userState.mEnabledServices)) { + userState.mEnabledServices.clear(); + userState.mEnabledServices.addAll(mTempComponentNameSet); + mTempComponentNameSet.clear(); + return true; + } + mTempComponentNameSet.clear(); + return false; } - private void populateTouchExplorationGrantedAccessibilityServicesLocked(UserState userState) { - populateComponentNamesFromSettingLocked( + private boolean readTouchExplorationGrantedAccessibilityServicesLocked( + UserState userState) { + mTempComponentNameSet.clear(); + readComponentNamesFromSettingLocked( Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, - userState.mUserId, userState.mTouchExplorationGrantedServices); + userState.mUserId, mTempComponentNameSet); + if (!mTempComponentNameSet.equals(userState.mTouchExplorationGrantedServices)) { + userState.mTouchExplorationGrantedServices.clear(); + userState.mTouchExplorationGrantedServices.addAll(mTempComponentNameSet); + mTempComponentNameSet.clear(); + return true; + } + mTempComponentNameSet.clear(); + return false; } /** @@ -862,8 +896,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { boolean isDefault) { try { UserState state = getCurrentUserStateLocked(); - for (int i = 0, count = state.mServices.size(); i < count; i++) { - Service service = state.mServices.get(i); + for (int i = 0, count = state.mBoundServices.size(); i < count; i++) { + Service service = state.mBoundServices.get(i); if (service.mIsDefault == isDefault) { if (canDispathEventLocked(service, event, state.mHandledFeedbackTypes)) { @@ -880,25 +914,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } - /** - * Adds a service for a user. - * - * @param service The service to add. - * @param userId The user id. - */ - private void tryAddServiceLocked(Service service, int userId) { + private void addServiceLocked(Service service, UserState userState) { try { - UserState userState = getUserStateLocked(userId); - if (userState.mServices.contains(service)) { - return; - } service.linkToOwnDeath(); - userState.mServices.add(service); + userState.mBoundServices.add(service); userState.mComponentNameToServiceMap.put(service.mComponentName, service); - scheduleUpdateInputFilter(userState); - tryEnableTouchExplorationLocked(service); - tryEnableEnhancedWebAccessibilityLocked(service); - } catch (RemoteException e) { + } catch (RemoteException re) { /* do nothing */ } } @@ -909,19 +930,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { * @param service The service. * @return True if the service was removed, false otherwise. */ - private boolean tryRemoveServiceLocked(Service service) { + private void removeServiceLocked(Service service) { UserState userState = getUserStateLocked(service.mUserId); - final boolean removed = userState.mServices.remove(service); - if (!removed) { - return false; - } + userState.mBoundServices.remove(service); userState.mComponentNameToServiceMap.remove(service.mComponentName); service.unlinkToOwnDeath(); service.dispose(); - scheduleUpdateInputFilter(userState); - tryDisableTouchExplorationLocked(service); - tryDisableEnhancedWebAccessibilityLocked(service); - return removed; } /** @@ -969,29 +983,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return false; } - /** - * Manages services by starting enabled ones and stopping disabled ones. - */ - private void manageServicesLocked(UserState userState) { - final int enabledInstalledServicesCount = updateServicesStateLocked(userState); - // No enabled installed services => disable accessibility to avoid - // sending accessibility events with no recipient across processes. - if (userState.mIsAccessibilityEnabled && enabledInstalledServicesCount == 0) { - Settings.Secure.putIntForUser(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId); - } - } - - /** - * Unbinds all bound services for a user. - * - * @param userState The user state. - */ private void unbindAllServicesLocked(UserState userState) { - List services = userState.mServices; + List services = userState.mBoundServices; for (int i = 0, count = services.size(); i < count; i++) { Service service = services.get(i); - if (service.unbind()) { + if (service.unbindLocked()) { i--; count--; } @@ -1006,7 +1002,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { * @param userId The user id. * @param outComponentNames The output component names. */ - private void populateComponentNamesFromSettingLocked(String settingName, int userId, + private void readComponentNamesFromSettingLocked(String settingName, int userId, Set outComponentNames) { String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), settingName, userId); @@ -1047,19 +1043,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { settingName, builder.toString(), userId); } - /** - * Updates the state of each service by starting (or keeping running) enabled ones and - * stopping the rest. - * - * @param userState The user state for which to do that. - * @return The number of enabled installed services. - */ - private int updateServicesStateLocked(UserState userState) { + private void manageServicesLocked(UserState userState) { Map componentNameToServiceMap = userState.mComponentNameToServiceMap; boolean isEnabled = userState.mIsAccessibilityEnabled; - int enabledInstalledServices = 0; for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) { AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i); ComponentName componentName = ComponentName.unflattenFromString( @@ -1067,32 +1055,46 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { Service service = componentNameToServiceMap.get(componentName); if (isEnabled) { + // Wait for the binding if it is in process. + if (userState.mBindingServices.contains(componentName)) { + continue; + } + // No enabled installed services => disable accessibility to avoid + // sending accessibility events with no recipient across processes. + if (userState.mEnabledServices.isEmpty()) { + userState.mIsAccessibilityEnabled = false; + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId); + return; + } if (userState.mEnabledServices.contains(componentName)) { if (service == null) { - service = new Service(userState.mUserId, componentName, - installedService, false); + service = new Service(userState.mUserId, componentName, installedService); + } else if (userState.mBoundServices.contains(service)) { + continue; } - service.bind(); - enabledInstalledServices++; + service.bindLocked(); } else { if (service != null) { - service.unbind(); + service.unbindLocked(); } } } else { if (service != null) { - service.unbind(); + service.unbindLocked(); + } else { + userState.mBindingServices.remove(componentName); } } } - - return enabledInstalledServices; } - private void scheduleSendStateToClientsLocked(UserState userState) { - if (mGlobalClients.getRegisteredCallbackCount() > 0 - || userState.mClients.getRegisteredCallbackCount() > 0) { - final int clientState = getClientState(userState); + private void scheduleUpdateClientsIfNeededLocked(UserState userState) { + final int clientState = userState.getClientState(); + if (userState.mLastSentClientState != clientState + && (mGlobalClients.getRegisteredCallbackCount() > 0 + || userState.mClients.getRegisteredCallbackCount() > 0)) { + userState.mLastSentClientState = clientState; mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS, clientState, userState.mUserId) .sendToTarget(); } @@ -1144,10 +1146,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } private void showEnableTouchExplorationDialog(final Service service) { - String label = service.mResolveInfo.loadLabel( - - mContext.getPackageManager()).toString(); synchronized (mLock) { + String label = service.mResolveInfo.loadLabel( + mContext.getPackageManager()).toString(); + final UserState state = getCurrentUserStateLocked(); if (state.mIsTouchExplorationEnabled) { return; @@ -1167,9 +1169,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, state.mTouchExplorationGrantedServices, state.mUserId); // Enable touch exploration. + UserState userState = getUserStateLocked(service.mUserId); + userState.mIsTouchExplorationEnabled = true; Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, service.mUserId); + onUserStateChangedLocked(userState); } }) .setNegativeButton(android.R.string.cancel, new OnClickListener() { @@ -1191,92 +1196,104 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } - private int getClientState(UserState userState) { - int clientState = 0; - if (userState.mIsAccessibilityEnabled) { - clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; - } - // Touch exploration relies on enabled accessibility. - if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) { - clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED; - } - return clientState; - } - - private void recreateInternalStateLocked(UserState userState) { - populateInstalledAccessibilityServiceLocked(userState); - populateEnabledAccessibilityServicesLocked(userState); - populateTouchExplorationGrantedAccessibilityServicesLocked(userState); - populatedEnhancedWebAccessibilityEnabledChangedLocked(userState); - - handleTouchExplorationEnabledSettingChangedLocked(userState); - handleDisplayMagnificationEnabledSettingChangedLocked(userState); - handleAccessibilityEnabledSettingChangedLocked(userState); - handleTouchExplorationGrantedAccessibilityServicesChangedLocked(userState); - - performServiceManagementLocked(userState); - + private void onUserStateChangedLocked(UserState userState) { + updateServicesLocked(userState); + updateTouchExplorationLocked(userState); + updateEnhancedWebAccessibilityLocked(userState); scheduleUpdateInputFilter(userState); - scheduleSendStateToClientsLocked(userState); + scheduleUpdateClientsIfNeededLocked(userState); } - private void handleAccessibilityEnabledSettingChangedLocked(UserState userState) { - userState.mIsAccessibilityEnabled = Settings.Secure.getIntForUser( - mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1; - } - - private void performServiceManagementLocked(UserState userState) { - if (userState.mIsAccessibilityEnabled ) { + private void updateServicesLocked(UserState userState) { + if (userState.mIsAccessibilityEnabled) { manageServicesLocked(userState); } else { unbindAllServicesLocked(userState); } } - private void handleTouchExplorationEnabledSettingChangedLocked(UserState userState) { - userState.mIsTouchExplorationEnabled = Settings.Secure.getIntForUser( - mContext.getContentResolver(), - Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1; + private boolean readConfigurationForUserStateLocked(UserState userState) { + boolean somthingChanged = false; + somthingChanged |= readAccessibilityEnabledSettingLocked(userState); + somthingChanged |= readInstalledAccessibilityServiceLocked(userState); + somthingChanged |= readEnabledAccessibilityServicesLocked(userState); + somthingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState); + somthingChanged |= readTouchExplorationEnabledSettingLocked(userState); + somthingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState); + somthingChanged |= readDisplayMagnificationEnabledSettingLocked(userState); + return somthingChanged; } - private void handleDisplayMagnificationEnabledSettingChangedLocked(UserState userState) { - userState.mIsDisplayMagnificationEnabled = Settings.Secure.getIntForUser( + private boolean readAccessibilityEnabledSettingLocked(UserState userState) { + final boolean accessibilityEnabled = Settings.Secure.getIntForUser( + mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1; + if (accessibilityEnabled != userState.mIsAccessibilityEnabled) { + userState.mIsAccessibilityEnabled = accessibilityEnabled; + return true; + } + return false; + } + + private boolean readTouchExplorationEnabledSettingLocked(UserState userState) { + final boolean touchExplorationEnabled = Settings.Secure.getIntForUser( + mContext.getContentResolver(), + Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1; + if (touchExplorationEnabled != userState.mIsTouchExplorationEnabled) { + userState.mIsTouchExplorationEnabled = touchExplorationEnabled; + return true; + } + return false; + } + + private boolean readDisplayMagnificationEnabledSettingLocked(UserState userState) { + final boolean displayMagnificationEnabled = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0, userState.mUserId) == 1; + if (displayMagnificationEnabled != userState.mIsDisplayMagnificationEnabled) { + userState.mIsDisplayMagnificationEnabled = displayMagnificationEnabled; + return true; + } + return false; } - private void handleTouchExplorationGrantedAccessibilityServicesChangedLocked( - UserState userState) { - Settings.Secure.putIntForUser(mContext.getContentResolver(), - Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId); - final int serviceCount = userState.mServices.size(); + private boolean readEnhancedWebAccessibilityEnabledChangedLocked(UserState userState) { + final boolean enhancedWeAccessibilityEnabled = Settings.Secure.getIntForUser( + mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, + 0, userState.mUserId) == 1; + if (enhancedWeAccessibilityEnabled != userState.mIsEnhancedWebAccessibilityEnabled) { + userState.mIsEnhancedWebAccessibilityEnabled = enhancedWeAccessibilityEnabled; + return true; + } + return false; + } + + private void updateTouchExplorationLocked(UserState userState) { + userState.mIsTouchExplorationEnabled = false; + final int serviceCount = userState.mBoundServices.size(); for (int i = 0; i < serviceCount; i++) { - Service service = userState.mServices.get(i); - tryEnableTouchExplorationLocked(service); + Service service = userState.mBoundServices.get(i); + if (tryEnableTouchExplorationLocked(service)) { + break; + } } } - private void populatedEnhancedWebAccessibilityEnabledChangedLocked(UserState userState) { - userState.mIsEnhancedWebAccessibilityEnabled = Settings.Secure.getIntForUser( - mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, - 0, userState.mUserId) == 1; - } - - private void tryEnableTouchExplorationLocked(Service service) { + private boolean tryEnableTouchExplorationLocked(Service service) { if (!service.canReceiveEventsLocked() || !service.mRequestTouchExplorationMode) { - return; + return false; } UserState userState = getUserStateLocked(service.mUserId); if (userState.mIsTouchExplorationEnabled) { - return; + return false; } // UI test automation service can always enable it. if (service.mIsAutomation) { + userState.mIsTouchExplorationEnabled = true; Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, service.mUserId); - return; + return true; } if (service.mResolveInfo.serviceInfo.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1) { @@ -1287,11 +1304,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (mEnableTouchExplorationDialog == null || (mEnableTouchExplorationDialog != null && !mEnableTouchExplorationDialog.isShowing())) { - showEnableTouchExplorationDialog(service); + mMainHandler.obtainMessage( + MainHandler.MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG, + service).sendToTarget(); } } else { + userState.mIsTouchExplorationEnabled = true; Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, service.mUserId); + return true; } } else { // Starting in JB-MR2 we request a permission to allow a service to enable @@ -1299,94 +1320,43 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (mContext.getPackageManager().checkPermission( android.Manifest.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE, service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED) { + userState.mIsTouchExplorationEnabled = true; Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, service.mUserId); + return true; } } + return false; } - private void tryDisableTouchExplorationLocked(Service service) { - if (!service.mRequestTouchExplorationMode) { - return; - } - UserState userState = getUserStateLocked(service.mUserId); - if (!userState.mIsTouchExplorationEnabled) { - return; - } - final int serviceCount = userState.mServices.size(); + private void updateEnhancedWebAccessibilityLocked(UserState userState) { + userState.mIsEnhancedWebAccessibilityEnabled = false; + final int serviceCount = userState.mBoundServices.size(); for (int i = 0; i < serviceCount; i++) { - Service other = userState.mServices.get(i); - if (other != service) { - if (service.mResolveInfo.serviceInfo.applicationInfo.targetSdkVersion - <= Build.VERSION_CODES.JELLY_BEAN_MR1) { - // Up to JB-MR1 we had a white list with services that can enable touch - // exploration. When a service is first started we show a dialog to the - // use to get a permission to white list the service. - if (other.mRequestTouchExplorationMode && - userState.mTouchExplorationGrantedServices.contains( - service.mComponentName)) { - // A white-listed service wants touch exploration, do not disable. - return; - } - } else { - // Starting in JB-MR2 we request a permission to allow a service to enable - // touch exploration and do not care if the service is in the white list. - if (other.mRequestTouchExplorationMode && (service.mIsAutomation - || mContext.getPackageManager().checkPermission( - android.Manifest.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE, - service.mComponentName.getPackageName()) - == PackageManager.PERMISSION_GRANTED)) { - // A service with permission wants touch exploration, do not disable. - return; - } - } - } - } - Settings.Secure.putIntForUser(mContext.getContentResolver(), - Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId); - } - - private void tryEnableEnhancedWebAccessibilityLocked(Service service) { - if (!service.canReceiveEventsLocked() || !service.mRequestEnhancedWebAccessibility ) { - return; - } - UserState userState = getUserStateLocked(service.mUserId); - if (userState.mIsEnhancedWebAccessibilityEnabled) { - return; - } - // Requested and can enabled, do it. - if (service.mRequestEnhancedWebAccessibility - && canEnabledEnhancedWebAccessibility(service)) { - Settings.Secure.putIntForUser(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 1, userState.mUserId); - } - } - - private void tryDisableEnhancedWebAccessibilityLocked(Service service) { - if (!service.mRequestEnhancedWebAccessibility) { - return; - } - UserState userState = getUserStateLocked(service.mUserId); - if (!userState.mIsEnhancedWebAccessibilityEnabled) { - return; - } - final int serviceCount = userState.mServices.size(); - for (int i = 0; i < serviceCount; i++) { - Service other = userState.mServices.get(i); - if (other != service && other.mRequestEnhancedWebAccessibility - && canEnabledEnhancedWebAccessibility(other)) { - // One service requests the feature, do not disable. + Service service = userState.mBoundServices.get(i); + if (tryEnableEnhancedWebAccessibilityLocked(service)) { return; } } - Settings.Secure.putIntForUser(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0, service.mUserId); } - private boolean canEnabledEnhancedWebAccessibility(Service service) { - return (service.mIsAutomation || mContext.getPackageManager().checkPermission( + private boolean tryEnableEnhancedWebAccessibilityLocked(Service service) { + if (!service.canReceiveEventsLocked() || !service.mRequestEnhancedWebAccessibility ) { + return false; + } + UserState userState = getUserStateLocked(service.mUserId); + if (userState.mIsEnhancedWebAccessibilityEnabled) { + return false; + } + if (service.mIsAutomation || mContext.getPackageManager().checkPermission( android.Manifest.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY, - service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED); + service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED) { + userState.mIsEnhancedWebAccessibilityEnabled = true; + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 1, userState.mUserId); + return true; + } + return false; } @Override @@ -1395,12 +1365,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { synchronized (mLock) { pw.println("ACCESSIBILITY MANAGER (dumpsys accessibility)"); pw.println(); - pw.println("Ui automation service: bound=" + (mUiAutomationService != null)); - pw.println(); - if (mUiAutomationService != null) { - mUiAutomationService.dump(fd, pw, args); - pw.println(); - } final int userCount = mUserStates.size(); for (int i = 0; i < userCount; i++) { UserState userState = mUserStates.valueAt(i); @@ -1410,17 +1374,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { pw.append(", touchExplorationEnabled=" + userState.mIsTouchExplorationEnabled); pw.append(", displayMagnificationEnabled=" + userState.mIsDisplayMagnificationEnabled); + if (userState.mUiAutomationService != null) { + pw.append(", "); + userState.mUiAutomationService.dump(fd, pw, args); + pw.println(); + } pw.append("}"); pw.println(); pw.append(" services:{"); - final int serviceCount = userState.mServices.size(); + final int serviceCount = userState.mBoundServices.size(); for (int j = 0; j < serviceCount; j++) { if (j > 0) { pw.append(", "); pw.println(); pw.append(" "); } - Service service = userState.mServices.get(j); + Service service = userState.mBoundServices.get(j); service.dump(fd, pw, args); } pw.println("}]"); @@ -1462,10 +1431,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 1; public static final int MSG_SEND_STATE_TO_CLIENTS = 2; public static final int MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER = 3; - public static final int MSG_SEND_RECREATE_INTERNAL_STATE = 4; - public static final int MSG_UPDATE_ACTIVE_WINDOW = 5; - public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 6; - public static final int MSG_UPDATE_INPUT_FILTER = 7; + public static final int MSG_UPDATE_ACTIVE_WINDOW = 4; + public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 5; + public static final int MSG_UPDATE_INPUT_FILTER = 6; + public static final int MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG = 7; public MainHandler(Looper looper) { super(looper); @@ -1494,13 +1463,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { final int userId = msg.arg1; sendStateToClientsForUser(0, userId); } break; - case MSG_SEND_RECREATE_INTERNAL_STATE: { - final int userId = msg.arg1; - synchronized (mLock) { - UserState userState = getUserStateLocked(userId); - recreateInternalStateLocked(userState); - } - } break; case MSG_UPDATE_ACTIVE_WINDOW: { final int windowId = msg.arg1; final int eventType = msg.arg2; @@ -1513,6 +1475,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { UserState userState = (UserState) msg.obj; updateInputFilter(userState); } break; + case MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG: { + Service service = (Service) msg.obj; + showEnableTouchExplorationDialog(service); + } break; } } @@ -1641,14 +1607,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { }; public Service(int userId, ComponentName componentName, - AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation) { + AccessibilityServiceInfo accessibilityServiceInfo) { mUserId = userId; mResolveInfo = accessibilityServiceInfo.getResolveInfo(); mId = sIdCounter++; mComponentName = componentName; mAccessibilityServiceInfo = accessibilityServiceInfo; - mIsAutomation = isAutomation; - if (!isAutomation) { + mIsAutomation = (sFakeAccessibilityServiceComponentName.equals(componentName)); + if (!mIsAutomation) { mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent(); mIntent = new Intent().setComponent(mComponentName); mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL, @@ -1688,24 +1654,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { mRequestEnhancedWebAccessibility = (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0; } - - // If this service is up and running we may have to enable touch - // exploration or enhanced web accessibility, otherwise this will - // happen when the service connects. - synchronized (mLock) { - if (canReceiveEventsLocked()) { - if (mRequestTouchExplorationMode) { - tryEnableTouchExplorationLocked(this); - } else { - tryDisableTouchExplorationLocked(this); - } - if (mRequestEnhancedWebAccessibility) { - tryEnableEnhancedWebAccessibilityLocked(this); - } else { - tryDisableEnhancedWebAccessibilityLocked(this); - } - } - } } /** @@ -1713,10 +1661,20 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { * * @return True if binding is successful. */ - public boolean bind() { - if (!mIsAutomation && mService == null) { - return mContext.bindServiceAsUser(mIntent, this, Context.BIND_AUTO_CREATE, - new UserHandle(mUserId)); + public boolean bindLocked() { + UserState userState = getUserStateLocked(mUserId); + if (!mIsAutomation) { + if (mService == null) { + if (mContext.bindServiceAsUser(mIntent, this, Context.BIND_AUTO_CREATE, + new UserHandle(mUserId))) { + userState.mBindingServices.add(mComponentName); + } + } + } else { + userState.mBindingServices.add(mComponentName); + mService = userState.mUiAutomationServiceClient.asBinder(); + onServiceConnected(mComponentName, mService); + userState.mUiAutomationService = this; } return false; } @@ -1727,17 +1685,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { * * @return True if unbinding is successful. */ - public boolean unbind() { - if (mService != null) { - synchronized (mLock) { - tryRemoveServiceLocked(this); - } - if (!mIsAutomation) { - mContext.unbindService(this); - } - return true; + public boolean unbindLocked() { + if (mService == null) { + return false; } - return false; + if (!mIsAutomation) { + mContext.unbindService(this); + } else { + UserState userState = getUserStateLocked(mUserId); + userState.mUiAutomationService = null; + userState.mUiAutomationServiceClient = null; + } + removeServiceLocked(this); + return true; } public boolean canReceiveEventsLocked() { @@ -1766,6 +1726,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } else { setDynamicallyConfigurableProperties(info); } + UserState userState = getUserStateLocked(mUserId); + onUserStateChangedLocked(userState); } } finally { Binder.restoreCallingIdentity(identity); @@ -1774,15 +1736,24 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { @Override public void onServiceConnected(ComponentName componentName, IBinder service) { - mService = service; - mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service); - try { - mServiceInterface.setConnection(this, mId); - synchronized (mLock) { - tryAddServiceLocked(this, mUserId); + final int connectionId; + synchronized (mLock) { + connectionId = mId; + mService = service; + mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service); + UserState userState = getUserStateLocked(mUserId); + if (!userState.mBindingServices.contains(mComponentName)) { + binderDied(); + } else { + userState.mBindingServices.remove(mComponentName); + addServiceLocked(this, userState); + onUserStateChangedLocked(userState); } + } + try { + mServiceInterface.setConnection(this, connectionId); } catch (RemoteException re) { - Slog.w(LOG_TAG, "Error while setting Controller for service: " + service, re); + Slog.w(LOG_TAG, "Error while setting connection for service: " + service, re); } } @@ -2128,13 +2099,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public void binderDied() { synchronized (mLock) { // The death recipient is unregistered in tryRemoveServiceLocked - tryRemoveServiceLocked(this); - // We no longer have an automation service, so restore - // the state based on values in the settings database. + removeServiceLocked(this); + UserState userState = getUserStateLocked(mUserId); if (mIsAutomation) { - mUiAutomationService = null; - recreateInternalStateLocked(getUserStateLocked(mUserId)); + // We no longer have an automation service, so restore + // the state based on values in the settings database. + userState.mUiAutomationService = null; + userState.mUiAutomationServiceClient = null; } + onUserStateChangedLocked(userState); } } @@ -2585,7 +2558,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private class UserState { public final int mUserId; - public final CopyOnWriteArrayList mServices = new CopyOnWriteArrayList(); + public final CopyOnWriteArrayList mBoundServices = new CopyOnWriteArrayList(); public final RemoteCallbackList mClients = new RemoteCallbackList(); @@ -2596,6 +2569,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public final List mInstalledServices = new ArrayList(); + public final Set mBindingServices = new HashSet(); + public final Set mEnabledServices = new HashSet(); public final Set mTouchExplorationGrantedServices = @@ -2609,57 +2584,30 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public int mHandledFeedbackTypes = 0; + public int mLastSentClientState; + public boolean mIsAccessibilityEnabled; public boolean mIsTouchExplorationEnabled; public boolean mIsEnhancedWebAccessibilityEnabled; public boolean mIsDisplayMagnificationEnabled; + private Service mUiAutomationService; + private IAccessibilityServiceClient mUiAutomationServiceClient; + public UserState(int userId) { mUserId = userId; } - } - private class TempUserStateChangeMemento { - public int mUserId = UserHandle.USER_NULL; - public boolean mIsAccessibilityEnabled; - public boolean mIsTouchExplorationEnabled; - public boolean mIsEnhancedWebAccessibilityEnabled; - public boolean mIsDisplayMagnificationEnabled; - public final Set mEnabledServices = new HashSet(); - public final Set mTouchExplorationGrantedServices = - new HashSet(); - - public void initialize(UserState userState) { - mUserId = userState.mUserId; - mIsAccessibilityEnabled = userState.mIsAccessibilityEnabled; - mIsTouchExplorationEnabled = userState.mIsTouchExplorationEnabled; - mIsEnhancedWebAccessibilityEnabled = userState.mIsEnhancedWebAccessibilityEnabled; - mIsDisplayMagnificationEnabled = userState.mIsDisplayMagnificationEnabled; - mEnabledServices.clear(); - mEnabledServices.addAll(userState.mEnabledServices); - mTouchExplorationGrantedServices.clear(); - mTouchExplorationGrantedServices.addAll(userState.mTouchExplorationGrantedServices); - } - - public void applyTo(UserState userState) { - userState.mIsAccessibilityEnabled = mIsAccessibilityEnabled; - userState.mIsTouchExplorationEnabled = mIsTouchExplorationEnabled; - userState.mIsEnhancedWebAccessibilityEnabled = mIsEnhancedWebAccessibilityEnabled; - userState.mIsDisplayMagnificationEnabled = mIsDisplayMagnificationEnabled; - userState.mEnabledServices.clear(); - userState.mEnabledServices.addAll(mEnabledServices); - userState.mTouchExplorationGrantedServices.clear(); - userState.mTouchExplorationGrantedServices.addAll(mTouchExplorationGrantedServices); - } - - public void clear() { - mUserId = UserHandle.USER_NULL; - mIsAccessibilityEnabled = false; - mIsTouchExplorationEnabled = false; - mIsEnhancedWebAccessibilityEnabled = false; - mIsDisplayMagnificationEnabled = false; - mEnabledServices.clear(); - mTouchExplorationGrantedServices.clear(); + public int getClientState() { + int clientState = 0; + if (mIsAccessibilityEnabled) { + clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; + } + // Touch exploration relies on enabled accessibility. + if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) { + clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED; + } + return clientState; } } @@ -2680,7 +2628,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES); - private final Uri mAccessibilityScriptInjectionUri = Settings.Secure + private final Uri mEnhancedWebAccessibilityUri = Settings.Secure .getUriFor(Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION); public AccessibilityContentObserver(Handler handler) { @@ -2699,7 +2647,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { contentResolver.registerContentObserver( mTouchExplorationGrantedAccessibilityServicesUri, false, this, UserHandle.USER_ALL); - contentResolver.registerContentObserver(mAccessibilityScriptInjectionUri, + contentResolver.registerContentObserver(mEnhancedWebAccessibilityUri, false, this, UserHandle.USER_ALL); } @@ -2708,58 +2656,61 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (mAccessibilityEnabledUri.equals(uri)) { synchronized (mLock) { // We will update when the automation service dies. - if (mUiAutomationService == null) { - UserState userState = getCurrentUserStateLocked(); - handleAccessibilityEnabledSettingChangedLocked(userState); - performServiceManagementLocked(userState); - scheduleUpdateInputFilter(userState); - scheduleSendStateToClientsLocked(userState); + UserState userState = getCurrentUserStateLocked(); + if (userState.mUiAutomationService == null) { + if (readAccessibilityEnabledSettingLocked(userState)) { + onUserStateChangedLocked(userState); + } } } } else if (mTouchExplorationEnabledUri.equals(uri)) { synchronized (mLock) { // We will update when the automation service dies. - if (mUiAutomationService == null) { - UserState userState = getCurrentUserStateLocked(); - handleTouchExplorationEnabledSettingChangedLocked(userState); - scheduleUpdateInputFilter(userState); - scheduleSendStateToClientsLocked(userState); + UserState userState = getCurrentUserStateLocked(); + if (userState.mUiAutomationService == null) { + if (readTouchExplorationEnabledSettingLocked(userState)) { + onUserStateChangedLocked(userState); + } } } } else if (mDisplayMagnificationEnabledUri.equals(uri)) { synchronized (mLock) { // We will update when the automation service dies. - if (mUiAutomationService == null) { - UserState userState = getCurrentUserStateLocked(); - handleDisplayMagnificationEnabledSettingChangedLocked(userState); - scheduleUpdateInputFilter(userState); - scheduleSendStateToClientsLocked(userState); + UserState userState = getCurrentUserStateLocked(); + if (userState.mUiAutomationService == null) { + if (readDisplayMagnificationEnabledSettingLocked(userState)) { + onUserStateChangedLocked(userState); + } } } } else if (mEnabledAccessibilityServicesUri.equals(uri)) { synchronized (mLock) { // We will update when the automation service dies. - if (mUiAutomationService == null) { - UserState userState = getCurrentUserStateLocked(); - populateEnabledAccessibilityServicesLocked(userState); - manageServicesLocked(userState); + UserState userState = getCurrentUserStateLocked(); + if (userState.mUiAutomationService == null) { + if (readEnabledAccessibilityServicesLocked(userState)) { + onUserStateChangedLocked(userState); + } } } } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) { synchronized (mLock) { // We will update when the automation service dies. - if (mUiAutomationService == null) { - UserState userState = getCurrentUserStateLocked(); - populateTouchExplorationGrantedAccessibilityServicesLocked(userState); - handleTouchExplorationGrantedAccessibilityServicesChangedLocked(userState); + UserState userState = getCurrentUserStateLocked(); + if (userState.mUiAutomationService == null) { + if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) { + onUserStateChangedLocked(userState); + } } } - } else if (mAccessibilityScriptInjectionUri.equals(uri)) { + } else if (mEnhancedWebAccessibilityUri.equals(uri)) { synchronized (mLock) { // We will update when the automation service dies. - if (mUiAutomationService == null) { - UserState userState = getCurrentUserStateLocked(); - populatedEnhancedWebAccessibilityEnabledChangedLocked(userState); + UserState userState = getCurrentUserStateLocked(); + if (userState.mUiAutomationService == null) { + if (readEnhancedWebAccessibilityEnabledChangedLocked(userState)) { + onUserStateChangedLocked(userState); + } } } } diff --git a/services/java/com/android/server/wm/DisplayMagnifier.java b/services/java/com/android/server/wm/DisplayMagnifier.java index 6e876f6511fa3..61093ad1138e8 100644 --- a/services/java/com/android/server/wm/DisplayMagnifier.java +++ b/services/java/com/android/server/wm/DisplayMagnifier.java @@ -86,8 +86,8 @@ final class DisplayMagnifier { mContext = windowManagerService.mContext; mWindowManagerService = windowManagerService; mCallbacks = callbacks; - mMagnifedViewport = new MagnifiedViewport(); mHandler = new MyHandler(mWindowManagerService.mH.getLooper()); + mMagnifedViewport = new MagnifiedViewport(); mLongAnimationDuration = mContext.getResources().getInteger( com.android.internal.R.integer.config_longAnimTime); } @@ -273,6 +273,7 @@ final class DisplayMagnifier { mContext.getResources().getDisplayMetrics()); mHalfBorderWidth = (int) (mBorderWidth + 0.5) / 2; mWindow = new ViewportWindow(mContext); + recomputeBoundsLocked(); } public void updateMagnificationSpecLocked(MagnificationSpec spec) {