17add67b949163f981b785a8c23de89d6b17fff93Kevin Jin/*
27add67b949163f981b785a8c23de89d6b17fff93Kevin Jin * Copyright (C) 2013 DroidDriver committers
37add67b949163f981b785a8c23de89d6b17fff93Kevin Jin *
47add67b949163f981b785a8c23de89d6b17fff93Kevin Jin * Licensed under the Apache License, Version 2.0 (the "License");
57add67b949163f981b785a8c23de89d6b17fff93Kevin Jin * you may not use this file except in compliance with the License.
67add67b949163f981b785a8c23de89d6b17fff93Kevin Jin * You may obtain a copy of the License at
77add67b949163f981b785a8c23de89d6b17fff93Kevin Jin *
87add67b949163f981b785a8c23de89d6b17fff93Kevin Jin *      http://www.apache.org/licenses/LICENSE-2.0
97add67b949163f981b785a8c23de89d6b17fff93Kevin Jin *
107add67b949163f981b785a8c23de89d6b17fff93Kevin Jin * Unless required by applicable law or agreed to in writing, software
117add67b949163f981b785a8c23de89d6b17fff93Kevin Jin * distributed under the License is distributed on an "AS IS" BASIS,
127add67b949163f981b785a8c23de89d6b17fff93Kevin Jin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137add67b949163f981b785a8c23de89d6b17fff93Kevin Jin * See the License for the specific language governing permissions and
147add67b949163f981b785a8c23de89d6b17fff93Kevin Jin * limitations under the License.
157add67b949163f981b785a8c23de89d6b17fff93Kevin Jin */
167add67b949163f981b785a8c23de89d6b17fff93Kevin Jin
177add67b949163f981b785a8c23de89d6b17fff93Kevin Jinpackage com.google.android.droiddriver.runner;
187add67b949163f981b785a8c23de89d6b17fff93Kevin Jin
197add67b949163f981b785a8c23de89d6b17fff93Kevin Jinimport android.app.Activity;
200c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jinimport android.os.Build;
217add67b949163f981b785a8c23de89d6b17fff93Kevin Jinimport android.os.Bundle;
227add67b949163f981b785a8c23de89d6b17fff93Kevin Jinimport android.test.AndroidTestRunner;
237add67b949163f981b785a8c23de89d6b17fff93Kevin Jinimport android.test.InstrumentationTestRunner;
240c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jinimport android.test.suitebuilder.TestMethod;
257add67b949163f981b785a8c23de89d6b17fff93Kevin Jinimport android.util.Log;
267add67b949163f981b785a8c23de89d6b17fff93Kevin Jin
270c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jinimport com.android.internal.util.Predicate;
28115eb39036a7a4e500dc94b57975a5693861f654Tony Wickhamimport com.google.android.droiddriver.util.ActivityUtils;
297add67b949163f981b785a8c23de89d6b17fff93Kevin Jinimport com.google.android.droiddriver.util.Logs;
30b18bb64ed9513bedf8222e6915abb5164e9108f9Kevin Jinimport com.google.common.base.Supplier;
310c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jinimport com.google.common.collect.Lists;
327add67b949163f981b785a8c23de89d6b17fff93Kevin Jinimport com.google.common.collect.Sets;
337add67b949163f981b785a8c23de89d6b17fff93Kevin Jin
347add67b949163f981b785a8c23de89d6b17fff93Kevin Jinimport junit.framework.AssertionFailedError;
357add67b949163f981b785a8c23de89d6b17fff93Kevin Jinimport junit.framework.Test;
367add67b949163f981b785a8c23de89d6b17fff93Kevin Jinimport junit.framework.TestListener;
377add67b949163f981b785a8c23de89d6b17fff93Kevin Jin
38df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jinimport java.lang.annotation.Annotation;
397add67b949163f981b785a8c23de89d6b17fff93Kevin Jinimport java.util.Iterator;
400c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jinimport java.util.List;
417add67b949163f981b785a8c23de89d6b17fff93Kevin Jinimport java.util.Set;
427add67b949163f981b785a8c23de89d6b17fff93Kevin Jin
437add67b949163f981b785a8c23de89d6b17fff93Kevin Jin/**
447add67b949163f981b785a8c23de89d6b17fff93Kevin Jin * Adds activity watcher to InstrumentationTestRunner.
457add67b949163f981b785a8c23de89d6b17fff93Kevin Jin */
467add67b949163f981b785a8c23de89d6b17fff93Kevin Jinpublic class TestRunner extends InstrumentationTestRunner {
477add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  private final Set<Activity> activities = Sets.newIdentityHashSet();
487add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  private final AndroidTestRunner androidTestRunner = new AndroidTestRunner();
49b18bb64ed9513bedf8222e6915abb5164e9108f9Kevin Jin  private Activity runningActivity;
507add67b949163f981b785a8c23de89d6b17fff93Kevin Jin
517add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  /**
527add67b949163f981b785a8c23de89d6b17fff93Kevin Jin   * Returns an {@link AndroidTestRunner} that is shared by this and super, such
537add67b949163f981b785a8c23de89d6b17fff93Kevin Jin   * that we can add custom {@link TestListener}s.
547add67b949163f981b785a8c23de89d6b17fff93Kevin Jin   */
557add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  @Override
567add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  protected AndroidTestRunner getAndroidTestRunner() {
577add67b949163f981b785a8c23de89d6b17fff93Kevin Jin    return androidTestRunner;
587add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  }
597add67b949163f981b785a8c23de89d6b17fff93Kevin Jin
607add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  /**
617add67b949163f981b785a8c23de89d6b17fff93Kevin Jin   * {@inheritDoc}
627add67b949163f981b785a8c23de89d6b17fff93Kevin Jin   * <p>
637add67b949163f981b785a8c23de89d6b17fff93Kevin Jin   * Adds a {@link TestListener} that finishes all created activities.
647add67b949163f981b785a8c23de89d6b17fff93Kevin Jin   */
657add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  @Override
667add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  public void onStart() {
677add67b949163f981b785a8c23de89d6b17fff93Kevin Jin    getAndroidTestRunner().addTestListener(new TestListener() {
687add67b949163f981b785a8c23de89d6b17fff93Kevin Jin      @Override
697add67b949163f981b785a8c23de89d6b17fff93Kevin Jin      public void endTest(Test test) {
707add67b949163f981b785a8c23de89d6b17fff93Kevin Jin        runOnMainSync(new Runnable() {
717add67b949163f981b785a8c23de89d6b17fff93Kevin Jin          @Override
727add67b949163f981b785a8c23de89d6b17fff93Kevin Jin          public void run() {
737add67b949163f981b785a8c23de89d6b17fff93Kevin Jin            Iterator<Activity> iterator = activities.iterator();
747add67b949163f981b785a8c23de89d6b17fff93Kevin Jin            while (iterator.hasNext()) {
757add67b949163f981b785a8c23de89d6b17fff93Kevin Jin              Activity activity = iterator.next();
767add67b949163f981b785a8c23de89d6b17fff93Kevin Jin              iterator.remove();
777add67b949163f981b785a8c23de89d6b17fff93Kevin Jin              if (!activity.isFinishing()) {
787add67b949163f981b785a8c23de89d6b17fff93Kevin Jin                try {
796316362de61fca700d7d5a455ad5c0ac9717c365Kevin Jin                  Logs.log(Log.INFO, "Stopping activity: " + activity);
807add67b949163f981b785a8c23de89d6b17fff93Kevin Jin                  activity.finish();
817add67b949163f981b785a8c23de89d6b17fff93Kevin Jin                } catch (RuntimeException e) {
826316362de61fca700d7d5a455ad5c0ac9717c365Kevin Jin                  Logs.log(Log.ERROR, e, "Failed to stop activity");
837add67b949163f981b785a8c23de89d6b17fff93Kevin Jin                }
847add67b949163f981b785a8c23de89d6b17fff93Kevin Jin              }
857add67b949163f981b785a8c23de89d6b17fff93Kevin Jin            }
867add67b949163f981b785a8c23de89d6b17fff93Kevin Jin          }
877add67b949163f981b785a8c23de89d6b17fff93Kevin Jin        });
887add67b949163f981b785a8c23de89d6b17fff93Kevin Jin      }
897add67b949163f981b785a8c23de89d6b17fff93Kevin Jin
907add67b949163f981b785a8c23de89d6b17fff93Kevin Jin      @Override
917add67b949163f981b785a8c23de89d6b17fff93Kevin Jin      public void addError(Test arg0, Throwable arg1) {}
927add67b949163f981b785a8c23de89d6b17fff93Kevin Jin
937add67b949163f981b785a8c23de89d6b17fff93Kevin Jin      @Override
947add67b949163f981b785a8c23de89d6b17fff93Kevin Jin      public void addFailure(Test arg0, AssertionFailedError arg1) {}
957add67b949163f981b785a8c23de89d6b17fff93Kevin Jin
967add67b949163f981b785a8c23de89d6b17fff93Kevin Jin      @Override
977add67b949163f981b785a8c23de89d6b17fff93Kevin Jin      public void startTest(Test arg0) {}
987add67b949163f981b785a8c23de89d6b17fff93Kevin Jin    });
99b18bb64ed9513bedf8222e6915abb5164e9108f9Kevin Jin
100b18bb64ed9513bedf8222e6915abb5164e9108f9Kevin Jin    ActivityUtils.setRunningActivitySupplier(new Supplier<Activity>() {
101b18bb64ed9513bedf8222e6915abb5164e9108f9Kevin Jin      @Override
102b18bb64ed9513bedf8222e6915abb5164e9108f9Kevin Jin      public Activity get() {
103b18bb64ed9513bedf8222e6915abb5164e9108f9Kevin Jin        return runningActivity;
104b18bb64ed9513bedf8222e6915abb5164e9108f9Kevin Jin      }
105b18bb64ed9513bedf8222e6915abb5164e9108f9Kevin Jin    });
106b18bb64ed9513bedf8222e6915abb5164e9108f9Kevin Jin
1077add67b949163f981b785a8c23de89d6b17fff93Kevin Jin    super.onStart();
1087add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  }
1097add67b949163f981b785a8c23de89d6b17fff93Kevin Jin
1100c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jin  // Overrides InstrumentationTestRunner
1110c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jin  List<Predicate<TestMethod>> getBuilderRequirements() {
1120c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jin    List<Predicate<TestMethod>> requirements = Lists.newArrayList();
1130c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jin    requirements.add(new Predicate<TestMethod>() {
1140c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jin      @Override
1150c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jin      public boolean apply(TestMethod arg0) {
116df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin        MinSdkVersion minSdkVersion = getAnnotation(arg0, MinSdkVersion.class);
117df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin        if (minSdkVersion != null && minSdkVersion.value() > Build.VERSION.SDK_INT) {
118df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin          Logs.logfmt(Log.INFO, "filtered %s#%s: MinSdkVersion=%d", arg0.getEnclosingClassname(),
119df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin              arg0.getName(), minSdkVersion.value());
120df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin          return false;
121df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin        }
122df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin
123df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin        UseUiAutomation useUiAutomation = getAnnotation(arg0, UseUiAutomation.class);
124df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin        if (useUiAutomation != null && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
125df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin          Logs.logfmt(Log.INFO,
126df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin              "filtered %s#%s: Has @UseUiAutomation, but ro.build.version.sdk=%d",
127df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin              arg0.getEnclosingClassname(), arg0.getName(), Build.VERSION.SDK_INT);
128df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin          return false;
1290c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jin        }
130df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin        return true;
131df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin      }
132df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin
133df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin      private <T extends Annotation> T getAnnotation(TestMethod testMethod, Class<T> clazz) {
134df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin        T annotation = testMethod.getAnnotation(clazz);
135df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin        if (annotation == null) {
136df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin          annotation = testMethod.getEnclosingClass().getAnnotation(clazz);
1370c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jin        }
138df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin        return annotation;
1390c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jin      }
1400c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jin    });
1410c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jin    return requirements;
1420c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jin  }
1430c2c0d1f1d7e1198a4e513f8b8ac2149518844abKevin Jin
1447add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  @Override
1457add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  public void callActivityOnDestroy(Activity activity) {
1467add67b949163f981b785a8c23de89d6b17fff93Kevin Jin    super.callActivityOnDestroy(activity);
1477add67b949163f981b785a8c23de89d6b17fff93Kevin Jin    activities.remove(activity);
1487add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  }
1497add67b949163f981b785a8c23de89d6b17fff93Kevin Jin
1507add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  @Override
1517add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  public void callActivityOnCreate(Activity activity, Bundle bundle) {
1527add67b949163f981b785a8c23de89d6b17fff93Kevin Jin    super.callActivityOnCreate(activity, bundle);
1537add67b949163f981b785a8c23de89d6b17fff93Kevin Jin    activities.add(activity);
1547add67b949163f981b785a8c23de89d6b17fff93Kevin Jin  }
155115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham
156115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham  @Override
157115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham  public void callActivityOnResume(Activity activity) {
158115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham    super.callActivityOnResume(activity);
159b18bb64ed9513bedf8222e6915abb5164e9108f9Kevin Jin    runningActivity = activity;
160115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham  }
161115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham
162115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham  @Override
163115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham  public void callActivityOnPause(Activity activity) {
164115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham    super.callActivityOnPause(activity);
165115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham    if (activity == ActivityUtils.getRunningActivity()) {
166b18bb64ed9513bedf8222e6915abb5164e9108f9Kevin Jin      runningActivity = null;
167115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham    }
168115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham  }
1697add67b949163f981b785a8c23de89d6b17fff93Kevin Jin}
170