Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Android - AndroidJUnitRunner that disable animations, disable screen lock and wake processor all the time to avoid Tests to fail because of test device setup. Note that my test buildType is mock to have a manifest just for tests (dont want to ship an app with SET_ANIMATION_SCALE permissions...).
<?xml version="1.0" encoding="utf-8"?>
<!-- This file should be outside of release manifest (in this case app/src/mock/Manifest.xml -->
<!-- For espresso testing purposes, this is removed in live builds, but not in dev builds -->
<uses-permission android:name="android.permission.SET_ANIMATION_SCALE" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
def appId = "com.example.tests"
def appVersionName = "1.0"
def appVersionCode = 2
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId appId
minSdkVersion 15
targetSdkVersion 23
versionCode appVersionCode
versionName appVersionName
multiDexEnabled = true // Avoid Bug with java 1.7
testInstrumentationRunner "com.example.tests.PreparerTestRunner"
//testInstrumentationRunner ""
testBuildType "mock"
dependencies {
androidTestCompile ''
androidTestCompile ''
androidTestCompile ''
androidTestCompile ''
androidTestCompile('') {
// this library uses the newest app compat v22 but the espresso contrib still v21.
// you have to specifically exclude the older versions of the contrib library or
// there will be some conflicts
exclude group: '', module: 'appcompat'
exclude group: '', module: 'support-v4'
exclude module: 'recyclerview-v7'
androidTestCompile 'junit:junit:4.12'
androidTestCompile 'com.squareup.retrofit:retrofit-mock:1.9.0'
androidTestCompile 'com.squareup.assertj:assertj-android:1.1.0'
androidTestCompile 'com.squareup.spoon:spoon-client:1.2.0'
// Grant animation permissions to avoid test failure because of ui sync.
task grantAnimationPermissions(type: Exec, dependsOn: 'installMock') {
group = 'test'
description = 'Grant permissions for testing.'
def absolutePath = file('..') // Get project absolute path
commandLine "$absolutePath/ $appId".split(" ")
// Source:
afterEvaluate {
// When launching individual tests from Android Studio, it seems that only the assemble tasks
// get called directly, not the install* versions
tasks.each { task ->
if ('assembleMockAndroidTest')) {
task.dependsOn grantAnimationPermissions
import android.Manifest;
import android.content.Context;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.util.Log;
import java.lang.reflect.Method;
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.Context.POWER_SERVICE;
import static android.os.PowerManager.ACQUIRE_CAUSES_WAKEUP;
import static android.os.PowerManager.FULL_WAKE_LOCK;
import static android.os.PowerManager.ON_AFTER_RELEASE;
import static;
* Tests can fail for other reasons than code, it´ because of the animations and espresso sync and
* emulator state (screen off or locked)
* Before all the tests prepare the device to run tests and avoid these problems.
* - Disable animations
* - Disable keyguard lock
* - Set it to be awake all the time (dont let the processor sleep)
* @see <a href="u2020 open source app by Jake Wharton"></a>
* @see <a href="Daj gist"></a>
* @see <a href="Android-test-kit Disabling Animations"></a>
public final class PreparerTestRunner extends AndroidJUnitRunner {
public void onStart() {
runOnMainSync(() -> {
Context app = getTargetContext().getApplicationContext();
String name = PreparerTestRunner.class.getSimpleName();
// Unlock the device so that the tests can input keystrokes.
KeyguardManager keyguard = (KeyguardManager) app.getSystemService(KEYGUARD_SERVICE);
// Wake up the screen.
PowerManager power = (PowerManager) app.getSystemService(POWER_SERVICE);
public void finish(int resultCode, Bundle results) {
super.finish(resultCode, results);
//<editor-fold desc="Animations">
void disableAnimations(Context context) {
int permStatus = context.checkCallingOrSelfPermission(Manifest.permission.SET_ANIMATION_SCALE);
if (permStatus == PackageManager.PERMISSION_GRANTED) {
void enableAnimations(Context context) {
int permStatus = context.checkCallingOrSelfPermission(Manifest.permission.SET_ANIMATION_SCALE);
if (permStatus == PackageManager.PERMISSION_GRANTED) {
private void setSystemAnimationsScale(float animationScale) {
try {
Class<?> windowManagerStubClazz = Class.forName("android.view.IWindowManager$Stub");
Method asInterface = windowManagerStubClazz.getDeclaredMethod("asInterface", IBinder.class);
Class<?> serviceManagerClazz = Class.forName("android.os.ServiceManager");
Method getService = serviceManagerClazz.getDeclaredMethod("getService", String.class);
Class<?> windowManagerClazz = Class.forName("android.view.IWindowManager");
Method setAnimationScales = windowManagerClazz.getDeclaredMethod("setAnimationScales", float[].class);
Method getAnimationScales = windowManagerClazz.getDeclaredMethod("getAnimationScales");
IBinder windowManagerBinder = (IBinder) getService.invoke(null, "window");
Object windowManagerObj = asInterface.invoke(null, windowManagerBinder);
float[] currentScales = (float[]) getAnimationScales.invoke(windowManagerObj);
for (int i = 0; i < currentScales.length; i++) {
currentScales[i] = animationScale;
setAnimationScales.invoke(windowManagerObj, new Object[]{currentScales});
} catch (Exception e) {
Log.e("SystemAnimations", "Could not change animation scale to " + animationScale + " :'(");
# source
# argument: apk package
# Set permission android.permission.SET_ANIMATION_SCALE for each device.
# ex: sh <package>
if [ "$#" = 0 ]; then
echo "No parameters found, run with sh <package>"
exit 0
# get all the devices
devices=$($adb devices | grep -v 'List of devices' | cut -f1 | grep '.')
for device in $devices; do
echo "Setting permissions to device" $device "for package" $package
$adb -s $device shell pm grant $package android.permission.SET_ANIMATION_SCALE
Copy link

danielgomezrico commented Oct 25, 2017

@jamespullar it worked for you? it is not working for me

Copy link

ahasbini commented Jan 4, 2018

@jamespullar, same as @caipivara, animationsDisabled doesn't do anything, checkout this comment: link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment