1 /* 2 * Copyright (C) 2013 DroidDriver committers 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.android.droiddriver.runner; 18 19 import android.app.Activity; 20 import android.os.Build; 21 import android.os.Bundle; 22 import android.test.AndroidTestRunner; 23 import android.test.InstrumentationTestRunner; 24 import android.test.suitebuilder.TestMethod; 25 import android.util.Log; 26 27 import com.android.internal.util.Predicate; 28 import com.google.android.droiddriver.util.ActivityUtils; 29 import com.google.android.droiddriver.util.Logs; 30 import com.google.common.base.Supplier; 31 import com.google.common.collect.Lists; 32 import com.google.common.collect.Sets; 33 34 import junit.framework.AssertionFailedError; 35 import junit.framework.Test; 36 import junit.framework.TestListener; 37 38 import java.lang.annotation.Annotation; 39 import java.util.Iterator; 40 import java.util.List; 41 import java.util.Set; 42 43 /** 44 * Adds activity watcher to InstrumentationTestRunner. 45 */ 46 public class TestRunner extends InstrumentationTestRunner { 47 private final Set<Activity> activities = Sets.newIdentityHashSet(); 48 private final AndroidTestRunner androidTestRunner = new AndroidTestRunner(); 49 private Activity runningActivity; 50 51 /** 52 * Returns an {@link AndroidTestRunner} that is shared by this and super, such 53 * that we can add custom {@link TestListener}s. 54 */ 55 @Override 56 protected AndroidTestRunner getAndroidTestRunner() { 57 return androidTestRunner; 58 } 59 60 /** 61 * {@inheritDoc} 62 * <p> 63 * Adds a {@link TestListener} that finishes all created activities. 64 */ 65 @Override 66 public void onStart() { 67 getAndroidTestRunner().addTestListener(new TestListener() { 68 @Override 69 public void endTest(Test test) { 70 runOnMainSync(new Runnable() { 71 @Override 72 public void run() { 73 Iterator<Activity> iterator = activities.iterator(); 74 while (iterator.hasNext()) { 75 Activity activity = iterator.next(); 76 iterator.remove(); 77 if (!activity.isFinishing()) { 78 try { 79 Logs.log(Log.INFO, "Stopping activity: " + activity); 80 activity.finish(); 81 } catch (RuntimeException e) { 82 Logs.log(Log.ERROR, e, "Failed to stop activity"); 83 } 84 } 85 } 86 } 87 }); 88 } 89 90 @Override 91 public void addError(Test arg0, Throwable arg1) {} 92 93 @Override 94 public void addFailure(Test arg0, AssertionFailedError arg1) {} 95 96 @Override 97 public void startTest(Test arg0) {} 98 }); 99 100 ActivityUtils.setRunningActivitySupplier(new Supplier<Activity>() { 101 @Override 102 public Activity get() { 103 return runningActivity; 104 } 105 }); 106 107 super.onStart(); 108 } 109 110 // Overrides InstrumentationTestRunner 111 List<Predicate<TestMethod>> getBuilderRequirements() { 112 List<Predicate<TestMethod>> requirements = Lists.newArrayList(); 113 requirements.add(new Predicate<TestMethod>() { 114 @Override 115 public boolean apply(TestMethod arg0) { 116 MinSdkVersion minSdkVersion = getAnnotation(arg0, MinSdkVersion.class); 117 if (minSdkVersion != null && minSdkVersion.value() > Build.VERSION.SDK_INT) { 118 Logs.logfmt(Log.INFO, "filtered %s#%s: MinSdkVersion=%d", arg0.getEnclosingClassname(), 119 arg0.getName(), minSdkVersion.value()); 120 return false; 121 } 122 123 UseUiAutomation useUiAutomation = getAnnotation(arg0, UseUiAutomation.class); 124 if (useUiAutomation != null && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { 125 Logs.logfmt(Log.INFO, 126 "filtered %s#%s: Has @UseUiAutomation, but ro.build.version.sdk=%d", 127 arg0.getEnclosingClassname(), arg0.getName(), Build.VERSION.SDK_INT); 128 return false; 129 } 130 return true; 131 } 132 133 private <T extends Annotation> T getAnnotation(TestMethod testMethod, Class<T> clazz) { 134 T annotation = testMethod.getAnnotation(clazz); 135 if (annotation == null) { 136 annotation = testMethod.getEnclosingClass().getAnnotation(clazz); 137 } 138 return annotation; 139 } 140 }); 141 return requirements; 142 } 143 144 @Override 145 public void callActivityOnDestroy(Activity activity) { 146 super.callActivityOnDestroy(activity); 147 activities.remove(activity); 148 } 149 150 @Override 151 public void callActivityOnCreate(Activity activity, Bundle bundle) { 152 super.callActivityOnCreate(activity, bundle); 153 activities.add(activity); 154 } 155 156 @Override 157 public void callActivityOnResume(Activity activity) { 158 super.callActivityOnResume(activity); 159 runningActivity = activity; 160 } 161 162 @Override 163 public void callActivityOnPause(Activity activity) { 164 super.callActivityOnPause(activity); 165 if (activity == ActivityUtils.getRunningActivity()) { 166 runningActivity = null; 167 } 168 } 169 } 170