2604226  Add test cases for the internal accessibility infrastructure.

Change-Id: Iaeb2c11b6c2167632086b50d9c79e6459cc072b8
diff --git a/core/tests/coretests/src/android/accessibilityservice/AccessibilityTestService.java b/core/tests/coretests/src/android/accessibilityservice/AccessibilityTestService.java
deleted file mode 100644
index 2a51eea..0000000
--- a/core/tests/coretests/src/android/accessibilityservice/AccessibilityTestService.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.accessibilityservice;
-
-import android.accessibilityservice.AccessibilityService;
-import android.accessibilityservice.AccessibilityServiceInfo;
-import android.app.Notification;
-import android.util.Log;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-
-import java.util.Timer;
-import java.util.TimerTask;
-
-/**
- * This class text the accessibility framework end to end.
- * <p>
- * Note: Since accessibility is provided by {@link AccessibilityService}s we create one,
- * and it generates an event and an interruption dispatching them through the
- * {@link AccessibilityManager}. We verify the received result. To trigger the test
- * go to Settings->Accessibility and select the enable accessibility check and then
- * select the check for this service (same name as the class).
- */
-public class AccessibilityTestService extends AccessibilityService {
-
-    private static final String LOG_TAG = "AccessibilityTestService";
-
-    private static final String CLASS_NAME = "foo.bar.baz.Test";
-    private static final String PACKAGE_NAME = "foo.bar.baz";
-    private static final String TEXT = "Some stuff";
-    private static final String BEFORE_TEXT = "Some other stuff";
-
-    private static final String CONTENT_DESCRIPTION = "Content description";
-
-    private static final int ITEM_COUNT = 10;
-    private static final int CURRENT_ITEM_INDEX = 1;
-    private static final int INTERRUPT_INVOCATION_TYPE = 0x00000200;
-
-    private static final int FROM_INDEX = 1;
-    private static final int ADDED_COUNT = 2;
-    private static final int REMOVED_COUNT = 1;
-
-    private static final int NOTIFICATION_TIMEOUT_MILLIS = 80;
-
-    private int mReceivedResult;
-
-    private Timer mTimer = new Timer();
-
-    @Override
-    public void onServiceConnected() {
-        AccessibilityServiceInfo info = new AccessibilityServiceInfo();
-        info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
-        info.feedbackType = AccessibilityServiceInfo.FEEDBACK_AUDIBLE;
-        info.notificationTimeout = NOTIFICATION_TIMEOUT_MILLIS;
-        info.flags &= AccessibilityServiceInfo.DEFAULT;
-        setServiceInfo(info);
-
-        // we need to wait until the system picks our configuration
-        // otherwise it will not notify us
-        mTimer.schedule(new TimerTask() {
-            @Override
-            public void run() {
-                try {
-                    testAccessibilityEventDispatching();
-                    testInterrupt();
-                } catch (Exception e) {
-                    Log.e(LOG_TAG, "Error in testing Accessibility feature", e);
-                }
-            }
-        }, 1000);
-    }
-
-    /**
-     * Check here if the event we received is actually the one we sent.
-     */
-    @Override
-    public void onAccessibilityEvent(AccessibilityEvent event) {
-        assert(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED == event.getEventType());
-        assert(event != null);
-        assert(event.getEventTime() > 0);
-        assert(CLASS_NAME.equals(event.getClassName()));
-        assert(PACKAGE_NAME.equals(event.getPackageName()));
-        assert(1 == event.getText().size());
-        assert(TEXT.equals(event.getText().get(0)));
-        assert(BEFORE_TEXT.equals(event.getBeforeText()));
-        assert(event.isChecked());
-        assert(CONTENT_DESCRIPTION.equals(event.getContentDescription()));
-        assert(ITEM_COUNT == event.getItemCount());
-        assert(CURRENT_ITEM_INDEX == event.getCurrentItemIndex());
-        assert(event.isEnabled());
-        assert(event.isPassword());
-        assert(FROM_INDEX == event.getFromIndex());
-        assert(ADDED_COUNT == event.getAddedCount());
-        assert(REMOVED_COUNT == event.getRemovedCount());
-        assert(event.getParcelableData() != null);
-        assert(1 == ((Notification) event.getParcelableData()).icon);
-
-        // set the type of the receved request
-        mReceivedResult = AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED;
-    }
-
-    /**
-     * Set a flag that we received the interrupt request.
-     */
-    @Override
-    public void onInterrupt() {
-
-        // set the type of the receved request
-        mReceivedResult = INTERRUPT_INVOCATION_TYPE;
-    }
-
-    /**
-     * If an {@link AccessibilityEvent} is sent and received correctly.
-     */
-   public void testAccessibilityEventDispatching() throws Exception {
-       AccessibilityEvent event =
-           AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
-
-       assert(event != null);
-       event.setClassName(CLASS_NAME);
-       event.setPackageName(PACKAGE_NAME);
-       event.getText().add(TEXT);
-       event.setBeforeText(BEFORE_TEXT);
-       event.setChecked(true);
-       event.setContentDescription(CONTENT_DESCRIPTION);
-       event.setItemCount(ITEM_COUNT);
-       event.setCurrentItemIndex(CURRENT_ITEM_INDEX);
-       event.setEnabled(true);
-       event.setPassword(true);
-       event.setFromIndex(FROM_INDEX);
-       event.setAddedCount(ADDED_COUNT);
-       event.setRemovedCount(REMOVED_COUNT);
-       event.setParcelableData(new Notification(1, "Foo", 1234));
-
-       AccessibilityManager.getInstance(this).sendAccessibilityEvent(event);
-
-       assert(mReceivedResult == event.getEventType());
-
-       Log.i(LOG_TAG, "AccessibilityTestService#testAccessibilityEventDispatching: Success");
-   }
-
-   /**
-    * If accessibility feedback interruption is triggered and received correctly.
-    */
-   public void testInterrupt() throws Exception {
-       AccessibilityManager.getInstance(this).interrupt();
-
-       assert(INTERRUPT_INVOCATION_TYPE == mReceivedResult);
-
-       Log.i(LOG_TAG, "AccessibilityTestService#testInterrupt: Success");
-   }
-}
-
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index b07a10b..186b349 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -7,8 +7,10 @@
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_STATIC_JAVA_LIBRARIES := easymocklib
 
 LOCAL_JAVA_LIBRARIES := android.test.runner services
+
 LOCAL_PACKAGE_NAME := FrameworksServicesTests
 
 LOCAL_CERTIFICATE := platform
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 5ce109f..f115f42 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -23,6 +23,19 @@
     
     <application>
         <uses-library android:name="android.test.runner" />
+
+        <service android:name="com.android.server.AccessibilityManagerServiceTest$MyFirstMockAccessibilityService">
+          <intent-filter>
+            <action android:name="android.accessibilityservice.AccessibilityService"/>
+          </intent-filter>
+        </service>
+
+        <service android:name="com.android.server.AccessibilityManagerServiceTest$MySecondMockAccessibilityService">
+          <intent-filter>
+            <action android:name="android.accessibilityservice.AccessibilityService"/>
+          </intent-filter>
+        </service>
+
     </application>
 
     <instrumentation
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
new file mode 100644
index 0000000..0410635
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ServiceInfo;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.IAccessibilityManager;
+import android.view.accessibility.IAccessibilityManagerClient;
+
+/**
+ * This test exercises the
+ * {@link com.android.server.AccessibilityManagerService} by mocking the
+ * {@link android.view.accessibility.AccessibilityManager} which talks to to the
+ * service. The service itself is interacting with the platform. Note: Testing
+ * the service in full isolation would require significant amount of work for
+ * mocking all system interactions. It would also require a lot of mocking code.
+ */
+public class AccessibilityManagerServiceTest extends AndroidTestCase {
+
+    /**
+     * Timeout required for pending Binder calls or event processing to
+     * complete.
+     */
+    private static final long TIMEOUT_BINDER_CALL = 100;
+
+    /**
+     * Timeout used for testing that a service is notified only upon a
+     * notification timeout.
+     */
+    private static final long TIMEOUT_TEST_NOTIFICATION_TIMEOUT = 300;
+
+    /**
+     * The package name.
+     */
+    private static String sPackageName;
+
+    /**
+     * The interface used to talk to the tested service.
+     */
+    private IAccessibilityManager mManagerService;
+
+    @Override
+    public void setContext(Context context) {
+        super.setContext(context);
+        if (sPackageName == null) {
+            sPackageName = context.getPackageName();
+        }
+    }
+
+    /**
+     * Creates a new instance.
+     */
+    public AccessibilityManagerServiceTest() {
+        IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
+        mManagerService = IAccessibilityManager.Stub.asInterface(iBinder);
+    }
+
+    @LargeTest
+    public void testAddClient_AccessibilityDisabledThenEnabled() throws Exception {
+        // make sure accessibility is disabled
+        ensureAccessibilityEnabled(mContext, false);
+
+        // create a client mock instance
+        MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
+
+        // invoke the method under test
+        boolean enabledAccessibilityDisabled = mManagerService.addClient(mockClient);
+
+        // check expected result
+        assertFalse("The client must be disabled since accessibility is disabled.",
+                enabledAccessibilityDisabled);
+
+        // enable accessibility
+        ensureAccessibilityEnabled(mContext, true);
+
+        // invoke the method under test
+        boolean enabledAccessibilityEnabled = mManagerService.addClient(mockClient);
+
+        // check expected result
+        assertTrue("The client must be enabled since accessibility is enabled.",
+                enabledAccessibilityEnabled);
+    }
+
+    @LargeTest
+    public void testAddClient_AccessibilityEnabledThenDisabled() throws Exception {
+        // enable accessibility before registering the client
+        ensureAccessibilityEnabled(mContext, true);
+
+        // create a client mock instance
+        MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
+
+        // invoke the method under test
+        boolean enabledAccessibilityEnabled = mManagerService.addClient(mockClient);
+
+        // check expected result
+        assertTrue("The client must be enabled since accessibility is enabled.",
+                enabledAccessibilityEnabled);
+
+        // disable accessibility
+        ensureAccessibilityEnabled(mContext, false);
+
+        // invoke the method under test
+        boolean enabledAccessibilityDisabled = mManagerService.addClient(mockClient);
+
+        // check expected result
+        assertFalse("The client must be disabled since accessibility is disabled.",
+                enabledAccessibilityDisabled);
+    }
+
+    @LargeTest
+    public void testGetAccessibilityServicesList() throws Exception {
+        boolean firstMockServiceInstalled = false;
+        boolean secondMockServiceInstalled = false;
+
+        String packageName = getContext().getPackageName();
+        String firstMockServiceClassName = MyFirstMockAccessibilityService.class.getName();
+        String secondMockServiceClassName = MySecondMockAccessibilityService.class.getName();
+
+        // look for the two mock services
+        for (ServiceInfo serviceInfo : mManagerService.getAccessibilityServiceList()) {
+            if (packageName.equals(serviceInfo.packageName)) {
+                if (firstMockServiceClassName.equals(serviceInfo.name)) {
+                    firstMockServiceInstalled = true;
+                } else if (secondMockServiceClassName.equals(serviceInfo.name)) {
+                    secondMockServiceInstalled = true;
+                }
+            }
+        }
+
+        // check expected result
+        assertTrue("First mock service must be installed", firstMockServiceInstalled);
+        assertTrue("Second mock service must be installed", secondMockServiceInstalled);
+    }
+
+    @LargeTest
+    public void testSendAccessibilityEvent_OneService_MatchingPackageAndEventType()
+            throws Exception {
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
+        // enable the mock accessibility service
+        ensureOnlyMockServicesEnabled(mContext, MyFirstMockAccessibilityService.sComponentName);
+
+        // configure the mock service
+        MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
+        service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
+
+        // wait for the binder call to #setService to complete
+        Thread.sleep(TIMEOUT_BINDER_CALL);
+
+        // create and populate an event to be sent
+        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+        fullyPopulateDefaultAccessibilityEvent(sentEvent);
+
+        // set expectations
+        service.expectEvent(sentEvent);
+        service.replay();
+
+        // send the event
+        mManagerService.sendAccessibilityEvent(sentEvent);
+
+        // verify if all expected methods have been called
+        assertMockServiceVerifiedWithinTimeout(service);
+    }
+
+    @LargeTest
+    public void testSendAccessibilityEvent_OneService_NotMatchingPackage() throws Exception {
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
+        // enable the mock accessibility service
+        ensureOnlyMockServicesEnabled(mContext, MyFirstMockAccessibilityService.sComponentName);
+
+        // configure the mock service
+        MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
+        service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
+
+        // wait for the binder call to #setService to complete
+        Thread.sleep(TIMEOUT_BINDER_CALL);
+
+        // create and populate an event to be sent
+        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+        fullyPopulateDefaultAccessibilityEvent(sentEvent);
+        sentEvent.setPackageName("no.service.registered.for.this.package");
+
+        // set expectations
+        service.replay();
+
+        // send the event
+        mManagerService.sendAccessibilityEvent(sentEvent);
+
+        // verify if all expected methods have been called
+        assertMockServiceVerifiedWithinTimeout(service);
+    }
+
+    @LargeTest
+    public void testSendAccessibilityEvent_OneService_NotMatchingEventType() throws Exception {
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
+        // enable the mock accessibility service
+        ensureOnlyMockServicesEnabled(mContext, MyFirstMockAccessibilityService.sComponentName);
+
+        // configure the mock service
+        MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
+        service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
+
+        // wait for the binder call to #setService to complete
+        Thread.sleep(TIMEOUT_BINDER_CALL);
+
+        // create and populate an event to be sent
+        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+        fullyPopulateDefaultAccessibilityEvent(sentEvent);
+        sentEvent.setEventType(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
+
+        // set expectations
+        service.replay();
+
+        // send the event
+        mManagerService.sendAccessibilityEvent(sentEvent);
+
+        // verify if all expected methods have been called
+        assertMockServiceVerifiedWithinTimeout(service);
+    }
+
+    @LargeTest
+    public void testSendAccessibilityEvent_OneService_NotifivationAfterTimeout() throws Exception {
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
+        // enable the mock accessibility service
+        ensureOnlyMockServicesEnabled(mContext, MyFirstMockAccessibilityService.sComponentName);
+
+        // configure the mock service
+        MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
+        AccessibilityServiceInfo info = MockAccessibilityService.createDefaultInfo();
+        info.notificationTimeout = TIMEOUT_TEST_NOTIFICATION_TIMEOUT;
+        service.setServiceInfo(info);
+
+        // wait for the binder call to #setService to complete
+        Thread.sleep(TIMEOUT_BINDER_CALL);
+
+        // create and populate the first event to be sent
+        AccessibilityEvent firstEvent = AccessibilityEvent.obtain();
+        fullyPopulateDefaultAccessibilityEvent(firstEvent);
+
+        // create and populate the second event to be sent
+        AccessibilityEvent secondEvent = AccessibilityEvent.obtain();
+        fullyPopulateDefaultAccessibilityEvent(secondEvent);
+
+        // set expectations
+        service.expectEvent(secondEvent);
+        service.replay();
+
+        // send the events
+        mManagerService.sendAccessibilityEvent(firstEvent);
+        mManagerService.sendAccessibilityEvent(secondEvent);
+
+        // wait for #sendAccessibilityEvent to reach the backing service
+        Thread.sleep(TIMEOUT_BINDER_CALL);
+
+        try {
+            service.verify();
+            fail("No events must be dispatched before the expiration of the notification timeout.");
+        } catch (IllegalStateException ise) {
+            /* expected */
+        }
+
+        // wait for the configured notification timeout to expire
+        Thread.sleep(TIMEOUT_TEST_NOTIFICATION_TIMEOUT);
+
+        // verify if all expected methods have been called
+        assertMockServiceVerifiedWithinTimeout(service);
+    }
+
+    @LargeTest
+    public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_DiffFeedback()
+            throws Exception {
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
+        // enable the mock accessibility services
+        ensureOnlyMockServicesEnabled(mContext, MyFirstMockAccessibilityService.sComponentName,
+                MySecondMockAccessibilityService.sComponentName);
+
+        // configure the first mock service
+        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
+        AccessibilityServiceInfo firstInfo = MockAccessibilityService.createDefaultInfo();
+        firstInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_AUDIBLE;
+        firstService.setServiceInfo(firstInfo);
+
+        // configure the second mock service
+        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
+        AccessibilityServiceInfo secondInfo = MockAccessibilityService.createDefaultInfo();
+        secondInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_HAPTIC;
+        secondService.setServiceInfo(secondInfo);
+
+        // wait for the binder calls to #setService to complete
+        Thread.sleep(TIMEOUT_BINDER_CALL);
+
+        // create and populate an event to be sent
+        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+        fullyPopulateDefaultAccessibilityEvent(sentEvent);
+
+        // set expectations for the first mock service
+        firstService.expectEvent(sentEvent);
+        firstService.replay();
+
+        // set expectations for the second mock service
+        secondService.expectEvent(sentEvent);
+        secondService.replay();
+
+        // send the event
+        mManagerService.sendAccessibilityEvent(sentEvent);
+
+        // verify if all expected methods have been called
+        assertMockServiceVerifiedWithinTimeout(firstService);
+        assertMockServiceVerifiedWithinTimeout(secondService);
+    }
+
+    @LargeTest
+    public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType()
+            throws Exception {
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
+        // enable the mock accessibility services
+        ensureOnlyMockServicesEnabled(mContext, MyFirstMockAccessibilityService.sComponentName,
+                MySecondMockAccessibilityService.sComponentName);
+
+        // configure the first mock service
+        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
+        firstService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
+
+        // configure the second mock service
+        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
+        secondService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
+
+        // wait for the binder calls to #setService to complete
+        Thread.sleep(TIMEOUT_BINDER_CALL);
+
+        // create and populate an event to be sent
+        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+        fullyPopulateDefaultAccessibilityEvent(sentEvent);
+
+        // set expectations for the first mock service
+        firstService.expectEvent(sentEvent);
+        firstService.replay();
+
+        // set expectations for the second mock service
+        secondService.replay();
+
+        // send the event
+        mManagerService.sendAccessibilityEvent(sentEvent);
+
+        // verify if all expected methods have been called
+        assertMockServiceVerifiedWithinTimeout(firstService);
+        assertMockServiceVerifiedWithinTimeout(secondService);
+    }
+
+    @LargeTest
+    public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_OneDefault()
+            throws Exception {
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
+        // enable the mock accessibility services
+        ensureOnlyMockServicesEnabled(mContext, MyFirstMockAccessibilityService.sComponentName,
+                MySecondMockAccessibilityService.sComponentName);
+
+        // configure the first mock service
+        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
+        AccessibilityServiceInfo firstInfo = MyFirstMockAccessibilityService.createDefaultInfo();
+        firstInfo.flags = AccessibilityServiceInfo.DEFAULT;
+        firstService.setServiceInfo(firstInfo);
+
+        // configure the second mock service
+        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
+        secondService.setServiceInfo(MySecondMockAccessibilityService.createDefaultInfo());
+
+        // wait for the binder calls to #setService to complete
+        Thread.sleep(TIMEOUT_BINDER_CALL);
+
+        // create and populate an event to be sent
+        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+        fullyPopulateDefaultAccessibilityEvent(sentEvent);
+
+        // set expectations for the first mock service
+        firstService.replay();
+
+        // set expectations for the second mock service
+        secondService.expectEvent(sentEvent);
+        secondService.replay();
+
+        // send the event
+        mManagerService.sendAccessibilityEvent(sentEvent);
+
+        // verify if all expected methods have been called
+        assertMockServiceVerifiedWithinTimeout(firstService);
+        assertMockServiceVerifiedWithinTimeout(secondService);
+    }
+
+    @LargeTest
+    public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_TwoDefault()
+            throws Exception {
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
+        // enable the mock accessibility services
+        ensureOnlyMockServicesEnabled(mContext, MyFirstMockAccessibilityService.sComponentName,
+                MySecondMockAccessibilityService.sComponentName);
+
+        // configure the first mock service
+        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
+        AccessibilityServiceInfo firstInfo = MyFirstMockAccessibilityService.createDefaultInfo();
+        firstInfo.flags = AccessibilityServiceInfo.DEFAULT;
+        firstService.setServiceInfo(firstInfo);
+
+        // configure the second mock service
+        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
+        AccessibilityServiceInfo secondInfo = MyFirstMockAccessibilityService.createDefaultInfo();
+        secondInfo.flags = AccessibilityServiceInfo.DEFAULT;
+        secondService.setServiceInfo(firstInfo);
+
+        // wait for the binder calls to #setService to complete
+        Thread.sleep(TIMEOUT_BINDER_CALL);
+
+        // create and populate an event to be sent
+        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+        fullyPopulateDefaultAccessibilityEvent(sentEvent);
+
+        // set expectations for the first mock service
+        firstService.expectEvent(sentEvent);
+        firstService.replay();
+
+        // set expectations for the second mock service
+        secondService.replay();
+
+        // send the event
+        mManagerService.sendAccessibilityEvent(sentEvent);
+
+        // verify if all expected methods have been called
+        assertMockServiceVerifiedWithinTimeout(firstService);
+        assertMockServiceVerifiedWithinTimeout(secondService);
+    }
+
+    @LargeTest
+    public void testInterrupt() throws Exception {
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
+        // enable the mock accessibility services
+        ensureOnlyMockServicesEnabled(mContext, MyFirstMockAccessibilityService.sComponentName,
+                MySecondMockAccessibilityService.sComponentName);
+
+        // configure the first mock service
+        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
+        firstService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
+
+        // configure the second mock service
+        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
+        secondService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
+
+        // wait for the binder calls to #setService to complete
+        Thread.sleep(TIMEOUT_BINDER_CALL);
+
+        // set expectations for the first mock service
+        firstService.expectInterrupt();
+        firstService.replay();
+
+        // set expectations for the second mock service
+        secondService.expectInterrupt();
+        secondService.replay();
+
+        // call the method under test
+        mManagerService.interrupt();
+
+        // verify if all expected methods have been called
+        assertMockServiceVerifiedWithinTimeout(firstService);
+        assertMockServiceVerifiedWithinTimeout(secondService);
+    }
+
+    /**
+     * Fully populates the {@link AccessibilityEvent} to marshal.
+     *
+     * @param sentEvent The event to populate.
+     */
+    private void fullyPopulateDefaultAccessibilityEvent(AccessibilityEvent sentEvent) {
+        sentEvent.setAddedCount(1);
+        sentEvent.setBeforeText("BeforeText");
+        sentEvent.setChecked(true);
+        sentEvent.setClassName("foo.bar.baz.Class");
+        sentEvent.setContentDescription("ContentDescription");
+        sentEvent.setCurrentItemIndex(1);
+        sentEvent.setEnabled(true);
+        sentEvent.setEventType(AccessibilityEvent.TYPE_VIEW_CLICKED);
+        sentEvent.setEventTime(1000);
+        sentEvent.setFromIndex(1);
+        sentEvent.setFullScreen(true);
+        sentEvent.setItemCount(1);
+        sentEvent.setPackageName("foo.bar.baz");
+        sentEvent.setParcelableData(Message.obtain(null, 1, null));
+        sentEvent.setPassword(true);
+        sentEvent.setRemovedCount(1);
+    }
+
+    /**
+     * This class is a mock {@link IAccessibilityManagerClient}.
+     */
+    public class MyMockAccessibilityManagerClient extends IAccessibilityManagerClient.Stub {
+        boolean mIsEnabled;
+
+        public void setEnabled(boolean enabled) {
+            mIsEnabled = enabled;
+        }
+    }
+
+    /**
+     * Ensures accessibility is in a given state by writing the state to the
+     * settings and waiting until the accessibility manager service pick it up.
+     *
+     * @param context A context handle to access the settings.
+     * @param enabled The accessibility state to write to the settings.
+     * @throws Exception If any error occurs.
+     */
+    private void ensureAccessibilityEnabled(Context context, boolean enabled) throws Exception {
+        boolean isEnabled = (Settings.Secure.getInt(context.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1 ? true : false);
+
+        if (isEnabled == enabled) {
+            return;
+        }
+
+        Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED,
+                enabled ? 1 : 0);
+
+        // wait the accessibility manager service to pick the change up
+        Thread.sleep(TIMEOUT_BINDER_CALL);
+    }
+
+    /**
+     * Ensures the only {@link MockAccessibilityService}s with given component
+     * names are enabled by writing to the system settings and waiting until the
+     * accessibility manager service picks that up.
+     *
+     * @param context A context handle to access the settings.
+     * @param componentNames The string representation of the
+     *            {@link ComponentName}s to enable.
+     * @throws Exception Exception If any error occurs.
+     */
+    private void ensureOnlyMockServicesEnabled(Context context, String... componentNames)
+            throws Exception {
+        String enabledServices = Settings.Secure.getString(context.getContentResolver(),
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+
+        StringBuilder servicesToEnable = new StringBuilder();
+        for (String componentName : componentNames) {
+            servicesToEnable.append(componentName).append(":");
+        }
+
+        if (servicesToEnable.equals(enabledServices)) {
+            return;
+        }
+
+        Settings.Secure.putString(context.getContentResolver(),
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, servicesToEnable.toString());
+
+        // wait the system to perform asynchronous processing
+        Thread.sleep(TIMEOUT_BINDER_CALL);
+    }
+
+    /**
+     * Asserts the the mock accessibility service has been successfully verified
+     * (which is it has received the expected method calls with expected
+     * arguments) within the {@link #TIMEOUT_BINDER_CALL}. The verified state is
+     * checked by polling upon small intervals.
+     *
+     * @param service The service to verify.
+     * @throws Exception If the verification has failed with exception after the
+     *             {@link #TIMEOUT_BINDER_CALL}.
+     */
+    private void assertMockServiceVerifiedWithinTimeout(MockAccessibilityService service)
+            throws Exception {
+        Exception lastVerifyException = null;
+        long beginTime = SystemClock.uptimeMillis();
+        long pollTmeout = TIMEOUT_BINDER_CALL / 5;
+
+        // poll until the timeout has elapsed
+        while (SystemClock.uptimeMillis() - beginTime < TIMEOUT_BINDER_CALL) {
+            // sleep first since immediate call will always fail
+            try {
+                Thread.sleep(pollTmeout);
+            } catch (InterruptedException ie) {
+                /* ignore */
+            }
+            // poll for verification and if this fails save the exception and
+            // keep polling
+            try {
+                service.verify();
+                // reset so it does not accept more events
+                service.reset();
+                return;
+            } catch (Exception e) {
+                lastVerifyException = e;
+            }
+        }
+
+        // reset, we have already failed
+        service.reset();
+
+        // always not null
+        throw lastVerifyException;
+    }
+
+    /**
+     * This class is the first mock {@link AccessibilityService}.
+     */
+    public static class MyFirstMockAccessibilityService extends MockAccessibilityService {
+
+        /**
+         * The service {@link ComponentName} flattened as a string.
+         */
+        static final String sComponentName = new ComponentName(
+                sPackageName,
+                MyFirstMockAccessibilityService.class.getName()
+                ).flattenToShortString();
+
+        /**
+         * Handle to the service instance.
+         */
+        static MyFirstMockAccessibilityService sInstance;
+
+        /**
+         * Creates a new instance.
+         */
+        public MyFirstMockAccessibilityService() {
+            sInstance = this;
+        }
+    }
+
+    /**
+     * This class is the first mock {@link AccessibilityService}.
+     */
+    public static class MySecondMockAccessibilityService extends MockAccessibilityService {
+
+        /**
+         * The service {@link ComponentName} flattened as a string.
+         */
+        static final String sComponentName = new ComponentName(
+                sPackageName,
+                MySecondMockAccessibilityService.class.getName()
+                ).flattenToShortString();
+
+        /**
+         * Handle to the service instance.
+         */
+        static MySecondMockAccessibilityService sInstance;
+
+        /**
+         * Creates a new instance.
+         */
+        public MySecondMockAccessibilityService() {
+            sInstance = this;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
new file mode 100644
index 0000000..38fed22
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static org.easymock.EasyMock.createStrictMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reportMatcher;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+
+import org.easymock.IArgumentMatcher;
+
+import android.content.pm.ServiceInfo;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
+import android.view.accessibility.IAccessibilityManagerClient;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for the AccessibilityManager which mocking the backing service.
+ */
+public class AccessibilityManagerTest extends AndroidTestCase {
+
+    /**
+     * Timeout required for pending Binder calls or event processing to
+     * complete.
+     */
+    public static final long TIMEOUT_BINDER_CALL = 50;
+
+    /**
+     * The reusable mock {@link IAccessibilityManager}.
+     */
+    private final IAccessibilityManager mMockServiceInterface =
+        createStrictMock(IAccessibilityManager.class);
+
+    @Override
+    public void setUp() throws Exception {
+        reset(mMockServiceInterface);
+    }
+
+    @MediumTest
+    public void testGetAccessibilityServiceList() throws Exception {
+        // create a list of installed accessibility services the mock service returns
+        List<ServiceInfo> expectedServices = new ArrayList<ServiceInfo>();
+        ServiceInfo serviceInfo = new ServiceInfo();
+        serviceInfo.name = "TestServiceInfoName";
+        expectedServices.add(serviceInfo);
+
+        // configure the mock service behavior
+        IAccessibilityManager mockServiceInterface = mMockServiceInterface;
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true);
+        expect(mockServiceInterface.getAccessibilityServiceList()).andReturn(expectedServices);
+        replay(mockServiceInterface);
+
+        // invoke the method under test
+        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+        List<ServiceInfo> receivedServices = manager.getAccessibilityServiceList();
+
+        // check expected result (list equals() compares it contents as well)
+        assertEquals("All expected services must be returned", receivedServices, expectedServices);
+
+        // verify the mock service was properly called
+        verify(mockServiceInterface);
+    }
+
+    @MediumTest
+    public void testInterrupt() throws Exception {
+        // configure the mock service behavior
+        IAccessibilityManager mockServiceInterface = mMockServiceInterface;
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true);
+        mockServiceInterface.interrupt();
+        replay(mockServiceInterface);
+
+        // invoke the method under test
+        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+        manager.interrupt();
+
+        // verify the mock service was properly called
+        verify(mockServiceInterface);
+    }
+
+    @LargeTest
+    public void testIsEnabled() throws Exception {
+        // configure the mock service behavior
+        IAccessibilityManager mockServiceInterface = mMockServiceInterface;
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true);
+        replay(mockServiceInterface);
+
+        // invoke the method under test
+        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+        boolean isEnabledServiceEnabled = manager.isEnabled();
+
+        // check expected result
+        assertTrue("Must be enabled since the mock service is enabled", isEnabledServiceEnabled);
+
+        // disable accessibility
+        manager.getClient().setEnabled(false);
+
+        // wait for the asynchronous IBinder call to complete
+        Thread.sleep(TIMEOUT_BINDER_CALL);
+
+        // invoke the method under test
+        boolean isEnabledServcieDisabled = manager.isEnabled();
+
+        // check expected result
+        assertFalse("Must be disabled since the mock service is disabled",
+                isEnabledServcieDisabled);
+
+        // verify the mock service was properly called
+        verify(mockServiceInterface);
+    }
+
+    @MediumTest
+    public void testSendAccessibilityEvent_AccessibilityEnabled() throws Exception {
+        // create an event to be dispatched
+        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+
+        // configure the mock service behavior
+        IAccessibilityManager mockServiceInterface = mMockServiceInterface;
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true);
+        expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent)))
+                .andReturn(true);
+        expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent)))
+                .andReturn(false);
+        replay(mockServiceInterface);
+
+        // invoke the method under test (manager and service in different processes)
+        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+        manager.sendAccessibilityEvent(sentEvent);
+
+        // check expected result
+        AccessibilityEvent nextEventDifferentProcesses = AccessibilityEvent.obtain();
+        assertSame("The manager and the service are in different processes, so the event must be " +
+                "recycled", sentEvent, nextEventDifferentProcesses);
+
+        // invoke the method under test (manager and service in the same process)
+        manager.sendAccessibilityEvent(sentEvent);
+
+        // check expected result
+        AccessibilityEvent nextEventSameProcess = AccessibilityEvent.obtain();
+        assertNotSame("The manager and the service are in the same process, so the event must not" +
+                "be recycled", sentEvent, nextEventSameProcess);
+
+        // verify the mock service was properly called
+        verify(mockServiceInterface);
+    }
+
+    @MediumTest
+    public void testSendAccessibilityEvent_AccessibilityDisabled() throws Exception {
+        // create an event to be dispatched
+        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+
+        // configure the mock service behavior
+        IAccessibilityManager mockServiceInterface = mMockServiceInterface;
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(false);
+        replay(mockServiceInterface);
+
+        // invoke the method under test (accessibility disabled)
+        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+        try {
+            manager.sendAccessibilityEvent(sentEvent);
+            fail("No accessibility events are sent if accessibility is disabled");
+        } catch (IllegalStateException ise) {
+            // check expected result
+            assertEquals("Accessibility off. Did you forget to check that?", ise.getMessage());
+        }
+
+        // verify the mock service was properly called
+        verify(mockServiceInterface);
+    }
+
+    /**
+     * Determines if an {@link AccessibilityEvent} passed as a method argument
+     * matches expectations.
+     *
+     * @param matched The event to check.
+     * @return True if expectations are matched.
+     */
+    private static AccessibilityEvent eqAccessibilityEvent(AccessibilityEvent matched) {
+        reportMatcher(new AccessibilityEventMather(matched));
+        return null;
+    }
+
+    /**
+     * Determines if an {@link IAccessibilityManagerClient} passed as a method argument
+     * matches expectations which in this case are that any instance is accepted.
+     *
+     * @return <code>null</code>.
+     */
+    private static IAccessibilityManagerClient anyIAccessibilityManagerClient() {
+        reportMatcher(new AnyIAccessibilityManagerClientMather());
+        return null;
+    }
+
+    /**
+     * Matcher for {@link AccessibilityEvent}s.
+     */
+    private static class AccessibilityEventMather implements IArgumentMatcher {
+        private AccessibilityEvent mExpectedEvent;
+
+        public AccessibilityEventMather(AccessibilityEvent expectedEvent) {
+            mExpectedEvent = expectedEvent;
+        }
+
+        public boolean matches(Object matched) {
+            if (!(matched instanceof AccessibilityEvent)) {
+                return false;
+            }
+            AccessibilityEvent receivedEvent = (AccessibilityEvent) matched;
+            return mExpectedEvent.getEventType() == receivedEvent.getEventType();
+        }
+
+        public void appendTo(StringBuffer buffer) {
+            buffer.append("sendAccessibilityEvent()");
+            buffer.append(" with event type \"");
+            buffer.append(mExpectedEvent.getEventType());
+            buffer.append("\"");
+        }
+    }
+
+    /**
+     * Matcher for {@link IAccessibilityManagerClient}s.
+     */
+    private static class AnyIAccessibilityManagerClientMather implements IArgumentMatcher {
+        public boolean matches(Object matched) {
+            if (!(matched instanceof IAccessibilityManagerClient)) {
+                return false;
+            }
+            return true;
+        }
+
+        public void appendTo(StringBuffer buffer) {
+            buffer.append("addClient() with any IAccessibilityManagerClient");
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java b/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java
new file mode 100644
index 0000000..663c121
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.os.Message;
+import android.view.accessibility.AccessibilityEvent;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+
+import junit.framework.TestCase;
+
+/**
+ * This is the base class for mock {@link AccessibilityService}s.
+ */
+public abstract class MockAccessibilityService extends AccessibilityService {
+
+    /**
+     * The event this service expects to receive.
+     */
+    private final Queue<AccessibilityEvent> mExpectedEvents = new LinkedList<AccessibilityEvent>();
+
+    /**
+     * Interruption call this service expects to receive.
+     */
+    private boolean mExpectedInterrupt;
+
+    /**
+     * Flag if the mock is currently replaying.
+     */
+    private boolean mReplaying;
+
+    /**
+     * Creates an {@link AccessibilityServiceInfo} populated with default
+     * values.
+     *
+     * @return The default info.
+     */
+    public static AccessibilityServiceInfo createDefaultInfo() {
+        AccessibilityServiceInfo defaultInfo = new AccessibilityServiceInfo();
+        defaultInfo.eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED;
+        defaultInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_AUDIBLE;
+        defaultInfo.flags = 0;
+        defaultInfo.notificationTimeout = 0;
+        defaultInfo.packageNames = new String[] {
+            "foo.bar.baz"
+        };
+
+        return defaultInfo;
+    }
+
+    /**
+     * Starts replaying the mock.
+     */
+    public void replay() {
+        mReplaying = true;
+    }
+
+    /**
+     * Verifies if all expected service methods have been called.
+     */
+    public void verify() {
+        if (!mReplaying) {
+            throw new IllegalStateException("Did you forget to call replay()");
+        }
+
+        if (mExpectedInterrupt) {
+            throw new IllegalStateException("Expected call to #interrupt() not received");
+        }
+        if (!mExpectedEvents.isEmpty()) {
+            throw new IllegalStateException("Expected a call to onAccessibilityEvent() for "
+                    + "events \"" + mExpectedEvents + "\" not received");
+        }
+    }
+
+    /**
+     * Resets this instance so it can be reused.
+     */
+    public void reset() {
+        mExpectedEvents.clear();
+        mExpectedInterrupt = false;
+        mReplaying = false;
+    }
+
+    /**
+     * Sets an expected call to
+     * {@link #onAccessibilityEvent(AccessibilityEvent)} with given event as
+     * argument.
+     *
+     * @param expectedEvent The expected event argument.
+     */
+    public void expectEvent(AccessibilityEvent expectedEvent) {
+        mExpectedEvents.add(expectedEvent);
+    }
+
+    /**
+     * Sets an expected call of {@link #onInterrupt()}.
+     */
+    public void expectInterrupt() {
+        mExpectedInterrupt = true;
+    }
+
+    @Override
+    public void onAccessibilityEvent(AccessibilityEvent receivedEvent) {
+        if (!mReplaying) {
+            return;
+        }
+
+        if (mExpectedEvents.isEmpty()) {
+            throw new IllegalStateException("Unexpected event: " + receivedEvent);
+        }
+
+        AccessibilityEvent expectedEvent = mExpectedEvents.poll();
+        assertEqualsAccessiblityEvent(expectedEvent, receivedEvent);
+    }
+
+    @Override
+    public void onInterrupt() {
+        if (!mReplaying) {
+            return;
+        }
+
+        if (!mExpectedInterrupt) {
+            throw new IllegalStateException("Unexpected call to onInterrupt()");
+        }
+
+        mExpectedInterrupt = false;
+    }
+
+    /**
+     * Compares all properties of the <code>expectedEvent</code> and the
+     * <code>receviedEvent</code> to verify that the received event is the one
+     * that is expected.
+     */
+    private void assertEqualsAccessiblityEvent(AccessibilityEvent expectedEvent,
+            AccessibilityEvent receivedEvent) {
+        TestCase.assertEquals("addedCount has incorrect value", expectedEvent.getAddedCount(),
+                receivedEvent.getAddedCount());
+        TestCase.assertEquals("beforeText has incorrect value", expectedEvent.getBeforeText(),
+                receivedEvent.getBeforeText());
+        TestCase.assertEquals("checked has incorrect value", expectedEvent.isChecked(),
+                receivedEvent.isChecked());
+        TestCase.assertEquals("className has incorrect value", expectedEvent.getClassName(),
+                receivedEvent.getClassName());
+        TestCase.assertEquals("contentDescription has incorrect value", expectedEvent
+                .getContentDescription(), receivedEvent.getContentDescription());
+        TestCase.assertEquals("currentItemIndex has incorrect value", expectedEvent
+                .getCurrentItemIndex(), receivedEvent.getCurrentItemIndex());
+        TestCase.assertEquals("enabled has incorrect value", expectedEvent.isEnabled(),
+                receivedEvent.isEnabled());
+        TestCase.assertEquals("eventType has incorrect value", expectedEvent.getEventType(),
+                receivedEvent.getEventType());
+        TestCase.assertEquals("fromIndex has incorrect value", expectedEvent.getFromIndex(),
+                receivedEvent.getFromIndex());
+        TestCase.assertEquals("fullScreen has incorrect value", expectedEvent.isFullScreen(),
+                receivedEvent.isFullScreen());
+        TestCase.assertEquals("itemCount has incorrect value", expectedEvent.getItemCount(),
+                receivedEvent.getItemCount());
+        assertEqualsNotificationAsParcelableData(expectedEvent, receivedEvent);
+        TestCase.assertEquals("password has incorrect value", expectedEvent.isPassword(),
+                receivedEvent.isPassword());
+        TestCase.assertEquals("removedCount has incorrect value", expectedEvent.getRemovedCount(),
+                receivedEvent.getRemovedCount());
+        assertEqualsText(expectedEvent, receivedEvent);
+    }
+
+    /**
+     * Compares the {@link android.os.Parcelable} data of the
+     * <code>expectedEvent</code> and <code>receivedEvent</code> to verify that
+     * the received event is the one that is expected.
+     */
+    private void assertEqualsNotificationAsParcelableData(AccessibilityEvent expectedEvent,
+            AccessibilityEvent receivedEvent) {
+        String message = "parcelableData has incorrect value";
+        Message expectedMessage = (Message) expectedEvent.getParcelableData();
+        Message receivedMessage = (Message) receivedEvent.getParcelableData();
+
+        if (expectedMessage == null) {
+            if (receivedMessage == null) {
+                return;
+            }
+        }
+
+        TestCase.assertNotNull(message, receivedMessage);
+
+        // we do a very simple sanity check since we do not test Message
+        TestCase.assertEquals(message, expectedMessage.what, receivedMessage.what);
+    }
+
+    /**
+     * Compares the text of the <code>expectedEvent</code> and
+     * <code>receivedEvent</code> by comparing the string representation of the
+     * corresponding {@link CharSequence}s.
+     */
+    private void assertEqualsText(AccessibilityEvent expectedEvent,
+            AccessibilityEvent receivedEvent) {
+        String message = "text has incorrect value";
+        List<CharSequence> expectedText = expectedEvent.getText();
+        List<CharSequence> receivedText = receivedEvent.getText();
+
+        TestCase.assertEquals(message, expectedText.size(), receivedText.size());
+
+        Iterator<CharSequence> expectedTextIterator = expectedText.iterator();
+        Iterator<CharSequence> receivedTextIterator = receivedText.iterator();
+
+        for (int i = 0; i < expectedText.size(); i++) {
+            // compare the string representation
+            TestCase.assertEquals(message, expectedTextIterator.next().toString(),
+                    receivedTextIterator.next().toString());
+        }
+    }
+}