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
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();
+                }
             }
         }