Merge "Consolidate a11y unit tests and get them working" into oc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
101b151548
@@ -41,6 +41,7 @@ import android.util.Log;
|
||||
import android.view.IWindow;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.IntPair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -126,6 +127,8 @@ public final class AccessibilityManager {
|
||||
|
||||
final Handler mHandler;
|
||||
|
||||
final Handler.Callback mCallback;
|
||||
|
||||
boolean mIsEnabled;
|
||||
|
||||
int mRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK;
|
||||
@@ -217,12 +220,12 @@ public final class AccessibilityManager {
|
||||
// is now off an exception will be thrown. We want to have the exception
|
||||
// enforcement to guard against apps that fire unnecessary accessibility
|
||||
// events when accessibility is off.
|
||||
mHandler.obtainMessage(MyHandler.MSG_SET_STATE, state, 0).sendToTarget();
|
||||
mHandler.obtainMessage(MyCallback.MSG_SET_STATE, state, 0).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyServicesStateChanged() {
|
||||
mHandler.obtainMessage(MyHandler.MSG_NOTIFY_SERVICES_STATE_CHANGED).sendToTarget();
|
||||
mHandler.obtainMessage(MyCallback.MSG_NOTIFY_SERVICES_STATE_CHANGED).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -271,7 +274,8 @@ public final class AccessibilityManager {
|
||||
public AccessibilityManager(Context context, IAccessibilityManager service, int userId) {
|
||||
// Constructor can't be chained because we can't create an instance of an inner class
|
||||
// before calling another constructor.
|
||||
mHandler = new MyHandler(context.getMainLooper());
|
||||
mCallback = new MyCallback();
|
||||
mHandler = new Handler(context.getMainLooper(), mCallback);
|
||||
mUserId = userId;
|
||||
synchronized (mLock) {
|
||||
tryConnectToServiceLocked(service);
|
||||
@@ -288,6 +292,7 @@ public final class AccessibilityManager {
|
||||
* @hide
|
||||
*/
|
||||
public AccessibilityManager(Handler handler, IAccessibilityManager service, int userId) {
|
||||
mCallback = new MyCallback();
|
||||
mHandler = handler;
|
||||
mUserId = userId;
|
||||
synchronized (mLock) {
|
||||
@@ -302,6 +307,14 @@ public final class AccessibilityManager {
|
||||
return mClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public Handler.Callback getCallback() {
|
||||
return mCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the accessibility in the system is enabled.
|
||||
*
|
||||
@@ -711,15 +724,15 @@ public final class AccessibilityManager {
|
||||
mIsHighTextContrastEnabled = highTextContrastEnabled;
|
||||
|
||||
if (wasEnabled != enabled) {
|
||||
mHandler.sendEmptyMessage(MyHandler.MSG_NOTIFY_ACCESSIBILITY_STATE_CHANGED);
|
||||
mHandler.sendEmptyMessage(MyCallback.MSG_NOTIFY_ACCESSIBILITY_STATE_CHANGED);
|
||||
}
|
||||
|
||||
if (wasTouchExplorationEnabled != touchExplorationEnabled) {
|
||||
mHandler.sendEmptyMessage(MyHandler.MSG_NOTIFY_EXPLORATION_STATE_CHANGED);
|
||||
mHandler.sendEmptyMessage(MyCallback.MSG_NOTIFY_EXPLORATION_STATE_CHANGED);
|
||||
}
|
||||
|
||||
if (wasHighTextContrastEnabled != highTextContrastEnabled) {
|
||||
mHandler.sendEmptyMessage(MyHandler.MSG_NOTIFY_HIGH_TEXT_CONTRAST_STATE_CHANGED);
|
||||
mHandler.sendEmptyMessage(MyCallback.MSG_NOTIFY_HIGH_TEXT_CONTRAST_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -960,19 +973,15 @@ public final class AccessibilityManager {
|
||||
}
|
||||
}
|
||||
|
||||
private final class MyHandler extends Handler {
|
||||
private final class MyCallback implements Handler.Callback {
|
||||
public static final int MSG_NOTIFY_ACCESSIBILITY_STATE_CHANGED = 1;
|
||||
public static final int MSG_NOTIFY_EXPLORATION_STATE_CHANGED = 2;
|
||||
public static final int MSG_NOTIFY_HIGH_TEXT_CONTRAST_STATE_CHANGED = 3;
|
||||
public static final int MSG_SET_STATE = 4;
|
||||
public static final int MSG_NOTIFY_SERVICES_STATE_CHANGED = 5;
|
||||
|
||||
public MyHandler(Looper looper) {
|
||||
super(looper, null, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
public boolean handleMessage(Message message) {
|
||||
switch (message.what) {
|
||||
case MSG_NOTIFY_ACCESSIBILITY_STATE_CHANGED: {
|
||||
handleNotifyAccessibilityStateChanged();
|
||||
@@ -998,6 +1007,7 @@ public final class AccessibilityManager {
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,20 +52,6 @@
|
||||
<application>
|
||||
<uses-library android:name="android.test.runner" />
|
||||
|
||||
<service android:name="com.android.server.AccessibilityManagerServiceTest$MyFirstMockAccessibilityService"
|
||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.accessibilityservice.AccessibilityService"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service android:name="com.android.server.AccessibilityManagerServiceTest$MySecondMockAccessibilityService"
|
||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.accessibilityservice.AccessibilityService"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service android:name="com.android.server.accounts.TestAccountType1AuthenticatorService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
|
||||
@@ -1,762 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,18 +14,24 @@
|
||||
* 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;
|
||||
@@ -33,6 +39,10 @@ import android.view.accessibility.IAccessibilityManagerClient;
|
||||
|
||||
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;
|
||||
|
||||
@@ -40,44 +50,48 @@ import java.util.ArrayList;
|
||||
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 {
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AccessibilityManagerTest {
|
||||
private static final boolean WITH_A11Y_ENABLED = true;
|
||||
private static final boolean WITH_A11Y_DISABLED = false;
|
||||
|
||||
/**
|
||||
* Timeout required for pending Binder calls or event processing to
|
||||
* complete.
|
||||
*/
|
||||
public static final long TIMEOUT_BINDER_CALL = 50;
|
||||
@Mock private IAccessibilityManager mMockService;
|
||||
private MessageCapturingHandler mHandler;
|
||||
private Instrumentation mInstrumentation;
|
||||
|
||||
@Mock
|
||||
private IAccessibilityManager mMockService;
|
||||
@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<>();
|
||||
@@ -99,59 +113,50 @@ public class AccessibilityManagerTest extends AndroidTestCase {
|
||||
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());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,12 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||
import static org.mockito.Matchers.anyObject;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
@@ -48,6 +49,7 @@ import android.view.WindowManagerInternal;
|
||||
import android.view.WindowManagerInternal.MagnificationCallbacks;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.TypeSafeMatcher;
|
||||
@@ -471,9 +473,10 @@ public class MagnificationControllerTest {
|
||||
public void testResetIfNeeded_doesWhatItSays() {
|
||||
mMagnificationController.register();
|
||||
zoomIn2xToMiddle();
|
||||
reset(mMockAms);
|
||||
assertTrue(mMagnificationController.resetIfNeeded(false));
|
||||
verify(mMockAms).notifyMagnificationChanged(
|
||||
eq(INITIAL_MAGNIFICATION_REGION), eq(1.0f), anyInt(), anyInt());
|
||||
eq(INITIAL_MAGNIFICATION_REGION), eq(1.0f), anyFloat(), anyFloat());
|
||||
assertFalse(mMagnificationController.isMagnifying());
|
||||
assertFalse(mMagnificationController.resetIfNeeded(false));
|
||||
}
|
||||
|
||||
@@ -42,6 +42,10 @@ public class MessageCapturingHandler extends Handler {
|
||||
return super.sendMessageAtTime(message, uptimeMillis);
|
||||
}
|
||||
|
||||
public void setCallback(Handler.Callback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
public void sendOneMessage() {
|
||||
Message message = timedMessages.remove(0).first;
|
||||
removeMessages(message.what, message.obj);
|
||||
|
||||
Reference in New Issue
Block a user