blob: 9783cb8fbe9d5ae271969de7305aa7f9d5864ada [file] [log] [blame]
/*
* Copyright (C) 2016 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 android.app.Instrumentation;
import android.app.UiAutomation;
import android.content.ContentResolver;
import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.provider.Settings;
import android.view.accessibility.AccessibilityManager;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Utility methods for enabling and disabling the services used in this package
*/
public class ServiceControlUtils {
private static final int TIMEOUT_FOR_SERVICE_ENABLE = 10000; // millis; 10s
private static final String SETTING_ENABLE_SPEAKING_AND_VIBRATING_SERVICES =
"android.view.accessibility.cts/.SpeakingAccessibilityService:"
+ "android.view.accessibility.cts/.VibratingAccessibilityService";
private static final String SETTING_ENABLE_MULTIPLE_FEEDBACK_TYPES_SERVICE =
"android.view.accessibility.cts/.SpeakingAndVibratingAccessibilityService";
/**
* Enable {@code SpeakingAccessibilityService} and {@code VibratingAccessibilityService}
*
* @param instrumentation A valid instrumentation
*/
public static void enableSpeakingAndVibratingServices(Instrumentation instrumentation)
throws IOException {
Context context = instrumentation.getContext();
// Get permission to enable accessibility
UiAutomation uiAutomation = instrumentation.getUiAutomation();
// Change the settings to enable the two services
ContentResolver cr = context.getContentResolver();
String alreadyEnabledServices = Settings.Secure.getString(
cr, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
ParcelFileDescriptor fd = uiAutomation.executeShellCommand("settings --user cur put secure "
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES + " "
+ alreadyEnabledServices + ":"
+ SETTING_ENABLE_SPEAKING_AND_VIBRATING_SERVICES);
InputStream in = new FileInputStream(fd.getFileDescriptor());
byte[] buffer = new byte[4096];
while (in.read(buffer) > 0);
uiAutomation.destroy();
// Wait for speaking service to be connected
long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_FOR_SERVICE_ENABLE;
boolean speakingServiceStarted = false;
while (!speakingServiceStarted && (SystemClock.uptimeMillis() < timeoutTimeMillis)) {
synchronized (SpeakingAccessibilityService.sWaitObjectForConnecting) {
if (SpeakingAccessibilityService.sConnectedInstance != null) {
speakingServiceStarted = true;
break;
}
if (!speakingServiceStarted) {
try {
SpeakingAccessibilityService.sWaitObjectForConnecting.wait(
timeoutTimeMillis - SystemClock.uptimeMillis());
} catch (InterruptedException e) {
}
}
}
}
if (!speakingServiceStarted) {
throw new RuntimeException("Speaking accessibility service not starting");
}
// Wait for vibrating service to be connected
while (SystemClock.uptimeMillis() < timeoutTimeMillis) {
synchronized (VibratingAccessibilityService.sWaitObjectForConnecting) {
if (VibratingAccessibilityService.sConnectedInstance != null) {
return;
}
try {
VibratingAccessibilityService.sWaitObjectForConnecting.wait(
timeoutTimeMillis - SystemClock.uptimeMillis());
} catch (InterruptedException e) {
}
}
}
throw new RuntimeException("Vibrating accessibility service not starting");
}
/**
* Enable {@link SpeakingAndVibratingAccessibilityService} for tests requiring a service with
* multiple feedback types
*
* @param instrumentation A valid instrumentation
*/
public static void enableMultipleFeedbackTypesService(Instrumentation instrumentation)
throws IOException {
Context context = instrumentation.getContext();
// Get permission to enable accessibility
UiAutomation uiAutomation = instrumentation.getUiAutomation();
// Change the settings to enable the services
ContentResolver cr = context.getContentResolver();
String alreadyEnabledServices = Settings.Secure.getString(
cr, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
ParcelFileDescriptor fd = uiAutomation.executeShellCommand("settings --user cur put secure "
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES + " "
+ alreadyEnabledServices + ":"
+ SETTING_ENABLE_MULTIPLE_FEEDBACK_TYPES_SERVICE);
InputStream in = new FileInputStream(fd.getFileDescriptor());
byte[] buffer = new byte[4096];
while (in.read(buffer) > 0);
uiAutomation.destroy();
// Wait for the service to be connected
long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_FOR_SERVICE_ENABLE;
boolean multipleFeedbackTypesServiceEnabled = false;
while (!multipleFeedbackTypesServiceEnabled && (SystemClock.uptimeMillis()
< timeoutTimeMillis)) {
synchronized (SpeakingAndVibratingAccessibilityService.sWaitObjectForConnecting) {
if (SpeakingAndVibratingAccessibilityService.sConnectedInstance != null) {
multipleFeedbackTypesServiceEnabled = true;
break;
}
if (!multipleFeedbackTypesServiceEnabled) {
try {
SpeakingAndVibratingAccessibilityService.sWaitObjectForConnecting.wait(
timeoutTimeMillis - SystemClock.uptimeMillis());
} catch (InterruptedException e) {
}
}
}
}
if (!multipleFeedbackTypesServiceEnabled) {
throw new RuntimeException(
"Multiple feedback types accessibility service not starting");
}
}
/**
* Turn off all accessibility services. Assumes permissions to write settings are already
* set, which they are in
* {@link ServiceControlUtils#enableSpeakingAndVibratingServices(Instrumentation)}.
*
* @param instrumentation A valid instrumentation
*/
public static void turnAccessibilityOff(Instrumentation instrumentation) {
if (SpeakingAccessibilityService.sConnectedInstance != null) {
SpeakingAccessibilityService.sConnectedInstance.disableSelf();
SpeakingAccessibilityService.sConnectedInstance = null;
}
if (VibratingAccessibilityService.sConnectedInstance != null) {
VibratingAccessibilityService.sConnectedInstance.disableSelf();
VibratingAccessibilityService.sConnectedInstance = null;
}
if (SpeakingAndVibratingAccessibilityService.sConnectedInstance != null) {
SpeakingAndVibratingAccessibilityService.sConnectedInstance.disableSelf();
SpeakingAndVibratingAccessibilityService.sConnectedInstance = null;
}
final Object waitLockForA11yOff = new Object();
AccessibilityManager manager = (AccessibilityManager) instrumentation
.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
manager.addAccessibilityStateChangeListener(
new AccessibilityManager.AccessibilityStateChangeListener() {
@Override
public void onAccessibilityStateChanged(boolean b) {
synchronized (waitLockForA11yOff) {
waitLockForA11yOff.notifyAll();
}
}
});
long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_FOR_SERVICE_ENABLE;
while (SystemClock.uptimeMillis() < timeoutTimeMillis) {
synchronized (waitLockForA11yOff) {
if (!manager.isEnabled()) {
return;
}
try {
waitLockForA11yOff.wait(timeoutTimeMillis - SystemClock.uptimeMillis());
} catch (InterruptedException e) {
// Ignored; loop again
}
}
}
throw new RuntimeException("Unable to turn accessibility off");
}
}