| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.base; | 5 package org.chromium.base; |
| 6 | 6 |
| 7 import android.app.Activity; | 7 import android.app.Activity; |
| 8 import android.app.Application; | 8 import android.app.Application; |
| 9 import android.app.Application.ActivityLifecycleCallbacks; | 9 import android.app.Application.ActivityLifecycleCallbacks; |
| 10 import android.content.Context; | 10 import android.content.Context; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 private static Object sCachedApplicationStateLock = new Object(); | 57 private static Object sCachedApplicationStateLock = new Object(); |
| 58 private static Integer sCachedApplicationState; | 58 private static Integer sCachedApplicationState; |
| 59 | 59 |
| 60 /** Last activity that was shown (or null if none or it was destroyed). */ | 60 /** Last activity that was shown (or null if none or it was destroyed). */ |
| 61 private static Activity sActivity; | 61 private static Activity sActivity; |
| 62 | 62 |
| 63 /** A lazily initialized listener that forwards application state changes to
native. */ | 63 /** A lazily initialized listener that forwards application state changes to
native. */ |
| 64 private static ApplicationStateListener sNativeApplicationStateListener; | 64 private static ApplicationStateListener sNativeApplicationStateListener; |
| 65 | 65 |
| 66 /** | 66 /** |
| 67 * If true means we are running in an activity lifecycle independent mode, |
| 68 * see {@link #initializeActivityIndependent(Application, Context)} for more
details. |
| 69 */ |
| 70 private static boolean sActivityLifecycleIndependentMode = false; |
| 71 |
| 72 /** |
| 73 * Context corresponding to sApplication. Note this context can be different
from sApplication |
| 74 * iself so use sApplicationContext instead of casting sApplication. |
| 75 */ |
| 76 private static Context sApplicationContext; |
| 77 |
| 78 /** |
| 67 * A map of which observers listen to state changes from which {@link Activi
ty}. | 79 * A map of which observers listen to state changes from which {@link Activi
ty}. |
| 68 */ | 80 */ |
| 69 private static final Map<Activity, ActivityInfo> sActivityInfo = | 81 private static final Map<Activity, ActivityInfo> sActivityInfo = |
| 70 new ConcurrentHashMap<Activity, ActivityInfo>(); | 82 new ConcurrentHashMap<Activity, ActivityInfo>(); |
| 71 | 83 |
| 72 /** | 84 /** |
| 73 * A list of observers to be notified when any {@link Activity} has a state
change. | 85 * A list of observers to be notified when any {@link Activity} has a state
change. |
| 74 */ | 86 */ |
| 75 private static final ObserverList<ActivityStateListener> sGeneralActivitySta
teListeners = | 87 private static final ObserverList<ActivityStateListener> sGeneralActivitySta
teListeners = |
| 76 new ObserverList<ActivityStateListener>(); | 88 new ObserverList<ActivityStateListener>(); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 102 * @param activity The activity that had a state change. | 114 * @param activity The activity that had a state change. |
| 103 * @param newState New activity state. | 115 * @param newState New activity state. |
| 104 */ | 116 */ |
| 105 public void onActivityStateChange(Activity activity, int newState); | 117 public void onActivityStateChange(Activity activity, int newState); |
| 106 } | 118 } |
| 107 | 119 |
| 108 private ApplicationStatus() {} | 120 private ApplicationStatus() {} |
| 109 | 121 |
| 110 /** | 122 /** |
| 111 * Initializes the activity status for a specified application. | 123 * Initializes the activity status for a specified application. |
| 124 * This method only registers for ActivityLifecycle changes. |
| 112 * | 125 * |
| 113 * @param application The application whose status you wish to monitor. | 126 * @param application The application whose status you wish to monitor. |
| 114 */ | 127 */ |
| 115 public static void initialize(BaseChromiumApplication application) { | 128 private static void initializeLifecycleCallbacks(Application application) { |
| 116 sApplication = application; | 129 sApplication = application; |
| 117 | 130 |
| 118 application.registerWindowFocusChangedListener( | |
| 119 new BaseChromiumApplication.WindowFocusChangedListener() { | |
| 120 @Override | |
| 121 public void onWindowFocusChanged(Activity activity, boolean
hasFocus) { | |
| 122 if (!hasFocus || activity == sActivity) return; | |
| 123 | |
| 124 int state = getStateForActivity(activity); | |
| 125 | |
| 126 if (state != ActivityState.DESTROYED && state != Activit
yState.STOPPED) { | |
| 127 sActivity = activity; | |
| 128 } | |
| 129 | |
| 130 // TODO(dtrainor): Notify of active activity change? | |
| 131 } | |
| 132 }); | |
| 133 | |
| 134 application.registerActivityLifecycleCallbacks(new ActivityLifecycleCall
backs() { | 131 application.registerActivityLifecycleCallbacks(new ActivityLifecycleCall
backs() { |
| 135 @Override | 132 @Override |
| 136 public void onActivityCreated(final Activity activity, Bundle savedI
nstanceState) { | 133 public void onActivityCreated(final Activity activity, Bundle savedI
nstanceState) { |
| 137 onStateChange(activity, ActivityState.CREATED); | 134 onStateChange(activity, ActivityState.CREATED); |
| 138 } | 135 } |
| 139 | 136 |
| 140 @Override | 137 @Override |
| 141 public void onActivityDestroyed(Activity activity) { | 138 public void onActivityDestroyed(Activity activity) { |
| 142 onStateChange(activity, ActivityState.DESTROYED); | 139 onStateChange(activity, ActivityState.DESTROYED); |
| 143 } | 140 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 161 } | 158 } |
| 162 | 159 |
| 163 @Override | 160 @Override |
| 164 public void onActivityStopped(Activity activity) { | 161 public void onActivityStopped(Activity activity) { |
| 165 onStateChange(activity, ActivityState.STOPPED); | 162 onStateChange(activity, ActivityState.STOPPED); |
| 166 } | 163 } |
| 167 }); | 164 }); |
| 168 } | 165 } |
| 169 | 166 |
| 170 /** | 167 /** |
| 168 * Initializes the activity status for a specified application. |
| 169 * The initialization should happen before any activity is created. |
| 170 * |
| 171 * @param application The application whose status you wish to monitor. |
| 172 */ |
| 173 public static void initialize(BaseChromiumApplication application) { |
| 174 sApplicationContext = application.getApplicationContext(); |
| 175 initializeLifecycleCallbacks(application); |
| 176 |
| 177 application.registerWindowFocusChangedListener( |
| 178 new BaseChromiumApplication.WindowFocusChangedListener() { |
| 179 @Override |
| 180 public void onWindowFocusChanged(Activity activity, boolean
hasFocus) { |
| 181 if (!hasFocus || activity == sActivity) return; |
| 182 |
| 183 int state = getStateForActivity(activity); |
| 184 |
| 185 if (state != ActivityState.DESTROYED && state != Activit
yState.STOPPED) { |
| 186 sActivity = activity; |
| 187 } |
| 188 |
| 189 // TODO(dtrainor): Notify of active activity change? |
| 190 } |
| 191 }); |
| 192 } |
| 193 |
| 194 |
| 195 /** |
| 196 * Initializes ApplicationStatus in "ActivityLifecycleIndependentMode". This
mode is |
| 197 * different from the regular initialization (@see initialize) in the follow
ing ways: |
| 198 * 1. Currently doesn't listen to focus changes (hence sActivity is always
null). |
| 199 * 2. Allows to specify a custom applicationContext and an android applica
tion object. |
| 200 * 3. Allows to call this method at any time during lifetime of the applic
ation. |
| 201 */ |
| 202 public static void initializeActivityIndependent(Application application, |
| 203 Context applicationContext) { |
| 204 sActivityLifecycleIndependentMode = true; |
| 205 sApplicationContext = applicationContext; |
| 206 |
| 207 // Assume we have running activity (or activity that will be running ver
y soon). |
| 208 // This is to handle the case when "initializeActivityIndependent" is ex
ecuted |
| 209 // after the ActivityState.CREATED, ActivityState.STARTED and ActivitySt
ate.RESUMED |
| 210 // have been dispatched. |
| 211 synchronized (sCachedApplicationStateLock) { |
| 212 sCachedApplicationState = ApplicationState.HAS_RUNNING_ACTIVITIES; |
| 213 } |
| 214 |
| 215 initializeLifecycleCallbacks(application); |
| 216 } |
| 217 |
| 218 /** |
| 171 * Must be called by the main activity when it changes state. | 219 * Must be called by the main activity when it changes state. |
| 172 * | 220 * |
| 173 * @param activity Current activity. | 221 * @param activity Current activity. |
| 174 * @param newState New state value. | 222 * @param newState New state value. |
| 175 */ | 223 */ |
| 176 private static void onStateChange(Activity activity, int newState) { | 224 private static void onStateChange(Activity activity, int newState) { |
| 177 if (activity == null) throw new IllegalArgumentException("null activity
is not supported"); | 225 if (activity == null) throw new IllegalArgumentException("null activity
is not supported"); |
| 178 | 226 |
| 179 if (sActivity == null | |
| 180 || newState == ActivityState.CREATED | |
| 181 || newState == ActivityState.RESUMED | |
| 182 || newState == ActivityState.STARTED) { | |
| 183 sActivity = activity; | |
| 184 } | |
| 185 | |
| 186 int oldApplicationState = getStateForApplication(); | 227 int oldApplicationState = getStateForApplication(); |
| 187 | 228 |
| 188 if (newState == ActivityState.CREATED) { | 229 if (sActivityLifecycleIndependentMode) { |
| 189 assert !sActivityInfo.containsKey(activity); | 230 assert sActivity == null; |
| 190 sActivityInfo.put(activity, new ActivityInfo()); | 231 if (!sActivityInfo.containsKey(activity)) { |
| 232 sActivityInfo.put(activity, new ActivityInfo()); |
| 233 } |
| 234 } else { |
| 235 if (sActivity == null |
| 236 || newState == ActivityState.CREATED |
| 237 || newState == ActivityState.RESUMED |
| 238 || newState == ActivityState.STARTED) { |
| 239 sActivity = activity; |
| 240 } |
| 241 |
| 242 if (newState == ActivityState.CREATED) { |
| 243 assert !sActivityInfo.containsKey(activity); |
| 244 sActivityInfo.put(activity, new ActivityInfo()); |
| 245 } |
| 191 } | 246 } |
| 192 | 247 |
| 193 // Invalidate the cached application state. | 248 // Invalidate the cached application state. |
| 194 synchronized (sCachedApplicationStateLock) { | 249 synchronized (sCachedApplicationStateLock) { |
| 195 sCachedApplicationState = null; | 250 sCachedApplicationState = null; |
| 196 } | 251 } |
| 197 | 252 |
| 198 ActivityInfo info = sActivityInfo.get(activity); | 253 ActivityInfo info = sActivityInfo.get(activity); |
| 199 info.setStatus(newState); | 254 info.setStatus(newState); |
| 200 | 255 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 226 * Testing method to update the state of the specified activity. | 281 * Testing method to update the state of the specified activity. |
| 227 */ | 282 */ |
| 228 @VisibleForTesting | 283 @VisibleForTesting |
| 229 public static void onStateChangeForTesting(Activity activity, int newState)
{ | 284 public static void onStateChangeForTesting(Activity activity, int newState)
{ |
| 230 onStateChange(activity, newState); | 285 onStateChange(activity, newState); |
| 231 } | 286 } |
| 232 | 287 |
| 233 /** | 288 /** |
| 234 * @return The most recent focused {@link Activity} tracked by this class.
Being focused means | 289 * @return The most recent focused {@link Activity} tracked by this class.
Being focused means |
| 235 * out of all the activities tracked here, it has most recently gain
ed window focus. | 290 * out of all the activities tracked here, it has most recently gain
ed window focus. |
| 291 * Note that in 'sActivityLifecycleIndependentMode' the returned Act
ivity is currently |
| 292 * always null (see crbug.com/538175). |
| 236 */ | 293 */ |
| 237 public static Activity getLastTrackedFocusedActivity() { | 294 public static Activity getLastTrackedFocusedActivity() { |
| 295 // sActivityLifecycleIndependentMode implies sActivity == null |
| 296 assert !sActivityLifecycleIndependentMode || sActivity == null; |
| 238 return sActivity; | 297 return sActivity; |
| 239 } | 298 } |
| 240 | 299 |
| 241 /** | 300 /** |
| 242 * @return A {@link List} of all non-destroyed {@link Activity}s. | 301 * @return A {@link List} of all non-destroyed {@link Activity}s. |
| 243 */ | 302 */ |
| 244 public static List<WeakReference<Activity>> getRunningActivities() { | 303 public static List<WeakReference<Activity>> getRunningActivities() { |
| 245 List<WeakReference<Activity>> activities = new ArrayList<WeakReference<A
ctivity>>(); | 304 List<WeakReference<Activity>> activities = new ArrayList<WeakReference<A
ctivity>>(); |
| 246 for (Activity activity : sActivityInfo.keySet()) { | 305 for (Activity activity : sActivityInfo.keySet()) { |
| 247 activities.add(new WeakReference<Activity>(activity)); | 306 activities.add(new WeakReference<Activity>(activity)); |
| 248 } | 307 } |
| 249 return activities; | 308 return activities; |
| 250 } | 309 } |
| 251 | 310 |
| 252 /** | 311 /** |
| 253 * @return The {@link Context} for the {@link Application}. | 312 * @return The {@link Context} for the {@link Application}. |
| 254 */ | 313 */ |
| 255 public static Context getApplicationContext() { | 314 public static Context getApplicationContext() { |
| 256 return sApplication != null ? sApplication.getApplicationContext() : nul
l; | 315 return sApplicationContext; |
| 257 } | 316 } |
| 258 | 317 |
| 259 /** | 318 /** |
| 260 * Query the state for a given activity. If the activity is not being track
ed, this will | 319 * Query the state for a given activity. If the activity is not being track
ed, this will |
| 261 * return {@link ActivityState#DESTROYED}. | 320 * return {@link ActivityState#DESTROYED}. |
| 262 * | 321 * |
| 263 * <p> | 322 * <p> |
| 264 * Please note that Chrome can have multiple activities running simultaneous
ly. Please also | 323 * Please note that Chrome can have multiple activities running simultaneous
ly. Please also |
| 265 * look at {@link #getStateForApplication()} for more details. | 324 * look at {@link #getStateForApplication()} for more details. |
| 266 * | 325 * |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 442 | 501 |
| 443 if (hasPausedActivity) return ApplicationState.HAS_PAUSED_ACTIVITIES; | 502 if (hasPausedActivity) return ApplicationState.HAS_PAUSED_ACTIVITIES; |
| 444 if (hasStoppedActivity) return ApplicationState.HAS_STOPPED_ACTIVITIES; | 503 if (hasStoppedActivity) return ApplicationState.HAS_STOPPED_ACTIVITIES; |
| 445 return ApplicationState.HAS_DESTROYED_ACTIVITIES; | 504 return ApplicationState.HAS_DESTROYED_ACTIVITIES; |
| 446 } | 505 } |
| 447 | 506 |
| 448 // Called to notify the native side of state changes. | 507 // Called to notify the native side of state changes. |
| 449 // IMPORTANT: This is always called on the main thread! | 508 // IMPORTANT: This is always called on the main thread! |
| 450 private static native void nativeOnApplicationStateChange(int newState); | 509 private static native void nativeOnApplicationStateChange(int newState); |
| 451 } | 510 } |
| OLD | NEW |