blob: 0f5afd15ef66de23af52a8192ce89d2a7f2c81f7 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view.accessibility.cts;
import static android.accessibility.cts.common.InstrumentedAccessibilityService.TIMEOUT_SERVICE_ENABLE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibility.cts.common.InstrumentedAccessibilityService;
import android.accessibility.cts.common.InstrumentedAccessibilityServiceTestRule;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Instrumentation;
import android.app.Service;
import android.app.UiAutomation;
import android.content.Context;
import android.content.pm.ServiceInfo;
import android.os.Handler;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
import android.view.accessibility.AccessibilityManager.AudioDescriptionRequestedChangeListener;
import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.SettingsStateChangerRule;
import com.android.compatibility.common.util.SystemUtil;
import com.android.compatibility.common.util.TestUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Class for testing {@link AccessibilityManager}.
*/
@RunWith(AndroidJUnit4.class)
public class AccessibilityManagerTest {
private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
new AccessibilityDumpOnFailureRule();
private InstrumentedAccessibilityServiceTestRule<SpeakingAccessibilityService>
mSpeakingAccessibilityServiceRule = new InstrumentedAccessibilityServiceTestRule<>(
SpeakingAccessibilityService.class, false);
private InstrumentedAccessibilityServiceTestRule<VibratingAccessibilityService>
mVibratingAccessibilityServiceRule = new InstrumentedAccessibilityServiceTestRule<>(
VibratingAccessibilityService.class, false);
private InstrumentedAccessibilityServiceTestRule<SpeakingAndVibratingAccessibilityService>
mSpeakingAndVibratingAccessibilityServiceRule =
new InstrumentedAccessibilityServiceTestRule<>(
SpeakingAndVibratingAccessibilityService.class, false);
private static final Instrumentation sInstrumentation =
InstrumentationRegistry.getInstrumentation();
private static final String SPEAKING_ACCESSIBLITY_SERVICE_NAME =
"android.view.accessibility.cts.SpeakingAccessibilityService";
private static final String VIBRATING_ACCESSIBLITY_SERVICE_NAME =
"android.view.accessibility.cts.VibratingAccessibilityService";
private static final String MULTIPLE_FEEDBACK_TYPES_ACCESSIBILITY_SERVICE_NAME =
"android.view.accessibility.cts.SpeakingAndVibratingAccessibilityService";
public static final String ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS =
"accessibility_non_interactive_ui_timeout_ms";
public static final String ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS =
"accessibility_interactive_ui_timeout_ms";
private static final String ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT =
"enabled_accessibility_audio_description_by_default";
private final SettingsStateChangerRule mAudioDescriptionSetterRule =
new SettingsStateChangerRule(
sInstrumentation.getContext(),
ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT,
"0");
@Rule
public final RuleChain mRuleChain = RuleChain
// SettingsStateChangerRule will suppress accessibility services, so it should be
// executed before enabling a11y services and after disabling a11y services.
.outerRule(mAudioDescriptionSetterRule)
.around(mSpeakingAndVibratingAccessibilityServiceRule)
.around(mVibratingAccessibilityServiceRule)
.around(mSpeakingAccessibilityServiceRule)
// Inner rule capture failure and dump data before finishing activity and a11y service
.around(mDumpOnFailureRule);
private AccessibilityManager mAccessibilityManager;
private Context mTargetContext;
private Handler mHandler;
@Before
public void setUp() throws Exception {
mAccessibilityManager = (AccessibilityManager)
sInstrumentation.getContext().getSystemService(Service.ACCESSIBILITY_SERVICE);
mTargetContext = sInstrumentation.getTargetContext();
mHandler = new Handler(mTargetContext.getMainLooper());
// In case the test runner started a UiAutomation, destroy it to start with a clean slate.
sInstrumentation.getUiAutomation().destroy();
InstrumentedAccessibilityService.disableAllServices();
}
@Test
public void testAddAndRemoveAccessibilityStateChangeListener() throws Exception {
AccessibilityStateChangeListener listener = (state) -> {
/* do nothing */
};
assertTrue(mAccessibilityManager.addAccessibilityStateChangeListener(listener));
assertTrue(mAccessibilityManager.removeAccessibilityStateChangeListener(listener));
assertFalse(mAccessibilityManager.removeAccessibilityStateChangeListener(listener));
}
@Test
public void testAddAndRemoveTouchExplorationStateChangeListener() throws Exception {
TouchExplorationStateChangeListener listener = (boolean enabled) -> {
// Do nothing.
};
assertTrue(mAccessibilityManager.addTouchExplorationStateChangeListener(listener));
assertTrue(mAccessibilityManager.removeTouchExplorationStateChangeListener(listener));
assertFalse(mAccessibilityManager.removeTouchExplorationStateChangeListener(listener));
}
@Test
public void testAddAndRemoveAudioDescriptionRequestedChangeListener() throws Exception {
AudioDescriptionRequestedChangeListener listener = (boolean enabled) -> {
// Do nothing.
};
mAccessibilityManager.addAudioDescriptionRequestedChangeListener(
mTargetContext.getMainExecutor(), listener);
assertTrue(
mAccessibilityManager.removeAudioDescriptionRequestedChangeListener(listener));
assertFalse(
mAccessibilityManager.removeAudioDescriptionRequestedChangeListener(listener));
}
@Test
public void testIsTouchExplorationEnabled() throws Exception {
mSpeakingAccessibilityServiceRule.enableService();
mVibratingAccessibilityServiceRule.enableService();
new PollingCheck() {
@Override
protected boolean check() {
return mAccessibilityManager.isTouchExplorationEnabled();
}
}.run();
}
@Test
public void testRemoveAccessibilityServicesStateChangeListener() throws Exception {
AccessibilityServicesStateChangeListener listener = (state) -> {
/* do nothing */
};
mAccessibilityManager.addAccessibilityServicesStateChangeListener(listener);
assertTrue(mAccessibilityManager.removeAccessibilityServicesStateChangeListener(listener));
assertFalse(mAccessibilityManager.removeAccessibilityServicesStateChangeListener(listener));
}
@Test
public void testGetInstalledAccessibilityServicesList() throws Exception {
List<AccessibilityServiceInfo> installedServices =
mAccessibilityManager.getInstalledAccessibilityServiceList();
assertFalse("There must be at least one installed service.", installedServices.isEmpty());
boolean speakingServiceInstalled = false;
boolean vibratingServiceInstalled = false;
final int serviceCount = installedServices.size();
for (int i = 0; i < serviceCount; i++) {
AccessibilityServiceInfo installedService = installedServices.get(i);
ServiceInfo serviceInfo = installedService.getResolveInfo().serviceInfo;
if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
&& SPEAKING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
speakingServiceInstalled = true;
}
if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
&& VIBRATING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
vibratingServiceInstalled = true;
}
}
assertTrue("The speaking service should be installed.", speakingServiceInstalled);
assertTrue("The vibrating service should be installed.", vibratingServiceInstalled);
}
@Test
public void testGetEnabledAccessibilityServiceList() throws Exception {
mSpeakingAccessibilityServiceRule.enableService();
mVibratingAccessibilityServiceRule.enableService();
List<AccessibilityServiceInfo> enabledServices =
mAccessibilityManager.getEnabledAccessibilityServiceList(
AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
boolean speakingServiceEnabled = false;
boolean vibratingServiceEnabled = false;
final int serviceCount = enabledServices.size();
for (int i = 0; i < serviceCount; i++) {
AccessibilityServiceInfo enabledService = enabledServices.get(i);
ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo;
if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
&& SPEAKING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
speakingServiceEnabled = true;
}
if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
&& VIBRATING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
vibratingServiceEnabled = true;
}
}
assertTrue("The speaking service should be enabled.", speakingServiceEnabled);
assertTrue("The vibrating service should be enabled.", vibratingServiceEnabled);
}
@Test
public void testGetEnabledAccessibilityServiceListForType() throws Exception {
mSpeakingAccessibilityServiceRule.enableService();
mVibratingAccessibilityServiceRule.enableService();
List<AccessibilityServiceInfo> enabledServices =
mAccessibilityManager.getEnabledAccessibilityServiceList(
AccessibilityServiceInfo.FEEDBACK_SPOKEN);
assertSame("There should be only one enabled speaking service.", 1, enabledServices.size());
final int serviceCount = enabledServices.size();
for (int i = 0; i < serviceCount; i++) {
AccessibilityServiceInfo enabledService = enabledServices.get(i);
ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo;
if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
&& SPEAKING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
return;
}
}
fail("The speaking service is not enabled.");
}
@Test
public void testGetEnabledAccessibilityServiceListForTypes() throws Exception {
mSpeakingAccessibilityServiceRule.enableService();
mVibratingAccessibilityServiceRule.enableService();
// For this test, also enable a service with multiple feedback types
mSpeakingAndVibratingAccessibilityServiceRule.enableService();
List<AccessibilityServiceInfo> enabledServices =
mAccessibilityManager.getEnabledAccessibilityServiceList(
AccessibilityServiceInfo.FEEDBACK_SPOKEN
| AccessibilityServiceInfo.FEEDBACK_HAPTIC);
assertSame("There should be 3 enabled accessibility services.", 3, enabledServices.size());
boolean speakingServiceEnabled = false;
boolean vibratingServiceEnabled = false;
boolean multipleFeedbackTypesServiceEnabled = false;
final int serviceCount = enabledServices.size();
for (int i = 0; i < serviceCount; i++) {
AccessibilityServiceInfo enabledService = enabledServices.get(i);
ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo;
if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
&& SPEAKING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
speakingServiceEnabled = true;
}
if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
&& VIBRATING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
vibratingServiceEnabled = true;
}
if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
&& MULTIPLE_FEEDBACK_TYPES_ACCESSIBILITY_SERVICE_NAME.equals(
serviceInfo.name)) {
multipleFeedbackTypesServiceEnabled = true;
}
}
assertTrue("The speaking service should be enabled.", speakingServiceEnabled);
assertTrue("The vibrating service should be enabled.", vibratingServiceEnabled);
assertTrue("The multiple feedback types service should be enabled.",
multipleFeedbackTypesServiceEnabled);
}
@SuppressWarnings("deprecation")
@Test
public void testGetAccessibilityServiceList() throws Exception {
List<ServiceInfo> services = mAccessibilityManager.getAccessibilityServiceList();
boolean speakingServiceInstalled = false;
boolean vibratingServiceInstalled = false;
final int serviceCount = services.size();
for (int i = 0; i < serviceCount; i++) {
ServiceInfo serviceInfo = services.get(i);
if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
&& SPEAKING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
speakingServiceInstalled = true;
}
if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
&& VIBRATING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
vibratingServiceInstalled = true;
}
}
assertTrue("The speaking service should be installed.", speakingServiceInstalled);
assertTrue("The vibrating service should be installed.", vibratingServiceInstalled);
}
@Test
public void testInterrupt() throws Exception {
// The APIs are heavily tested in the android.accessibilityservice package.
// This just makes sure the call does not throw an exception.
mSpeakingAccessibilityServiceRule.enableService();
mVibratingAccessibilityServiceRule.enableService();
waitForAccessibilityEnabled();
mAccessibilityManager.interrupt();
}
@Test
public void testSendAccessibilityEvent() throws Exception {
// The APIs are heavily tested in the android.accessibilityservice package.
// This just makes sure the call does not throw an exception.
mSpeakingAccessibilityServiceRule.enableService();
mVibratingAccessibilityServiceRule.enableService();
waitForAccessibilityEnabled();
mAccessibilityManager.sendAccessibilityEvent(AccessibilityEvent.obtain(
AccessibilityEvent.TYPE_VIEW_CLICKED));
}
@Test
public void testTouchExplorationListenerNoHandler() throws Exception {
final Object waitObject = new Object();
final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
TouchExplorationStateChangeListener listener = (boolean b) -> {
synchronized (waitObject) {
atomicBoolean.set(b);
waitObject.notifyAll();
}
};
mAccessibilityManager.addTouchExplorationStateChangeListener(listener);
mSpeakingAccessibilityServiceRule.enableService();
mVibratingAccessibilityServiceRule.enableService();
waitForAtomicBooleanBecomes(atomicBoolean, true, waitObject,
"Touch exploration state listener called when services enabled");
assertTrue("Listener told that touch exploration is enabled, but manager says disabled",
mAccessibilityManager.isTouchExplorationEnabled());
InstrumentedAccessibilityService.disableAllServices();
waitForAtomicBooleanBecomes(atomicBoolean, false, waitObject,
"Touch exploration state listener called when services disabled");
assertFalse("Listener told that touch exploration is disabled, but manager says it enabled",
mAccessibilityManager.isTouchExplorationEnabled());
mAccessibilityManager.removeTouchExplorationStateChangeListener(listener);
}
@Test
public void testTouchExplorationListenerWithHandler() throws Exception {
final Object waitObject = new Object();
final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
TouchExplorationStateChangeListener listener = (boolean b) -> {
synchronized (waitObject) {
atomicBoolean.set(b);
waitObject.notifyAll();
}
};
mAccessibilityManager.addTouchExplorationStateChangeListener(listener, mHandler);
mSpeakingAccessibilityServiceRule.enableService();
mVibratingAccessibilityServiceRule.enableService();
waitForAtomicBooleanBecomes(atomicBoolean, true, waitObject,
"Touch exploration state listener called when services enabled");
assertTrue("Listener told that touch exploration is enabled, but manager says disabled",
mAccessibilityManager.isTouchExplorationEnabled());
InstrumentedAccessibilityService.disableAllServices();
waitForAtomicBooleanBecomes(atomicBoolean, false, waitObject,
"Touch exploration state listener called when services disabled");
assertFalse("Listener told that touch exploration is disabled, but manager says it enabled",
mAccessibilityManager.isTouchExplorationEnabled());
mAccessibilityManager.removeTouchExplorationStateChangeListener(listener);
}
@Test
public void testAccessibilityServicesStateListenerNoExecutor() {
final Object waitObject = new Object();
final AtomicBoolean serviceEnabled = new AtomicBoolean(false);
final UiAutomation automan = sInstrumentation.getUiAutomation(
UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
final AccessibilityServicesStateChangeListener listener = (AccessibilityManager manager) ->
checkServiceEnabled(waitObject, manager, serviceEnabled,
VibratingAccessibilityService.class.getSimpleName());
try {
mAccessibilityManager.addAccessibilityServicesStateChangeListener(listener);
mVibratingAccessibilityServiceRule.enableService();
waitForAtomicBooleanBecomes(serviceEnabled, true, waitObject,
"Accessibility services state listener called when service is enabled");
} finally {
automan.destroy();
}
}
@Test
public void testAccessibilityServicesStateListenerWithExecutor() {
final Object waitObject = new Object();
final AtomicBoolean serviceEnabled = new AtomicBoolean(false);
final UiAutomation automan = sInstrumentation.getUiAutomation(
UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
final AccessibilityServicesStateChangeListener listener = (AccessibilityManager manager) ->
checkServiceEnabled(waitObject, manager, serviceEnabled,
VibratingAccessibilityService.class.getSimpleName());
try {
mAccessibilityManager.addAccessibilityServicesStateChangeListener(
mTargetContext.getMainExecutor(), listener);
mVibratingAccessibilityServiceRule.enableService();
waitForAtomicBooleanBecomes(serviceEnabled, true, waitObject,
"Accessibility services state listener called when service is enabled");
} finally {
automan.destroy();
}
}
@Test
public void testAccessibilityStateListenerNoHandler() throws Exception {
final Object waitObject = new Object();
final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
AccessibilityStateChangeListener listener = (boolean b) -> {
synchronized (waitObject) {
atomicBoolean.set(b);
waitObject.notifyAll();
}
};
mAccessibilityManager.addAccessibilityStateChangeListener(listener);
mSpeakingAndVibratingAccessibilityServiceRule.enableService();
waitForAtomicBooleanBecomes(atomicBoolean, true, waitObject,
"Accessibility state listener called when services enabled");
assertTrue("Listener told that accessibility is enabled, but manager says disabled",
mAccessibilityManager.isEnabled());
InstrumentedAccessibilityService.disableAllServices();
waitForAtomicBooleanBecomes(atomicBoolean, false, waitObject,
"Accessibility state listener called when services disabled");
assertFalse("Listener told that accessibility is disabled, but manager says enabled",
mAccessibilityManager.isEnabled());
mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
}
@Test
public void testAudioDescriptionRequestedChangeListenerWithExecutor() {
final UiAutomation automan = sInstrumentation.getUiAutomation(
UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
final Object waitObject = new Object();
final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
AudioDescriptionRequestedChangeListener listener = (boolean b) -> {
synchronized (waitObject) {
atomicBoolean.set(b);
waitObject.notifyAll();
}
};
try {
mAccessibilityManager.addAudioDescriptionRequestedChangeListener(
mTargetContext.getMainExecutor(), listener);
putSecureSetting(automan, ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT, "1");
waitForAtomicBooleanBecomes(atomicBoolean, true, waitObject,
"Audio description state listener called when services enabled");
assertTrue("Listener told that audio description by default is request.",
mAccessibilityManager.isAudioDescriptionRequested());
putSecureSetting(automan, ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT, "0");
waitForAtomicBooleanBecomes(atomicBoolean, false, waitObject,
"Audio description state listener called when services disabled");
assertFalse("Listener told that audio description by default is not request.",
mAccessibilityManager.isAudioDescriptionRequested());
assertTrue(
mAccessibilityManager.removeAudioDescriptionRequestedChangeListener(
listener));
} finally {
automan.destroy();
}
}
@Test
public void testIsAudioDescriptionEnabled() throws Exception {
final UiAutomation automan = sInstrumentation.getUiAutomation(
UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
try {
putSecureSetting(automan, ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT, "1");
PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
@Override
public boolean canProceed() {
return mAccessibilityManager.isAudioDescriptionRequested();
}
});
assertTrue(mAccessibilityManager.isAudioDescriptionRequested());
putSecureSetting(automan, ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT, "0");
PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
@Override
public boolean canProceed() {
return !mAccessibilityManager.isAudioDescriptionRequested();
}
});
assertFalse(mAccessibilityManager.isAudioDescriptionRequested());
} finally {
automan.destroy();
}
}
@Test
public void testAccessibilityStateListenerWithHandler() throws Exception {
final Object waitObject = new Object();
final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
AccessibilityStateChangeListener listener = (boolean b) -> {
synchronized (waitObject) {
atomicBoolean.set(b);
waitObject.notifyAll();
}
};
mAccessibilityManager.addAccessibilityStateChangeListener(listener, mHandler);
mSpeakingAndVibratingAccessibilityServiceRule.enableService();
waitForAtomicBooleanBecomes(atomicBoolean, true, waitObject,
"Accessibility state listener called when services enabled");
assertTrue("Listener told that accessibility is enabled, but manager says disabled",
mAccessibilityManager.isEnabled());
InstrumentedAccessibilityService.disableAllServices();
waitForAtomicBooleanBecomes(atomicBoolean, false, waitObject,
"Accessibility state listener called when services disabled");
assertFalse("Listener told that accessibility is disabled, but manager says enabled",
mAccessibilityManager.isEnabled());
mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
}
@Test
public void testGetRecommendedTimeoutMillis() throws Exception {
mSpeakingAccessibilityServiceRule.enableService();
mVibratingAccessibilityServiceRule.enableService();
waitForAccessibilityEnabled();
UiAutomation automan = sInstrumentation.getUiAutomation(
UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
try {
// SpeakingA11yService interactive/nonInteractive timeout is 6000/1000
// vibratingA11yService interactive/nonInteractive timeout is 5000/2000
turnOffRecommendedUiTimoutSettings(automan);
PollingCheck.waitFor(() -> sameRecommendedTimeout(6000, 2000));
turnOnRecommendedUiTimoutSettings(automan, 7000, 0);
PollingCheck.waitFor(() -> sameRecommendedTimeout(7000, 2000));
turnOnRecommendedUiTimoutSettings(automan, 0, 4000);
PollingCheck.waitFor(() -> sameRecommendedTimeout(6000, 4000));
turnOnRecommendedUiTimoutSettings(automan, 9000, 8000);
PollingCheck.waitFor(() -> sameRecommendedTimeout(9000, 8000));
turnOffRecommendedUiTimoutSettings(automan);
PollingCheck.waitFor(() -> sameRecommendedTimeout(6000, 2000));
assertEquals("Should return original timeout", 3000,
mAccessibilityManager.getRecommendedTimeoutMillis(3000,
AccessibilityManager.FLAG_CONTENT_ICONS));
assertEquals("Should return original timeout", 7000,
mAccessibilityManager.getRecommendedTimeoutMillis(7000,
AccessibilityManager.FLAG_CONTENT_CONTROLS));
} finally {
automan.destroy();
}
}
private void checkServiceEnabled(Object waitObject, AccessibilityManager manager,
AtomicBoolean serviceEnabled, String serviceName) {
synchronized (waitObject) {
List<AccessibilityServiceInfo> infos = manager.getEnabledAccessibilityServiceList(
AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
for (AccessibilityServiceInfo info : infos) {
final String serviceId = info.getId();
if (serviceId.endsWith(serviceName)) {
serviceEnabled.set(true);
waitObject.notifyAll();
}
}
}
}
private void waitForAtomicBooleanBecomes(AtomicBoolean atomicBoolean,
boolean expectedValue, Object waitObject, String condition) {
long timeoutTime = System.currentTimeMillis() + TIMEOUT_SERVICE_ENABLE;
TestUtils.waitOn(waitObject, () -> atomicBoolean.get() == expectedValue, timeoutTime,
condition);
}
private void waitForAccessibilityEnabled() throws InterruptedException {
final Object waitObject = new Object();
AccessibilityStateChangeListener listener = (boolean b) -> {
synchronized (waitObject) {
waitObject.notifyAll();
}
};
mAccessibilityManager.addAccessibilityStateChangeListener(listener);
long timeoutTime =
System.currentTimeMillis() + TIMEOUT_SERVICE_ENABLE;
synchronized (waitObject) {
while (!mAccessibilityManager.isEnabled()
&& (System.currentTimeMillis() < timeoutTime)) {
waitObject.wait(timeoutTime - System.currentTimeMillis());
}
}
mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
assertTrue("Timed out enabling accessibility", mAccessibilityManager.isEnabled());
}
private void turnOffRecommendedUiTimoutSettings(UiAutomation automan) {
putSecureSetting(automan, ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, null);
putSecureSetting(automan, ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, null);
}
private void turnOnRecommendedUiTimoutSettings(UiAutomation automan,
int interactiveUiTimeout, int nonInteractiveUiTimeout) {
putSecureSetting(automan, ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
Integer.toString(interactiveUiTimeout));
putSecureSetting(automan, ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
Integer.toString(nonInteractiveUiTimeout));
}
private boolean sameRecommendedTimeout(int interactiveUiTimeout,
int nonInteractiveUiTimeout) {
final int currentInteractiveUiTimeout = mAccessibilityManager
.getRecommendedTimeoutMillis(0, AccessibilityManager.FLAG_CONTENT_CONTROLS);
final int currentNonInteractiveUiTimeout = mAccessibilityManager
.getRecommendedTimeoutMillis(0, AccessibilityManager.FLAG_CONTENT_ICONS);
return (currentInteractiveUiTimeout == interactiveUiTimeout
&& currentNonInteractiveUiTimeout == nonInteractiveUiTimeout);
}
private void putSecureSetting(UiAutomation automan, String name, String value) {
final StringBuilder cmd = new StringBuilder("settings put secure ")
.append(name).append(" ")
.append(value);
try {
SystemUtil.runShellCommand(automan, cmd.toString());
} catch (IOException e) {
fail("Fail to run shell command");
}
}
}