Last active
September 2, 2018 12:14
-
-
Save patrickhammond/19e584b90d7aae20f8f4 to your computer and use it in GitHub Desktop.
Revisions
-
Patrick Hammond revised this gist
Apr 13, 2016 . 1 changed file with 7 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -45,8 +45,8 @@ public class EspressoTestRule<T extends Activity> extends ActivityTestRule<T> { private static final float ANIMATION_DISABLED = 0.0f; private static final float ANIMATION_DEFAULT = 1.0f; // Giving the device a full second to turn the screen on. This should be a one time hit. private static final long SCREEN_ON_ATTEMPT_DELAY = 1000; private static final int MAX_SCREEN_ON_ATTEMPTS = 20; public interface UIRunner { @@ -83,7 +83,7 @@ protected void afterActivityLaunched() { PowerManager powerManager = (PowerManager) activity.getSystemService(Context.POWER_SERVICE); int count = 0; while (!powerManager.isScreenOn() && count < MAX_SCREEN_ON_ATTEMPTS) { ui(new UIRunner() { @Override public void run() { @@ -120,16 +120,15 @@ public void run() { // Inspired from https://gist.github.com/JakeWharton/f50f3b4d87e57d8e96e9 @SuppressWarnings("deprecation") private void riseAndShine(Activity activity) { KeyguardManager keyguardManager = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE); KeyguardLock keyguardLock = keyguardManager.newKeyguardLock(activity.getLocalClassName()); keyguardLock.disableKeyguard(); activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); PowerManager powerManager = (PowerManager) activity.getSystemService(Context.POWER_SERVICE); WakeLock lock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "wakeup!"); lock.acquire(); lock.release(); @@ -139,15 +138,15 @@ private void disableAllAnimations() { if (getAnimationPermissionStatus() == PackageManager.PERMISSION_GRANTED) { setSystemAnimationsScale(ANIMATION_DISABLED); } else { Log.e(TAG, "Not granted permission to change animation scale."); } } private void enableAllAnimations() { if (getAnimationPermissionStatus() == PackageManager.PERMISSION_GRANTED) { setSystemAnimationsScale(ANIMATION_DEFAULT); } else { Log.e(TAG, "Not granted permission to change animation scale."); } } -
Patrick Hammond revised this gist
Apr 11, 2016 . 1 changed file with 2 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -45,8 +45,9 @@ public class EspressoTestRule<T extends Activity> extends ActivityTestRule<T> { private static final float ANIMATION_DISABLED = 0.0f; private static final float ANIMATION_DEFAULT = 1.0f; // This delay is kind of a sweet spot to ensure rise and shine has a chance to work private static final long SCREEN_ON_ATTEMPT_DELAY = 250; private static final int MAX_SCREEN_ON_ATTEMPTS = 20; public interface UIRunner { void run(); -
Patrick Hammond revised this gist
Apr 8, 2016 . 1 changed file with 6 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -45,6 +45,9 @@ public class EspressoTestRule<T extends Activity> extends ActivityTestRule<T> { private static final float ANIMATION_DISABLED = 0.0f; private static final float ANIMATION_DEFAULT = 1.0f; private static final int MAX_SCREEN_ON_ATTEMPTS = 20; private static final long SCREEN_ON_ATTEMPT_DELAY = 100; public interface UIRunner { void run(); } @@ -79,7 +82,7 @@ protected void afterActivityLaunched() { PowerManager powerManager = (PowerManager) activity.getSystemService(Context.POWER_SERVICE); int count = 0; while (count == 0 || (!powerManager.isScreenOn() && count < MAX_SCREEN_ON_ATTEMPTS)) { ui(new UIRunner() { @Override public void run() { @@ -88,14 +91,14 @@ public void run() { }); try { Thread.sleep(SCREEN_ON_ATTEMPT_DELAY); } catch (InterruptedException ex) { Log.e(TAG, "Couldn't sleep the test thread after trying to turn the screen on", ex); } count++; } if (count >= MAX_SCREEN_ON_ATTEMPTS) { Log.e(TAG, "Giving up trying to turn the screen on"); } } -
Patrick Hammond revised this gist
Apr 8, 2016 . 1 changed file with 2 additions and 5 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,7 @@ import android.app.Activity; import android.app.Instrumentation; import android.app.KeyguardManager; import android.app.KeyguardManager.KeyguardLock; import android.content.Context; import android.content.pm.PackageManager; import android.os.IBinder; @@ -116,7 +117,7 @@ public void run() { @SuppressWarnings("deprecation") private void riseAndShine(Activity activity) { KeyguardManager keyguardManager = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE); KeyguardLock keyguardLock = keyguardManager.newKeyguardLock(activity.getLocalClassName()); keyguardLock.disableKeyguard(); activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); @@ -128,10 +129,6 @@ private void riseAndShine(Activity activity) { lock.acquire(); lock.release(); } private void disableAllAnimations() { -
Patrick Hammond revised this gist
Apr 8, 2016 . 1 changed file with 28 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,7 +1,6 @@ import android.app.Activity; import android.app.Instrumentation; import android.app.KeyguardManager; import android.content.Context; import android.content.pm.PackageManager; import android.os.IBinder; @@ -75,12 +74,29 @@ public Statement apply(Statement base, Description description) { @Override protected void afterActivityLaunched() { super.afterActivityLaunched(); final Activity activity = getActivity(); PowerManager powerManager = (PowerManager) activity.getSystemService(Context.POWER_SERVICE); int count = 0; while (count == 0 || (!powerManager.isScreenOn() && count < 10)) { ui(new UIRunner() { @Override public void run() { riseAndShine(activity); } }); try { Thread.sleep(100); } catch (InterruptedException ex) { Log.e(TAG, "Couldn't sleep the test thread after trying to turn the screen on", ex); } count++; } if (count >= 10) { Log.e(TAG, "Giving up trying to turn the screen on"); } } public void ui(final UIRunner runner) { @@ -100,7 +116,7 @@ public void run() { @SuppressWarnings("deprecation") private void riseAndShine(Activity activity) { KeyguardManager keyguardManager = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE); KeyguardManager.KeyguardLock keyguardLock = keyguardManager.newKeyguardLock(activity.getLocalClassName()); keyguardLock.disableKeyguard(); activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); @@ -112,6 +128,10 @@ private void riseAndShine(Activity activity) { lock.acquire(); lock.release(); if (!powerManager.isScreenOn()) { } } private void disableAllAnimations() { @@ -233,4 +253,4 @@ public static Set<Activity> getActivitiesInStages(Stage... stages) { } return activities; } } -
Patrick Hammond created this gist
May 14, 2015 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,236 @@ import android.app.Activity; import android.app.Instrumentation; import android.app.KeyguardManager; import android.app.KeyguardManager.KeyguardLock; import android.content.Context; import android.content.pm.PackageManager; import android.os.IBinder; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.support.test.InstrumentationRegistry; import android.support.test.rule.ActivityTestRule; import android.support.test.runner.lifecycle.ActivityLifecycleMonitor; import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; import android.support.test.runner.lifecycle.Stage; import android.util.Log; import android.view.WindowManager; import com.google.common.base.Throwables; import com.google.common.collect.Sets; import org.junit.runner.Description; import org.junit.runners.model.Statement; import java.lang.reflect.Method; import java.util.Collection; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicReference; /** * Make sure this gets added to the manifest of the application under test (typically a manifest in the debug variant). * <code> <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"/> </code> * * @param <T> */ public class EspressoTestRule<T extends Activity> extends ActivityTestRule<T> { private static final String TAG = EspressoTestRule.class.getSimpleName(); private static final String ANIMATION_PERMISSION = "android.permission.SET_ANIMATION_SCALE"; private static final float ANIMATION_DISABLED = 0.0f; private static final float ANIMATION_DEFAULT = 1.0f; public interface UIRunner { void run(); } public EspressoTestRule(Class<T> activityClass) { super(activityClass); } public EspressoTestRule(Class<T> activityClass, boolean initialTouchMode) { super(activityClass, initialTouchMode); } public EspressoTestRule(Class<T> activityClass, boolean initialTouchMode, boolean launchActivity) { super(activityClass, initialTouchMode, launchActivity); } @Override public Statement apply(Statement base, Description description) { try { disableAllAnimations(); return super.apply(base, description); } finally { enableAllAnimations(); closeAllActivities(); } } @Override protected void afterActivityLaunched() { super.afterActivityLaunched(); ui(new UIRunner() { @Override public void run() { riseAndShine(getActivity()); } }); } public void ui(final UIRunner runner) { try { runOnUiThread(new Runnable() { @Override public void run() { runner.run(); } }); } catch (Throwable throwable) { throw new RuntimeException(throwable); } } // Inspired from https://gist.github.com/JakeWharton/f50f3b4d87e57d8e96e9 @SuppressWarnings("deprecation") private void riseAndShine(Activity activity) { KeyguardManager keyguardManager = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE); KeyguardLock keyguardLock = keyguardManager.newKeyguardLock(activity.getLocalClassName()); keyguardLock.disableKeyguard(); activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); PowerManager powerManager = (PowerManager) activity.getSystemService(Context.POWER_SERVICE); WakeLock lock = powerManager.newWakeLock( PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "wakeup!"); lock.acquire(); lock.release(); } private void disableAllAnimations() { if (getAnimationPermissionStatus() == PackageManager.PERMISSION_GRANTED) { setSystemAnimationsScale(ANIMATION_DISABLED); } else { Log.w(TAG, "Not granted permission to change animation scale."); } } private void enableAllAnimations() { if (getAnimationPermissionStatus() == PackageManager.PERMISSION_GRANTED) { setSystemAnimationsScale(ANIMATION_DEFAULT); } else { Log.w(TAG, "Not granted permission to change animation scale."); } } private int getAnimationPermissionStatus() { Context context = InstrumentationRegistry.getTargetContext(); return context.checkCallingOrSelfPermission(ANIMATION_PERMISSION); } // https://code.google.com/p/android-test-kit/wiki/DisablingAnimations 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 ex) { Log.e(TAG, "Could not use reflection to change animation scale to: " + animationScale, ex); } } // See https://code.google.com/p/android-test-kit/issues/detail?id=66 private void closeAllActivities() { try { Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); closeAllActivities(instrumentation); } catch (Exception ex) { Log.e(TAG, "Could not use close all activities", ex); } } private void closeAllActivities(Instrumentation instrumentation) throws Exception { final int NUMBER_OF_RETRIES = 100; int i = 0; while (closeActivity(instrumentation)) { if (i++ > NUMBER_OF_RETRIES) { throw new AssertionError("Limit of retries excesses"); } Thread.sleep(200); } } private boolean closeActivity(Instrumentation instrumentation) throws Exception { final Boolean activityClosed = callOnMainSync(instrumentation, new Callable<Boolean>() { @Override public Boolean call() throws Exception { final Set<Activity> activities = getActivitiesInStages(Stage.RESUMED, Stage.STARTED, Stage.PAUSED, Stage.STOPPED, Stage.CREATED); activities.removeAll(getActivitiesInStages(Stage.DESTROYED)); if (activities.size() > 0) { final Activity activity = activities.iterator().next(); activity.finish(); return true; } else { return false; } } }); if (activityClosed) { instrumentation.waitForIdleSync(); } return activityClosed; } private <X> X callOnMainSync(Instrumentation instrumentation, final Callable<X> callable) throws Exception { final AtomicReference<X> retAtomic = new AtomicReference<>(); final AtomicReference<Throwable> exceptionAtomic = new AtomicReference<>(); instrumentation.runOnMainSync(new Runnable() { @Override public void run() { try { retAtomic.set(callable.call()); } catch (Throwable e) { exceptionAtomic.set(e); } } }); final Throwable exception = exceptionAtomic.get(); if (exception != null) { Throwables.propagateIfInstanceOf(exception, Exception.class); Throwables.propagate(exception); } return retAtomic.get(); } public static Set<Activity> getActivitiesInStages(Stage... stages) { final Set<Activity> activities = Sets.newHashSet(); final ActivityLifecycleMonitor instance = ActivityLifecycleMonitorRegistry.getInstance(); for (Stage stage : stages) { final Collection<Activity> activitiesInStage = instance.getActivitiesInStage(stage); if (activitiesInStage != null) { activities.addAll(activitiesInStage); } } return activities; } } This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,26 @@ import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.LargeTest; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import static android.support.test.espresso.Espresso.*; import static android.support.test.espresso.assertion.ViewAssertions.*; import static android.support.test.espresso.matcher.ViewMatchers.*; import static org.hamcrest.Matchers.is; @RunWith(AndroidJUnit4.class) @LargeTest public class SampleTest { @Rule public EspressoTestRule<SampleActivity> activityRule = new EspressoTestRule<>(SampleActivity.class); @Test public void testInitialDisplay() { onView(withId(R.id.progress)).check(matches(withEffectiveVisibility(Visibility.VISIBLE))); onView(withId(R.id.content)).check(matches(withEffectiveVisibility(Visibility.INVISIBLE))); onView(withId(R.id.header)).check(matches(withText("Sample Header"))); } }