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 io.appium.droiddriver.util; 18 19 import android.app.Activity; 20 import android.os.Looper; 21 import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; 22 import android.support.test.runner.lifecycle.Stage; 23 import android.util.Log; 24 import java.util.Iterator; 25 import java.util.concurrent.Callable; 26 27 /** Static helper methods for retrieving activities. */ 28 public class ActivityUtils { 29 private static final Callable<Activity> GET_RUNNING_ACTIVITY = 30 new Callable<Activity>() { 31 @Override 32 public Activity call() { 33 Iterator<Activity> activityIterator = 34 ActivityLifecycleMonitorRegistry.getInstance() 35 .getActivitiesInStage(Stage.RESUMED) 36 .iterator(); 37 return activityIterator.hasNext() ? activityIterator.next() : null; 38 } 39 }; 40 private static Supplier<Activity> runningActivitySupplier = 41 new Supplier<Activity>() { 42 @Override 43 public Activity get() { 44 try { 45 // If this is called on main (UI) thread, don't call runOnMainSync 46 if (Looper.myLooper() == Looper.getMainLooper()) { 47 return GET_RUNNING_ACTIVITY.call(); 48 } 49 50 return InstrumentationUtils.runOnMainSyncWithTimeout(GET_RUNNING_ACTIVITY); 51 } catch (Exception e) { 52 Logs.log(Log.WARN, e); 53 return null; 54 } 55 } 56 }; 57 58 /** 59 * Sets the Supplier for the running (a.k.a. resumed or foreground) activity. If a custom runner 60 * is used, this method must be called appropriately, otherwise {@link #getRunningActivity} won't 61 * work. 62 */ setRunningActivitySupplier(Supplier<Activity> activitySupplier)63 public static synchronized void setRunningActivitySupplier(Supplier<Activity> activitySupplier) { 64 runningActivitySupplier = Preconditions.checkNotNull(activitySupplier); 65 } 66 67 /** Shorthand to {@link #getRunningActivity(long)} with {@code timeoutMillis=30_000}. */ getRunningActivity()68 public static Activity getRunningActivity() { 69 return getRunningActivity(30_000L); 70 } 71 72 /** 73 * Waits for idle on main looper, then gets the running (a.k.a. resumed or foreground) activity. 74 * 75 * @return the currently running activity, or null if no activity has focus. 76 */ getRunningActivity(long timeoutMillis)77 public static Activity getRunningActivity(long timeoutMillis) { 78 // It's safe to check running activity only when the main looper is idle. 79 // If the AUT is in background, its main looper should be idle already. 80 // If the AUT is in foreground, its main looper should be idle eventually. 81 if (InstrumentationUtils.tryWaitForIdleSync(timeoutMillis)) { 82 return getRunningActivityNoWait(); 83 } 84 return null; 85 } 86 87 /** 88 * Gets the running (a.k.a. resumed or foreground) activity without waiting for idle on main 89 * looper. 90 * 91 * @return the currently running activity, or null if no activity has focus. 92 */ getRunningActivityNoWait()93 public static synchronized Activity getRunningActivityNoWait() { 94 return runningActivitySupplier.get(); 95 } 96 97 public interface Supplier<T> { 98 /** 99 * Retrieves an instance of the appropriate type. The returned object may or may not be a new 100 * instance, depending on the implementation. 101 * 102 * @return an instance of the appropriate type 103 */ get()104 T get(); 105 } 106 } 107