Merge "Accessibility test automation API not working."

This commit is contained in:
Svetoslav Ganov
2011-10-06 17:28:51 -07:00
committed by Android (Google) Code Review
2 changed files with 137 additions and 176 deletions

View File

@@ -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<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 @@ 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<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 @@ 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<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
@@ -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;
}
}

View File

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