Merge "Accessibility test automation API not working."
diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
index cd8dcb9..3521296 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_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.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 @@
 
     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 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 @@
             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 @@
 
     @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<AccessibilityNodeInfo> 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 @@
 
     @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<AccessibilityNodeInfo> 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 @@
 
     @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 @@
             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<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
@@ -221,7 +216,6 @@
                 }
             }
         } finally {
-            afterClassIfNeeded();
             if (DEBUG) {
                 final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
                 Log.i(LOG_TAG, "testTraverseAllViews: " + elapsedTimeMillis + "ms");
@@ -231,15 +225,17 @@
 
     @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 @@
 
             // 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 @@
 
     @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 @@
 
             // 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 @@
 
             // 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 @@
 
     @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 @@
 
             // 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 @@
 
     @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 @@
 
             // 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 @@
 
             // 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 @@
 
     @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 @@
             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 @@
 
     @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 @@
             }
             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 @@
         /* 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 @@
                     }
                 }
             };
-            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++;
+            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 testMethodCount;
+        return sConnection;
     }
 }
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index ed8fa40..fd528cc 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -298,16 +298,7 @@
                     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 @@
             client.asBinder().linkToDeath(new DeathRecipient() {
                 public void binderDied() {
                     synchronized (mLock) {
+                        addedClient.asBinder().unlinkToDeath(this, 0);
                         mClients.remove(addedClient);
                     }
                 }
@@ -445,10 +437,12 @@
             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 @@
         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();
             }
-            // 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);
+            // If necessary enable accessibility and announce that.
+            if (!mIsAccessibilityEnabled) {
+                mIsAccessibilityEnabled = true;
+                sendStateToClientsLocked();
+            }
         }
+        // Hook the automation service up.
         AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo();
         accessibilityServiceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
         accessibilityServiceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
@@ -717,11 +713,12 @@
      * 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);
@@ -744,6 +741,21 @@
     }
 
     /**
+     * Unbinds the automation service if such is running.
+     */
+    private void unbindAutomationService() {
+        List<Service> 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.
      *
@@ -868,6 +880,22 @@
     }
 
     /**
+     * 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
      * service and is responsible for adding/removing the service in the data structures
@@ -1171,7 +1199,13 @@
 
         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();
+                }
             }
         }