+++ /dev/null
-/*
- * 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.os.UserHandle;
-import android.provider.Settings;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.IAccessibilityManager;
-import android.view.accessibility.IAccessibilityManagerClient;
-
-import com.android.internal.util.IntPair;
-
-/**
- * This test exercises the
- * {@link com.android.server.accessibility.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 in which we are waiting for the system to start the mock
- * accessibility services.
- */
- private static final long TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES = 1000;
-
- /**
- * Timeout used for testing that a service is notified only upon a
- * notification timeout.
- */
- private static final long TIMEOUT_TEST_NOTIFICATION_TIMEOUT = 300;
-
- /**
- * The interface used to talk to the tested service.
- */
- private IAccessibilityManager mManagerService;
-
- @Override
- protected void setUp() throws Exception {
- // Reset the state.
- ensureOnlyMockServicesEnabled(getContext(), false, false);
- }
-
- @Override
- public void setContext(Context context) {
- super.setContext(context);
- if (MyFirstMockAccessibilityService.sComponentName == null) {
- MyFirstMockAccessibilityService.sComponentName = new ComponentName(
- context.getPackageName(), MyFirstMockAccessibilityService.class.getName())
- .flattenToShortString();
- }
- if (MySecondMockAccessibilityService.sComponentName == null) {
- MySecondMockAccessibilityService.sComponentName = new ComponentName(
- context.getPackageName(), MySecondMockAccessibilityService.class.getName())
- .flattenToShortString();
- }
- }
-
- /**
- * 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 {
- // at least some service must be enabled, otherwise accessibility will always be disabled.
- ensureOnlyMockServicesEnabled(mContext, true, false);
-
- // make sure accessibility is disabled
- ensureAccessibilityEnabled(mContext, false);
-
- // create a client mock instance
- MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
-
- // invoke the method under test
- final int stateFlagsDisabled =
- IntPair.first(mManagerService.addClient(mockClient, UserHandle.USER_CURRENT));
- boolean enabledAccessibilityDisabled =
- (stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
-
- // check expected result
- assertFalse("The client must be disabled since accessibility is disabled.",
- enabledAccessibilityDisabled);
-
- // enable accessibility
- ensureAccessibilityEnabled(mContext, true);
-
- // invoke the method under test
- final int stateFlagsEnabled =
- IntPair.first(mManagerService.addClient(mockClient, UserHandle.USER_CURRENT));
- boolean enabledAccessibilityEnabled =
- (stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
-
- // check expected result
- assertTrue("The client must be enabled since accessibility is enabled.",
- enabledAccessibilityEnabled);
- }
-
- @LargeTest
- public void testAddClient_AccessibilityEnabledThenDisabled() throws Exception {
- // at least some service must be enabled, otherwise accessibility will always be disabled.
- ensureOnlyMockServicesEnabled(mContext, true, false);
-
- // enable accessibility before registering the client
- ensureAccessibilityEnabled(mContext, true);
-
- // create a client mock instance
- MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
-
- // invoke the method under test
- final int stateFlagsEnabled =
- IntPair.first(mManagerService.addClient(mockClient, UserHandle.USER_CURRENT));
- boolean enabledAccessibilityEnabled =
- (stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
-
- // check expected result
- assertTrue("The client must be enabled since accessibility is enabled.",
- enabledAccessibilityEnabled);
-
- // disable accessibility
- ensureAccessibilityEnabled(mContext, false);
-
- // invoke the method under test
- final int stateFlagsDisabled =
- IntPair.first(mManagerService.addClient(mockClient, UserHandle.USER_CURRENT));
- boolean enabledAccessibilityDisabled =
- (stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
-
- // 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 (AccessibilityServiceInfo info : mManagerService.getInstalledAccessibilityServiceList(
- UserHandle.USER_CURRENT)) {
- ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
- 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 {
- // enable the mock accessibility service
- ensureOnlyMockServicesEnabled(mContext, true, false);
-
- // set the accessibility setting value
- ensureAccessibilityEnabled(mContext, true);
-
- // 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, UserHandle.USER_CURRENT);
-
- // verify if all expected methods have been called
- assertMockServiceVerifiedWithinTimeout(service);
- }
-
- @LargeTest
- public void testSendAccessibilityEvent_OneService_NotMatchingPackage() throws Exception {
- // enable the mock accessibility service
- ensureOnlyMockServicesEnabled(mContext, true, false);
-
- // set the accessibility setting value
- ensureAccessibilityEnabled(mContext, true);
-
- // 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, UserHandle.USER_CURRENT);
-
- // verify if all expected methods have been called
- assertMockServiceVerifiedWithinTimeout(service);
- }
-
- @LargeTest
- public void testSendAccessibilityEvent_OneService_NotMatchingEventType() throws Exception {
- // enable the mock accessibility service
- ensureOnlyMockServicesEnabled(mContext, true, false);
-
- // set the accessibility setting value
- ensureAccessibilityEnabled(mContext, true);
-
- // 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, UserHandle.USER_CURRENT);
-
- // verify if all expected methods have been called
- assertMockServiceVerifiedWithinTimeout(service);
- }
-
- @LargeTest
- public void testSendAccessibilityEvent_OneService_NotificationAfterTimeout() throws Exception {
- // enable the mock accessibility service
- ensureOnlyMockServicesEnabled(mContext, true, false);
-
- // set the accessibility setting value
- ensureAccessibilityEnabled(mContext, true);
-
- // 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, UserHandle.USER_CURRENT);
- mManagerService.sendAccessibilityEvent(secondEvent, UserHandle.USER_CURRENT);
-
- // 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 {
- // enable the mock accessibility services
- ensureOnlyMockServicesEnabled(mContext, true, true);
-
- // set the accessibility setting value
- ensureAccessibilityEnabled(mContext, true);
-
- // 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, UserHandle.USER_CURRENT);
-
- // verify if all expected methods have been called
- assertMockServiceVerifiedWithinTimeout(firstService);
- assertMockServiceVerifiedWithinTimeout(secondService);
- }
-
- @LargeTest
- public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType()
- throws Exception {
- // enable the mock accessibility services
- ensureOnlyMockServicesEnabled(mContext, true, true);
-
- // set the accessibility setting value
- ensureAccessibilityEnabled(mContext, true);
-
- // 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, UserHandle.USER_CURRENT);
-
- // verify if all expected methods have been called
- assertMockServiceVerifiedWithinTimeout(firstService);
- assertMockServiceVerifiedWithinTimeout(secondService);
- }
-
- @LargeTest
- public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_OneDefault()
- throws Exception {
- // enable the mock accessibility services
- ensureOnlyMockServicesEnabled(mContext, true, true);
-
- // set the accessibility setting value
- ensureAccessibilityEnabled(mContext, true);
-
- // 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, UserHandle.USER_CURRENT);
-
- // verify if all expected methods have been called
- assertMockServiceVerifiedWithinTimeout(firstService);
- assertMockServiceVerifiedWithinTimeout(secondService);
- }
-
- @LargeTest
- public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_TwoDefault()
- throws Exception {
- // enable the mock accessibility services
- ensureOnlyMockServicesEnabled(mContext, true, true);
-
- // set the accessibility setting value
- ensureAccessibilityEnabled(mContext, true);
-
- // 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, UserHandle.USER_CURRENT);
-
- // verify if all expected methods have been called
- assertMockServiceVerifiedWithinTimeout(firstService);
- assertMockServiceVerifiedWithinTimeout(secondService);
- }
-
- @LargeTest
- public void testInterrupt() throws Exception {
- // enable the mock accessibility services
- ensureOnlyMockServicesEnabled(mContext, true, true);
-
- // set the accessibility setting value
- ensureAccessibilityEnabled(mContext, true);
-
- // 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(UserHandle.USER_CURRENT);
-
- // 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_ANNOUNCEMENT);
- 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 {
- int mState;
-
- public void setState(int state) {
- mState = state;
- }
-
- public void notifyServicesStateChanged() {}
-
- public void setRelevantEventTypes(int eventTypes) {}
-
- public void setTouchExplorationEnabled(boolean 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;
-
- 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 or the
- * {@link #TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES} is exceeded.
- *
- * @param context A context handle to access the settings.
- * @param firstMockServiceEnabled If the first mock accessibility service is enabled.
- * @param secondMockServiceEnabled If the second mock accessibility service is enabled.
- * @throws IllegalStateException If some of the requested for enabling mock services
- * is not properly started.
- * @throws Exception Exception If any error occurs.
- */
- private void ensureOnlyMockServicesEnabled(Context context, boolean firstMockServiceEnabled,
- boolean secondMockServiceEnabled) throws Exception {
- String enabledServices = Settings.Secure.getString(context.getContentResolver(),
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
-
- StringBuilder servicesToEnable = new StringBuilder();
- if (firstMockServiceEnabled) {
- servicesToEnable.append(MyFirstMockAccessibilityService.sComponentName).append(":");
- }
- if (secondMockServiceEnabled) {
- servicesToEnable.append(MySecondMockAccessibilityService.sComponentName).append(":");
- }
-
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, servicesToEnable.toString());
-
- // Optimization. If things will not change, we don't have to do anything.
- if (servicesToEnable.equals(enabledServices)) {
- return;
- }
-
- // we have enabled the services of interest and need to wait until they
- // are instantiated and started (if needed) and the system binds to them
- boolean firstMockServiceOK = false;
- boolean secondMockServiceOK = false;
- long start = SystemClock.uptimeMillis();
- long pollingInterval = TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES / 6;
-
- while (SystemClock.uptimeMillis() - start < TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES) {
- firstMockServiceOK = !firstMockServiceEnabled
- || (MyFirstMockAccessibilityService.sInstance != null
- && MyFirstMockAccessibilityService.sInstance.isSystemBoundAsClient());
-
- secondMockServiceOK = !secondMockServiceEnabled
- || (MySecondMockAccessibilityService.sInstance != null
- && MySecondMockAccessibilityService.sInstance.isSystemBoundAsClient());
-
- if (firstMockServiceOK && secondMockServiceOK) {
- return;
- }
-
- Thread.sleep(pollingInterval);
- }
-
- StringBuilder message = new StringBuilder();
- message.append("Mock accessibility services not started or system not bound as a client: ");
- if (!firstMockServiceOK) {
- message.append(MyFirstMockAccessibilityService.sComponentName);
- message.append(" ");
- }
- if (!secondMockServiceOK) {
- message.append(MySecondMockAccessibilityService.sComponentName);
- }
- throw new IllegalStateException(message.toString());
- }
-
- /**
- * 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 pollTimeout = 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(pollTimeout);
- } 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 String sComponentName;
-
- /**
- * 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 String sComponentName;
-
- /**
- * Handle to the service instance.
- */
- static MySecondMockAccessibilityService sInstance;
-
- /**
- * Creates a new instance.
- */
- public MySecondMockAccessibilityService() {
- sInstance = this;
- }
- }
-}
+++ /dev/null
-/*
- * 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.Intent;
-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;
-
- /**
- * Flag if the system is bound as a client to this service.
- */
- private boolean mIsSystemBoundAsClient;
-
- /**
- * Creates an {@link AccessibilityServiceInfo} populated with default
- * values.
- *
- * @return The default info.
- */
- public static AccessibilityServiceInfo createDefaultInfo() {
- AccessibilityServiceInfo defaultInfo = new AccessibilityServiceInfo();
- defaultInfo.eventTypes = AccessibilityEvent.TYPE_ANNOUNCEMENT;
- 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;
- }
-
- @Override
- protected void onServiceConnected() {
- mIsSystemBoundAsClient = true;
- }
-
- @Override
- public boolean onUnbind(Intent intent) {
- mIsSystemBoundAsClient = false;
- return false;
- }
-
- /**
- * Returns if the system is bound as client to this service.
- *
- * @return True if the system is bound, false otherwise.
- */
- public boolean isSystemBoundAsClient() {
- return mIsSystemBoundAsClient;
- }
-
- /**
- * 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());
- }
- }
-}
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.accessibility;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertSame;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.Instrumentation;
+import android.os.Looper;
import android.os.UserHandle;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
import com.android.internal.util.IntPair;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.List;
/**
- * Tests for the AccessibilityManager which mocking the backing service.
+ * Tests for the AccessibilityManager by 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;
-
- @Mock
- private IAccessibilityManager mMockService;
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityManagerTest {
+ private static final boolean WITH_A11Y_ENABLED = true;
+ private static final boolean WITH_A11Y_DISABLED = false;
+
+ @Mock private IAccessibilityManager mMockService;
+ private MessageCapturingHandler mHandler;
+ private Instrumentation mInstrumentation;
+
+ @BeforeClass
+ public static void oneTimeInitialization() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ }
- @Override
+ @Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mHandler = new MessageCapturingHandler(null);
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
}
private AccessibilityManager createManager(boolean enabled) throws Exception {
- if (enabled) {
- when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt()))
- .thenReturn(
- IntPair.of(AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED,
- AccessibilityEvent.TYPES_ALL_MASK));
- } else {
- when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt()))
- .thenReturn(IntPair.of(0, AccessibilityEvent.TYPES_ALL_MASK));
- }
+ long serviceReturnValue = IntPair.of(
+ (enabled) ? AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED : 0,
+ AccessibilityEvent.TYPES_ALL_MASK);
+ when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt()))
+ .thenReturn(serviceReturnValue);
AccessibilityManager manager =
- new AccessibilityManager(mContext, mMockService, UserHandle.USER_CURRENT);
+ new AccessibilityManager(mHandler, mMockService, UserHandle.USER_CURRENT);
verify(mMockService).addClient(any(IAccessibilityManagerClient.class), anyInt());
-
+ mHandler.setCallback(manager.getCallback());
+ mHandler.sendAllMessages();
return manager;
}
- @MediumTest
+ @Test
public void testGetAccessibilityServiceList() throws Exception {
// create a list of installed accessibility services the mock service returns
List<AccessibilityServiceInfo> expectedServices = new ArrayList<>();
assertEquals("All expected services must be returned", expectedServices, receivedServices);
}
- @MediumTest
+ @Test
public void testInterrupt() throws Exception {
- AccessibilityManager manager = createManager(true);
+ AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
manager.interrupt();
verify(mMockService).interrupt(UserHandle.USER_CURRENT);
}
- @LargeTest
+ @Test
public void testIsEnabled() throws Exception {
- // invoke the method under test
- AccessibilityManager manager = createManager(true);
- boolean isEnabledServiceEnabled = manager.isEnabled();
+ // Create manager with a11y enabled
+ AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
+ assertTrue("Must be enabled since the mock service is enabled", manager.isEnabled());
- // check expected result
- assertTrue("Must be enabled since the mock service is enabled", isEnabledServiceEnabled);
-
- // disable accessibility
+ // Disable accessibility
manager.getClient().setState(0);
-
- // 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);
+ mHandler.sendAllMessages();
+ assertFalse("Must be disabled since the mock service is disabled", manager.isEnabled());
}
- @MediumTest
+ @Test
public void testSendAccessibilityEvent_AccessibilityEnabled() throws Exception {
- AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+ AccessibilityEvent sentEvent = AccessibilityEvent.obtain(
+ AccessibilityEvent.TYPE_ANNOUNCEMENT);
- AccessibilityManager manager = createManager(true);
+ AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
manager.sendAccessibilityEvent(sentEvent);
assertSame("The event should be recycled.", sentEvent, AccessibilityEvent.obtain());
}
- @MediumTest
+ @Test
public void testSendAccessibilityEvent_AccessibilityDisabled() throws Exception {
AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
- AccessibilityManager manager = createManager(false /* disabled */);
-
- 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());
- }
+ AccessibilityManager manager = createManager(WITH_A11Y_DISABLED);
+ mInstrumentation.runOnMainSync(() -> {
+ 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());
+ }
+ });
}
}