Index: base/android/java/src/org/chromium/base/ActivityStatus.java |
diff --git a/base/android/java/src/org/chromium/base/ActivityStatus.java b/base/android/java/src/org/chromium/base/ActivityStatus.java |
index 47472342b20946466c13268558b9616c12d1d625..e449b38d829f182bc25e8b948f36f08c5bc51d48 100644 |
--- a/base/android/java/src/org/chromium/base/ActivityStatus.java |
+++ b/base/android/java/src/org/chromium/base/ActivityStatus.java |
@@ -5,8 +5,12 @@ |
package org.chromium.base; |
import android.app.Activity; |
-import android.os.Handler; |
-import android.os.Looper; |
+import android.app.Application; |
+import android.app.Application.ActivityLifecycleCallbacks; |
+import android.os.Bundle; |
+ |
+import java.util.HashMap; |
+import java.util.Map; |
/** |
* Provides information about the current activity's status, and a way |
@@ -25,15 +29,14 @@ public class ActivityStatus { |
public static final int STOPPED = ActivityState.STOPPED; |
public static final int DESTROYED = ActivityState.DESTROYED; |
- // Current main activity, or null if none. |
+ // Last activity that was shown (or null if none or it was destroyed). |
private static Activity sActivity; |
- // Current main activity's state. This can be set even if sActivity is null, to simplify unit |
- // testing. |
- private static int sActivityState; |
+ private static final Map<Activity, Integer> sActivityStates |
+ = new HashMap<Activity, Integer>(); |
- private static final ObserverList<StateListener> sStateListeners = |
- new ObserverList<StateListener>(); |
+ private static final ObserverList<StateListener> sStateListeners |
+ = new ObserverList<StateListener>(); |
/** |
* Interface to be implemented by listeners. |
@@ -49,47 +52,163 @@ public class ActivityStatus { |
private ActivityStatus() {} |
/** |
+ * Initializes the activity status for a specified application. |
+ * |
+ * @param application The application whose status you wish to monitor. |
+ */ |
+ public static void initialize(Application application) { |
+ application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { |
+ @Override |
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) { |
+ onStateChange(activity, CREATED); |
+ } |
+ |
+ @Override |
+ public void onActivityDestroyed(Activity activity) { |
+ onStateChange(activity, DESTROYED); |
+ } |
+ |
+ @Override |
+ public void onActivityPaused(Activity activity) { |
+ onStateChange(activity, PAUSED); |
+ } |
+ |
+ @Override |
+ public void onActivityResumed(Activity activity) { |
+ onStateChange(activity, RESUMED); |
+ } |
+ |
+ @Override |
+ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {} |
+ |
+ @Override |
+ public void onActivityStarted(Activity activity) { |
+ onStateChange(activity, STARTED); |
+ } |
+ |
+ @Override |
+ public void onActivityStopped(Activity activity) { |
+ onStateChange(activity, STOPPED); |
+ } |
+ }); |
+ } |
+ |
+ /** |
* Must be called by the main activity when it changes state. |
+ * |
* @param activity Current activity. |
* @param newState New state value. |
*/ |
+ // TODO(tedchoc): Make this method private (and remove @Deprecated) once all downstream usages |
+ // move to the initialize method. |
+ @Deprecated |
public static void onStateChange(Activity activity, int newState) { |
+ if (activity == null) throw new IllegalArgumentException("null activity is not supported"); |
+ |
if (sActivity != activity) { |
// ActivityStatus is notified with the CREATED event very late during the main activity |
// creation to avoid making startup performance worse than it is by notifying observers |
// that could do some expensive work. This can lead to non-CREATED events being fired |
// before the CREATED event which is problematic. |
// TODO(pliard): fix http://crbug.com/176837. |
- sActivity = activity; |
+ if (sActivity == null |
+ || newState == CREATED || newState == RESUMED || newState == STARTED) { |
+ sActivity = activity; |
+ } |
} |
- sActivityState = newState; |
- for (StateListener listener : sStateListeners) { |
- listener.onActivityStateChange(newState); |
+ |
+ if (newState != DESTROYED) { |
+ sActivityStates.put(activity, newState); |
+ } else { |
+ sActivityStates.remove(activity); |
} |
- if (newState == DESTROYED) { |
- sActivity = null; |
+ |
+ if (sActivity == activity) { |
+ for (StateListener listener : sStateListeners) { |
+ listener.onActivityStateChange(newState); |
+ } |
+ if (newState == DESTROYED) { |
+ sActivity = null; |
+ } |
} |
} |
/** |
- * Indicates that the parent activity is currently paused. |
+ * Testing method to update the state of the specified activity. |
+ */ |
+ public static void onStateChangeForTesting(Activity activity, int newState) { |
+ onStateChange(activity, newState); |
+ } |
+ |
+ /** |
+ * Indicates that the current activity is paused. |
+ * |
+ * Use explicit state checking instead. |
*/ |
+ @Deprecated |
public static boolean isPaused() { |
- return sActivityState == PAUSED; |
+ if (sActivity == null) return false; |
+ Integer currentStatus = sActivityStates.get(sActivity); |
+ return currentStatus != null && currentStatus.intValue() == PAUSED; |
} |
/** |
- * Returns the current main application activity. |
+ * @return The current activity. |
*/ |
public static Activity getActivity() { |
return sActivity; |
} |
/** |
- * Returns the current main application activity's state. |
+ * @return The current activity's state (if no activity is registered, then DESTROYED will |
+ * be returned). |
*/ |
public static int getState() { |
- return sActivityState; |
+ return getStateForActivity(sActivity); |
+ } |
+ |
+ /** |
+ * Query the state for a given activity. If the activity is not being tracked, this will |
+ * return {@link #DESTROYED}. |
+ * |
+ * <p> |
+ * When relying on this method, be familiar with the expected life cycle state |
+ * transitions: |
+ * <a href="http://developer.android.com/guide/components/activities.html#Lifecycle"> |
+ * Activity Lifecycle |
+ * </a> |
+ * |
+ * <p> |
+ * During activity transitions (activity B launching in front of activity A), A will completely |
+ * paused before the creation of activity B begins. |
+ * |
+ * <p> |
+ * A basic flow for activity A starting, followed by activity B being opened and then closed: |
+ * <ul> |
+ * <li> -- Starting Activity A -- |
+ * <li> Activity A - CREATED |
+ * <li> Activity A - STARTED |
+ * <li> Activity A - RESUMED |
+ * <li> -- Staring Activity B -- |
+ * <li> Activity A - PAUSED |
+ * <li> Activity B - CREATED |
+ * <li> Activity B - STARTED |
+ * <li> Activity B - RESUMED |
+ * <li> Activity A - STOPPED |
+ * <li> -- Closing Activity B, Activity A regaining focus -- |
+ * <li> Activity B - PAUSED |
+ * <li> Activity A - STARTED |
+ * <li> Activity A - RESUMED |
+ * <li> Activity B - STOPPED |
+ * <li> Activity B - DESTROYED |
+ * </ul> |
+ * |
+ * @param activity The activity whose state is to be returned. |
+ * @return The state of the specified activity. |
+ */ |
+ public static int getStateForActivity(Activity activity) { |
+ Integer currentStatus = sActivityStates.get(activity); |
+ return currentStatus != null ? currentStatus.intValue() : DESTROYED; |
} |
/** |