18
18
19
19
import android .app .Activity ;
20
20
import android .app .Application ;
21
+ import android .app .Application .ActivityLifecycleCallbacks ;
21
22
import android .os .Bundle ;
22
23
import android .os .Looper ;
23
24
import androidx .annotation .GuardedBy ;
24
25
import androidx .annotation .NonNull ;
25
26
import androidx .annotation .Nullable ;
27
+ import androidx .annotation .VisibleForTesting ;
26
28
import com .google .android .gms .tasks .SuccessContinuation ;
27
29
import com .google .android .gms .tasks .Task ;
28
30
import com .google .android .gms .tasks .TaskCompletionSource ;
35
37
import javax .inject .Inject ;
36
38
import javax .inject .Singleton ;
37
39
38
- @ Singleton
39
- class FirebaseAppDistributionLifecycleNotifier implements Application . ActivityLifecycleCallbacks {
40
+ @ Singleton // Only one lifecycle notifier is required across the entire app
41
+ class FirebaseAppDistributionLifecycleNotifier {
40
42
41
43
/** An {@link Executor} that runs tasks on the current thread. */
42
44
private static final Executor DIRECT_EXECUTOR = Runnable ::run ;
@@ -59,8 +61,12 @@ interface NullableActivityFunction<T> {
59
61
}
60
62
61
63
@ UiThread private final Executor uiThreadExecutor ;
64
+ @ VisibleForTesting final LifecycleCallbacks lifecycleCallbacks = new LifecycleCallbacks ();
62
65
private final Object lock = new Object ();
63
66
67
+ @ GuardedBy ("lock" )
68
+ private boolean lifecycleCallbacksRegistered = false ;
69
+
64
70
@ GuardedBy ("lock" )
65
71
private Activity currentActivity ;
66
72
@@ -112,6 +118,21 @@ interface OnActivityDestroyedListener {
112
118
void onDestroyed (Activity activity );
113
119
}
114
120
121
+ /**
122
+ * Register for activity lifecycle callbacks for the application.
123
+ *
124
+ * <p>This must be called for this class to provide information about activity state.
125
+ */
126
+ void registerActivityLifecycleCallbacks (Application application ) {
127
+ synchronized (lock ) {
128
+ // Make sure we register for callbacks only once, so callbacks are not called twice
129
+ if (!lifecycleCallbacksRegistered ) {
130
+ application .registerActivityLifecycleCallbacks (lifecycleCallbacks );
131
+ lifecycleCallbacksRegistered = true ;
132
+ }
133
+ }
134
+ }
135
+
115
136
/**
116
137
* Apply a function to a foreground activity, when one is available, returning a {@link Task} that
117
138
* will complete immediately after the function is applied.
@@ -311,67 +332,71 @@ void addOnActivityPausedListener(@NonNull OnActivityPausedListener listener) {
311
332
}
312
333
}
313
334
314
- @ Override
315
- public void onActivityCreated (@ NonNull Activity activity , @ Nullable Bundle bundle ) {
316
- synchronized (lock ) {
317
- updateCurrentActivity (activity );
318
- for (OnActivityCreatedListener listener : onActivityCreatedListeners ) {
319
- listener .onCreated (activity );
335
+ @ VisibleForTesting
336
+ class LifecycleCallbacks implements ActivityLifecycleCallbacks {
337
+
338
+ @ Override
339
+ public void onActivityCreated (@ NonNull Activity activity , @ Nullable Bundle bundle ) {
340
+ synchronized (lock ) {
341
+ updateCurrentActivity (activity );
342
+ for (OnActivityCreatedListener listener : onActivityCreatedListeners ) {
343
+ listener .onCreated (activity );
344
+ }
320
345
}
321
346
}
322
- }
323
347
324
- @ Override
325
- public void onActivityStarted (@ NonNull Activity activity ) {
326
- synchronized (lock ) {
327
- updateCurrentActivity (activity );
328
- for (OnActivityStartedListener listener : onActivityStartedListeners ) {
329
- listener .onStarted (activity );
348
+ @ Override
349
+ public void onActivityStarted (@ NonNull Activity activity ) {
350
+ synchronized (lock ) {
351
+ updateCurrentActivity (activity );
352
+ for (OnActivityStartedListener listener : onActivityStartedListeners ) {
353
+ listener .onStarted (activity );
354
+ }
330
355
}
331
356
}
332
- }
333
357
334
- @ Override
335
- public void onActivityResumed (@ NonNull Activity activity ) {
336
- synchronized (lock ) {
337
- updateCurrentActivity (activity );
338
- for (OnActivityResumedListener listener : onActivityResumedListeners ) {
339
- listener .onResumed (activity );
358
+ @ Override
359
+ public void onActivityResumed (@ NonNull Activity activity ) {
360
+ synchronized (lock ) {
361
+ updateCurrentActivity (activity );
362
+ for (OnActivityResumedListener listener : onActivityResumedListeners ) {
363
+ listener .onResumed (activity );
364
+ }
340
365
}
341
366
}
342
- }
343
367
344
- @ Override
345
- public void onActivityPaused (@ NonNull Activity activity ) {
346
- synchronized (lock ) {
347
- if (currentActivity == activity ) {
348
- updateCurrentActivity (null );
349
- }
350
- for (OnActivityPausedListener listener : onActivityPausedListeners ) {
351
- listener .onPaused (activity );
368
+ @ Override
369
+ public void onActivityPaused (@ NonNull Activity activity ) {
370
+ synchronized (lock ) {
371
+ if (currentActivity == activity ) {
372
+ updateCurrentActivity (null );
373
+ }
374
+ for (OnActivityPausedListener listener : onActivityPausedListeners ) {
375
+ listener .onPaused (activity );
376
+ }
352
377
}
353
378
}
354
- }
355
379
356
- @ Override
357
- public void onActivityStopped (@ NonNull Activity activity ) {}
380
+ @ Override
381
+ public void onActivityStopped (@ NonNull Activity activity ) {}
358
382
359
- @ Override
360
- public void onActivitySaveInstanceState (@ NonNull Activity activity , @ NonNull Bundle bundle ) {}
383
+ @ Override
384
+ public void onActivitySaveInstanceState (@ NonNull Activity activity , @ NonNull Bundle bundle ) {}
361
385
362
- @ Override
363
- public void onActivityDestroyed (@ NonNull Activity activity ) {
364
- synchronized (lock ) {
365
- // If an activity is destroyed, delete all references to it, including the previous activity
366
- if (currentActivity == activity ) {
367
- updateCurrentActivity (null );
368
- }
369
- if (previousActivity == activity ) {
370
- previousActivity = null ;
371
- }
386
+ @ Override
387
+ public void onActivityDestroyed (@ NonNull Activity activity ) {
388
+ synchronized (lock ) {
389
+ // If an activity is destroyed, delete all references to it, including the previous activity
390
+ if (currentActivity == activity ) {
391
+ updateCurrentActivity (null );
392
+ }
393
+ if (previousActivity == activity ) {
394
+ previousActivity = null ;
395
+ }
372
396
373
- for (OnActivityDestroyedListener listener : onDestroyedListeners ) {
374
- listener .onDestroyed (activity );
397
+ for (OnActivityDestroyedListener listener : onDestroyedListeners ) {
398
+ listener .onDestroyed (activity );
399
+ }
375
400
}
376
401
}
377
402
}
0 commit comments