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 |