-
-
Save pt2121/e6d0e071e3b3d0835407 to your computer and use it in GitHub Desktop.
Disable animations for Espresso tests - run with `gradle cATDD`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<manifest | |
xmlns:android="http://schemas.android.com/apk/res/android" | |
package="com.novoda.espresso"> | |
<!-- For espresso testing purposes, this is removed in live builds, but not in dev builds --> | |
<uses-permission android:name="android.permission.SET_ANIMATION_SCALE" /> | |
<!-- ... --> | |
</manifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apply plugin: 'android' | |
android { | |
// ... | |
productFlavors { | |
dev { | |
// The one for development/testing | |
} | |
live { | |
// The flavour for releasing | |
} | |
} | |
} | |
// ... | |
task grantAnimationPermission(type: Exec, dependsOn: 'installDevDebug') { // or install{productFlavour}{buildType} | |
commandLine "adb shell pm grant $android.defaultConfig.packageName android.permission.SET_ANIMATION_SCALE".split(' ') | |
} | |
tasks.whenTaskAdded { task -> | |
if (task.name.startsWith('connectedAndroidTest')) { | |
task.dependsOn grantAnimationPermission | |
} | |
} | |
def copyAndReplaceText(source, dest, Closure replaceText) { | |
dest.write(replaceText(source.text)) | |
} | |
// Override Data in Manifest - This can be done using different Manifest files for each flavor, this way there's no need to modify the manifest | |
android.applicationVariants.all { variant -> | |
if (variant.name.startsWith('dev')) { // Where dev is the one you'll use to run Espresso tests | |
System.out.println("Not removing the SET_ANIMATION_SCALE permission for $variant.name") | |
return | |
} | |
System.out.println("Removing the SET_ANIMATION_SCALE permission for $variant.name") | |
variant.processManifest.doLast { | |
copyAndReplaceText(manifestOutputFile, manifestOutputFile) { | |
def replaced = it.replace('<uses-permission android:name="android.permission.SET_ANIMATION_SCALE"/>', ''); | |
if (replaced.contains('SET_ANIMATION_SCALE')) { | |
// For security, imagine an extra space is added before closing tag, then the replace would fail - TODO use regex | |
throw new RuntimeException("Don't ship with this permission! android.permission.SET_ANIMATION_SCALE") | |
} | |
replaced | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MyInstrumentationTestCase extends ActivityInstrumentationTestCase2<MyActivity> { | |
private SystemAnimations systemAnimations; | |
public MyInstrumentationTestCase() { | |
super(MyActivity.class); | |
} | |
@Override | |
protected void setUp() throws Exception { | |
super.setUp(); | |
systemAnimations = new SystemAnimations(getInstrumentation().getContext()); | |
systemAnimations.disableAll(); | |
getActivity(); | |
} | |
@Override | |
protected void tearDown() throws Exception { | |
super.tearDown(); | |
systemAnimations.enableAll(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SystemAnimations { | |
private static final String ANIMATION_PERMISSION = "android.permission.SET_ANIMATION_SCALE"; | |
private static final float DISABLED = 0.0f; | |
private static final float DEFAULT = 1.0f; | |
private final Context context; | |
SystemAnimations(Context context) { | |
this.context = context; | |
} | |
void disableAll() { | |
int permStatus = context.checkCallingOrSelfPermission(ANIMATION_PERMISSION); | |
if (permStatus == PackageManager.PERMISSION_GRANTED) { | |
setSystemAnimationsScale(DISABLED); | |
} | |
} | |
void enableAll() { | |
int permStatus = context.checkCallingOrSelfPermission(ANIMATION_PERMISSION); | |
if (permStatus == PackageManager.PERMISSION_GRANTED) { | |
setSystemAnimationsScale(DEFAULT); | |
} | |
} | |
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 + " :'("); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment