From b6eca6e6691d4563d8395b3c3843d9932a2a6560 Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Tue, 27 Sep 2011 10:47:58 -0700 Subject: [PATCH] Accessibility test automation API not working. 1. Due to a previous change that disabled accessibility if not enabled and installed serivces are present the automation APIs stopped working since they use fake automation service that is not installed. 2. Added clean up of death recipients when binders die. bug:5374662 bug:5239044 Change-Id: I1f3c8cd1d1c79753a4a64e2b8b2963025abb2939 --- .../InterrogationActivityTest.java | 229 ++++++------------ .../AccessibilityManagerService.java | 84 +++++-- 2 files changed, 137 insertions(+), 176 deletions(-) diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java index cd8dcb9732299..3521296713e13 100644 --- a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java +++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java @@ -19,14 +19,10 @@ import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_SELE import static android.view.accessibility.AccessibilityNodeInfo.ACTION_FOCUS; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SELECT; -import com.android.frameworks.coretests.R; - import android.content.Context; import android.graphics.Rect; -import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; -import android.provider.Settings; import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; @@ -36,8 +32,8 @@ import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityManager; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; +import com.android.frameworks.coretests.R; + import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -55,14 +51,9 @@ public class InterrogationActivityTest private static String LOG_TAG = "InterrogationActivityTest"; - // Timeout before give up wait for the system to process an accessibility setting change. + // Timeout before give up wait for the system to process an accessibility setting change. private static final int TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING = 2000; - // Helpers to figure out the first and last test methods - // This is a workaround for the lack of such support in JUnit3 - private static int sTestMethodCount; - private static int sExecutedTestMethodCount; - // Handle to a connection to the AccessibilityManagerService private static IAccessibilityServiceConnection sConnection; @@ -71,19 +62,20 @@ public class InterrogationActivityTest public InterrogationActivityTest() { super(InterrogationActivity.class); - sTestMethodCount = getTestMethodCount(); } @LargeTest public void testFindAccessibilityNodeInfoByViewId() throws Exception { - beforeClassIfNeeded(); final long startTimeMillis = SystemClock.uptimeMillis(); try { + // hook into the system first + IAccessibilityServiceConnection connection = getConnection(); + // bring up the activity getActivity(); AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(getConnection(), R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); assertNotNull(button); assertEquals(0, button.getChildCount()); @@ -116,7 +108,6 @@ public class InterrogationActivityTest assertEquals(ACTION_FOCUS | ACTION_SELECT | ACTION_CLEAR_SELECTION, button.getActions()); } finally { - afterClassIfNeeded(); if (DEBUG) { final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; Log.i(LOG_TAG, "testFindAccessibilityNodeInfoByViewId: " @@ -127,18 +118,19 @@ public class InterrogationActivityTest @LargeTest public void testFindAccessibilityNodeInfoByViewText() throws Exception { - beforeClassIfNeeded(); final long startTimeMillis = SystemClock.uptimeMillis(); try { + // hook into the system first + IAccessibilityServiceConnection connection = getConnection(); + // bring up the activity getActivity(); // find a view by text List buttons = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfosByViewTextInActiveWindow(getConnection(), "butto"); + .findAccessibilityNodeInfosByViewTextInActiveWindow(connection, "butto"); assertEquals(9, buttons.size()); } finally { - afterClassIfNeeded(); if (DEBUG) { final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; Log.i(LOG_TAG, "testFindAccessibilityNodeInfoByViewText: " @@ -149,19 +141,20 @@ public class InterrogationActivityTest @LargeTest public void testFindAccessibilityNodeInfoByViewTextContentDescription() throws Exception { - beforeClassIfNeeded(); final long startTimeMillis = SystemClock.uptimeMillis(); try { + // hook into the system first + IAccessibilityServiceConnection connection = getConnection(); + // bring up the activity getActivity(); // find a view by text List buttons = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfosByViewTextInActiveWindow(getConnection(), + .findAccessibilityNodeInfosByViewTextInActiveWindow(connection, "contentDescription"); assertEquals(1, buttons.size()); } finally { - afterClassIfNeeded(); if (DEBUG) { final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; Log.i(LOG_TAG, "testFindAccessibilityNodeInfoByViewTextContentDescription: " @@ -172,9 +165,11 @@ public class InterrogationActivityTest @LargeTest public void testTraverseAllViews() throws Exception { - beforeClassIfNeeded(); final long startTimeMillis = SystemClock.uptimeMillis(); try { + // hook into the system first + IAccessibilityServiceConnection connection = getConnection(); + // bring up the activity getActivity(); @@ -195,7 +190,7 @@ public class InterrogationActivityTest classNameAndTextList.add("android.widget.ButtonButton9"); AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(getConnection(), R.id.root); + .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.root); assertNotNull("We must find the existing root.", root); Queue fringe = new LinkedList(); @@ -221,7 +216,6 @@ public class InterrogationActivityTest } } } finally { - afterClassIfNeeded(); if (DEBUG) { final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; Log.i(LOG_TAG, "testTraverseAllViews: " + elapsedTimeMillis + "ms"); @@ -231,15 +225,17 @@ public class InterrogationActivityTest @LargeTest public void testPerformAccessibilityActionFocus() throws Exception { - beforeClassIfNeeded(); final long startTimeMillis = SystemClock.uptimeMillis(); try { + // hook into the system first + IAccessibilityServiceConnection connection = getConnection(); + // bring up the activity getActivity(); // find a view and make sure it is not focused AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(getConnection(), R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); assertFalse(button.isFocused()); // focus the view @@ -247,10 +243,9 @@ public class InterrogationActivityTest // find the view again and make sure it is focused button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(getConnection(), R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); assertTrue(button.isFocused()); } finally { - afterClassIfNeeded(); if (DEBUG) { final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; Log.i(LOG_TAG, "testPerformAccessibilityActionFocus: " + elapsedTimeMillis + "ms"); @@ -260,15 +255,17 @@ public class InterrogationActivityTest @LargeTest public void testPerformAccessibilityActionClearFocus() throws Exception { - beforeClassIfNeeded(); final long startTimeMillis = SystemClock.uptimeMillis(); try { + // hook into the system first + IAccessibilityServiceConnection connection = getConnection(); + // bring up the activity getActivity(); // find a view and make sure it is not focused AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(getConnection(), R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); assertFalse(button.isFocused()); // focus the view @@ -276,7 +273,7 @@ public class InterrogationActivityTest // find the view again and make sure it is focused button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(getConnection(), R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); assertTrue(button.isFocused()); // unfocus the view @@ -284,10 +281,9 @@ public class InterrogationActivityTest // find the view again and make sure it is not focused button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(getConnection(), R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); assertFalse(button.isFocused()); } finally { - afterClassIfNeeded(); if (DEBUG) { final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; Log.i(LOG_TAG, "testPerformAccessibilityActionClearFocus: " @@ -298,15 +294,17 @@ public class InterrogationActivityTest @LargeTest public void testPerformAccessibilityActionSelect() throws Exception { - beforeClassIfNeeded(); final long startTimeMillis = SystemClock.uptimeMillis(); try { + // hook into the system first + IAccessibilityServiceConnection connection = getConnection(); + // bring up the activity getActivity(); // find a view and make sure it is not selected AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(getConnection(), R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); assertFalse(button.isSelected()); // select the view @@ -314,10 +312,9 @@ public class InterrogationActivityTest // find the view again and make sure it is selected button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(getConnection(), R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); assertTrue(button.isSelected()); } finally { - afterClassIfNeeded(); if (DEBUG) { final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; Log.i(LOG_TAG, "testPerformAccessibilityActionSelect: " + elapsedTimeMillis + "ms"); @@ -327,15 +324,17 @@ public class InterrogationActivityTest @LargeTest public void testPerformAccessibilityActionClearSelection() throws Exception { - beforeClassIfNeeded(); final long startTimeMillis = SystemClock.uptimeMillis(); try { + // hook into the system first + IAccessibilityServiceConnection connection = getConnection(); + // bring up the activity getActivity(); // find a view and make sure it is not selected AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(getConnection(), R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); assertFalse(button.isSelected()); // select the view @@ -343,7 +342,7 @@ public class InterrogationActivityTest // find the view again and make sure it is selected button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(getConnection(), R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); assertTrue(button.isSelected()); // unselect the view @@ -351,10 +350,9 @@ public class InterrogationActivityTest // find the view again and make sure it is not selected button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(getConnection(), R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); assertFalse(button.isSelected()); } finally { - afterClassIfNeeded(); if (DEBUG) { final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; Log.i(LOG_TAG, "testPerformAccessibilityActionClearSelection: " @@ -365,15 +363,17 @@ public class InterrogationActivityTest @LargeTest public void testAccessibilityEventGetSource() throws Exception { - beforeClassIfNeeded(); final long startTimeMillis = SystemClock.uptimeMillis(); try { + // hook into the system first + IAccessibilityServiceConnection connection = getConnection(); + // bring up the activity - getActivity(); + getActivity(); // find a view and make sure it is not focused AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(getConnection(), R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); assertFalse(button.isSelected()); // focus the view @@ -419,7 +419,6 @@ public class InterrogationActivityTest assertSame(button.isCheckable(), source.isCheckable()); assertSame(button.isChecked(), source.isChecked()); } finally { - afterClassIfNeeded(); if (DEBUG) { final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; Log.i(LOG_TAG, "testAccessibilityEventGetSource: " + elapsedTimeMillis + "ms"); @@ -429,15 +428,17 @@ public class InterrogationActivityTest @LargeTest public void testObjectContract() throws Exception { - beforeClassIfNeeded(); final long startTimeMillis = SystemClock.uptimeMillis(); try { + // hook into the system first + IAccessibilityServiceConnection connection = getConnection(); + // bring up the activity getActivity(); // find a view and make sure it is not focused AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(getConnection(), R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); AccessibilityNodeInfo parent = button.getParent(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { @@ -451,7 +452,6 @@ public class InterrogationActivityTest } fail("Parent's children do not have the info whose parent is the parent."); } finally { - afterClassIfNeeded(); if (DEBUG) { final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; Log.i(LOG_TAG, "testObjectContract: " + elapsedTimeMillis + "ms"); @@ -464,90 +464,10 @@ public class InterrogationActivityTest /* intentionally do not scrub */ } - /** - * Sets accessibility in a given state by writing the state to the - * settings and waiting until the accessibility manager service picks - * it up for max {@link #TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING}. - * - * @param state The accessibility state. - * @throws Exception If any error occurs. - */ - private void ensureAccessibilityState(boolean state) throws Exception { - Context context = getInstrumentation().getContext(); - // If the local manager ready => nothing to do. - AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(context); - if (accessibilityManager.isEnabled() == state) { - return; - } - synchronized (this) { - // Check if the system already knows about the desired state. - final boolean currentState = Settings.Secure.getInt(context.getContentResolver(), - Settings.Secure.ACCESSIBILITY_ENABLED) == 1; - if (currentState != state) { - // Make sure we wake ourselves as the desired state is propagated. - accessibilityManager.addAccessibilityStateChangeListener( - new AccessibilityManager.AccessibilityStateChangeListener() { - public void onAccessibilityStateChanged(boolean enabled) { - synchronized (this) { - notifyAll(); - } - } - }); - Settings.Secure.putInt(context.getContentResolver(), - Settings.Secure.ACCESSIBILITY_ENABLED, state ? 1 : 0); - } - // No while one attempt and that is it. - try { - wait(TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING); - } catch (InterruptedException ie) { - /* ignore */ - } - } - if (accessibilityManager.isEnabled() != state) { - throw new IllegalStateException("Could not set accessibility state to: " + state); - } - } - - /** - * Execute some set up code before any test method. - * - * NOTE: I miss Junit4's @BeforeClass - * - * @throws Exception If an error occurs. - */ - private void beforeClassIfNeeded() throws Exception { - sExecutedTestMethodCount++; - if (sExecutedTestMethodCount == 1) { - ensureAccessibilityState(true); - } - } - - /** - * Execute some clean up code after all test methods. - * - * NOTE: I miss Junit4's @AfterClass - * - * @throws Exception If an error occurs. - */ - public void afterClassIfNeeded() throws Exception { - if (sExecutedTestMethodCount == sTestMethodCount) { - sExecutedTestMethodCount = 0; - ensureAccessibilityState(false); - } - } - - private static IAccessibilityServiceConnection getConnection() throws Exception { + private IAccessibilityServiceConnection getConnection() throws Exception { if (sConnection == null) { IEventListener listener = new IEventListener.Stub() { - public void setConnection(IAccessibilityServiceConnection connection) - throws RemoteException { - AccessibilityServiceInfo info = new AccessibilityServiceInfo(); - info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK; - info.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN; - info.notificationTimeout = 0; - info.flags = AccessibilityServiceInfo.DEFAULT; - connection.setServiceInfo(info); - } + public void setConnection(IAccessibilityServiceConnection connection) {} public void onInterrupt() {} @@ -560,26 +480,33 @@ public class InterrogationActivityTest } } }; - IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface( - ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)); - sConnection = manager.registerEventListener(listener); + + AccessibilityManager accessibilityManager = + AccessibilityManager.getInstance(getInstrumentation().getContext()); + + synchronized (this) { + if (!accessibilityManager.isEnabled()) { + // Make sure we wake ourselves as the desired state is propagated. + accessibilityManager.addAccessibilityStateChangeListener( + new AccessibilityManager.AccessibilityStateChangeListener() { + public void onAccessibilityStateChanged(boolean enabled) { + synchronized (this) { + notifyAll(); + } + } + }); + IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface( + ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)); + sConnection = manager.registerEventListener(listener); + + wait(TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING); + } else { + IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface( + ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)); + sConnection = manager.registerEventListener(listener); + } + } } return sConnection; } - - /** - * @return The number of test methods. - */ - private int getTestMethodCount() { - int testMethodCount = 0; - for (Method method : getClass().getMethods()) { - final int modifiers = method.getModifiers(); - if (method.getName().startsWith("test") - && (modifiers & Modifier.PUBLIC) != 0 - && (modifiers & Modifier.STATIC) == 0) { - testMethodCount++; - } - } - return testMethodCount; - } } diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index ed8fa40f9dc3d..fd528cce8490a 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -298,16 +298,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub super.onChange(selfChange); synchronized (mLock) { - mIsAccessibilityEnabled = Settings.Secure.getInt( - mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1; - if (mIsAccessibilityEnabled) { - manageServicesLocked(); - } else { - unbindAllServicesLocked(); - } - updateInputFilterLocked(); - sendStateToClientsLocked(); + handleAccessibilityEnabledSettingChangedLocked(); } } }); @@ -354,6 +345,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub client.asBinder().linkToDeath(new DeathRecipient() { public void binderDied() { synchronized (mLock) { + addedClient.asBinder().unlinkToDeath(this, 0); mClients.remove(addedClient); } } @@ -445,10 +437,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub IAccessibilityInteractionConnection connection) throws RemoteException { synchronized (mLock) { final IWindow addedWindowToken = windowToken; + final IAccessibilityInteractionConnection addedConnection = connection; final int windowId = sNextWindowId++; - connection.asBinder().linkToDeath(new DeathRecipient() { + addedConnection.asBinder().linkToDeath(new DeathRecipient() { public void binderDied() { synchronized (mLock) { + addedConnection.asBinder().unlinkToDeath(this, 0); removeAccessibilityInteractionConnection(addedWindowToken); } } @@ -485,21 +479,23 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub ComponentName componentName = new ComponentName("foo.bar", "AutomationAccessibilityService"); synchronized (mLock) { - Service oldService = mComponentNameToServiceMap.get(componentName); - if (oldService != null) { - tryRemoveServiceLocked(oldService); + // 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. + + // Disable all services. + final int runningServiceCount = mServices.size(); + for (int i = 0; i < runningServiceCount; i++) { + Service runningService = mServices.get(i); + runningService.unbind(); + } + // If necessary enable accessibility and announce that. + if (!mIsAccessibilityEnabled) { + mIsAccessibilityEnabled = true; + sendStateToClientsLocked(); } - // Now this service is enabled. - mEnabledServices.add(componentName); - // Also make sure this service is the only one. - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, - componentName.flattenToString()); - // This API is intended for testing so enable accessibility to make - // sure clients can start poking with the window content. - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_ENABLED, 1); } + // Hook the automation service up. AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo(); accessibilityServiceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK; accessibilityServiceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC; @@ -717,11 +713,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub * Manages services by starting enabled ones and stopping disabled ones. */ private void manageServicesLocked() { + unbindAutomationService(); populateEnabledServicesLocked(mEnabledServices); final int enabledInstalledServicesCount = updateServicesStateLocked(mInstalledServices, mEnabledServices); // No enabled installed services => disable accessibility to avoid - // sending accessibility events with no recipient across processes. + // sending accessibility events with no recipient across processes. if (mIsAccessibilityEnabled && enabledInstalledServicesCount == 0) { Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED, 0); @@ -743,6 +740,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } + /** + * Unbinds the automation service if such is running. + */ + private void unbindAutomationService() { + List runningServices = mServices; + int runningServiceCount = mServices.size(); + for (int i = 0; i < runningServiceCount; i++) { + Service service = runningServices.get(i); + if (service.mIsAutomation) { + service.unbind(); + return; + } + } + } + /** * Populates a list with the {@link ComponentName}s of all enabled * {@link AccessibilityService}s. @@ -867,6 +879,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } + /** + * Updated the state based on the accessibility enabled setting. + */ + private void handleAccessibilityEnabledSettingChangedLocked() { + mIsAccessibilityEnabled = Settings.Secure.getInt( + mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1; + if (mIsAccessibilityEnabled) { + manageServicesLocked(); + } else { + unbindAllServicesLocked(); + } + updateInputFilterLocked(); + sendStateToClientsLocked(); + } + /** * This class represents an accessibility service. It stores all per service * data required for the service management, provides API for starting/stopping the @@ -1171,7 +1199,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public void binderDied() { synchronized (mLock) { + mService.unlinkToDeath(this, 0); tryRemoveServiceLocked(this); + // We no longer have an automation service, so restore + // the state based on values in the settings database. + if (mIsAutomation) { + handleAccessibilityEnabledSettingChangedLocked(); + } } }