21
21
import androidx .annotation .NonNull ;
22
22
import androidx .annotation .Nullable ;
23
23
import androidx .annotation .VisibleForTesting ;
24
+ import com .google .android .gms .tasks .SuccessContinuation ;
24
25
import com .google .android .gms .tasks .Task ;
25
26
import com .google .android .gms .tasks .TaskCompletionSource ;
26
27
import com .google .android .gms .tasks .Tasks ;
27
28
import java .util .ArrayDeque ;
28
29
import java .util .Queue ;
30
+ import java .util .concurrent .Executor ;
29
31
30
32
class FirebaseAppDistributionLifecycleNotifier implements Application .ActivityLifecycleCallbacks {
31
33
32
- /** A functional interface for a function that takes an activity and returns a value. */
33
- interface ActivityFunction <T > {
34
- T apply (Activity activity ) throws FirebaseAppDistributionException ;
35
- }
34
+ /** An {@link Executor} that runs tasks on the current thread. */
35
+ private static final Executor DIRECT_EXECUTOR = Runnable ::run ;
36
36
37
- /** A functional interface for a function that takes an activity and returns a {@link Task} . */
38
- interface ActivityChainingFunction <T > {
39
- Task < T > apply (Activity activity ) throws FirebaseAppDistributionException ;
37
+ /** A functional interface for a function that takes an activity and does something with it . */
38
+ interface ActivityConsumer <T > {
39
+ void consume (Activity activity );
40
40
}
41
41
42
+ /** A {@link SuccessContinuation} that takes an activity and returns a new {@link Task}. */
43
+ interface ActivityContinuation <T > extends SuccessContinuation <Activity , T > {}
44
+
42
45
private static FirebaseAppDistributionLifecycleNotifier instance ;
43
46
private final Object lock = new Object ();
44
47
@@ -96,13 +99,43 @@ interface OnActivityDestroyedListener {
96
99
}
97
100
98
101
/**
99
- * Get a {@link Task} that will succeed with a result of the app's foregrounded {@link Activity},
100
- * when one is available.
101
- *
102
- * <p>The returned task will never fail. It will instead remain pending indefinitely until some
103
- * activity comes to the foreground.
102
+ * Apply a function to a foreground activity, when one is available, returning a {@link Task} that
103
+ * will complete immediately after the function is applied.
104
104
*/
105
- Task <Activity > getForegroundActivity () {
105
+ Task <Void > applyToForegroundActivity (ActivityConsumer consumer ) {
106
+ return getForegroundActivity ()
107
+ .onSuccessTask (
108
+ // Use direct executor to ensure the consumer is called while Activity is in foreground
109
+ DIRECT_EXECUTOR ,
110
+ activity -> {
111
+ try {
112
+ consumer .consume (activity );
113
+ return Tasks .forResult (null );
114
+ } catch (Throwable t ) {
115
+ return Tasks .forException (FirebaseAppDistributionException .wrap (t ));
116
+ }
117
+ });
118
+ }
119
+
120
+ /**
121
+ * Apply a function to a foreground activity, when one is available, returning a {@link Task} that
122
+ * will complete with the result of the Task returned by that function.
123
+ */
124
+ <T > Task <T > applyToForegroundActivityTask (ActivityContinuation <T > continuation ) {
125
+ return getForegroundActivity ()
126
+ .onSuccessTask (
127
+ // Use direct executor to ensure the consumer is called while Activity is in foreground
128
+ DIRECT_EXECUTOR ,
129
+ activity -> {
130
+ try {
131
+ return continuation .then (activity );
132
+ } catch (Throwable t ) {
133
+ return Tasks .forException (FirebaseAppDistributionException .wrap (t ));
134
+ }
135
+ });
136
+ }
137
+
138
+ private Task <Activity > getForegroundActivity () {
106
139
synchronized (lock ) {
107
140
if (currentActivity != null ) {
108
141
return Tasks .forResult (currentActivity );
@@ -122,97 +155,6 @@ public void onResumed(Activity activity) {
122
155
}
123
156
}
124
157
125
- // /**
126
- // * Get a {@link Task} that will succeed with a result of the app's foregrounded {@link Activity},
127
- // * when one is available.
128
- // *
129
- // * <p>The returned task will never fail. It will instead remain pending indefinitely until some
130
- // * activity comes to the foreground.
131
- // */
132
- // Task<Activity> getForegroundActivity() {
133
- // return getForegroundActivity(activity -> {});
134
- // }
135
-
136
- // /**
137
- // * Get a {@link Task} that results from applying a {@link ActivityFunction} applied to the app's
138
- // * foregrounded {@link Activity}, when one is available.
139
- // *
140
- // * <p>The returned task will fail if the {@link ActivityFunction} throws, or the task it returns
141
- // * fails. Otherwise it will never fail, and will wait indefinitely for a foreground activity
142
- // * before applying the function.
143
- // */
144
- // <T> Task<T> applyToForegroundActivityChaining(ActivityFunction<Task<T>> function) {
145
- // synchronized (lock) {
146
- // TaskCompletionSource<T> task = new TaskCompletionSource<>();
147
- // if (currentActivity != null) {
148
- // chainToActivity(task, currentActivity, function);
149
- // } else {
150
- // addOnActivityResumedListener(
151
- // new OnActivityResumedListener() {
152
- // @Override
153
- // public void onResumed(Activity activity) {
154
- // chainToActivity(task, activity, function);
155
- // removeOnActivityResumedListener(this);
156
- // }
157
- // });
158
- // }
159
- //
160
- // return task.getTask();
161
- // }
162
- // }
163
- //
164
- // <T> Task<T> chainToActivity(
165
- // TaskCompletionSource<T> task, Activity activity, ActivityFunction<Task<T>> function) {
166
- // MoreExecutors
167
- // try {
168
- // function.apply(activity)
169
- // .addOnSuccessListener(task::setResult)
170
- // .addOnFailureListener(task::setException)
171
- // .addOnCanceledListener(task::canc)
172
- // continuation.on
173
- // task.setResult(function.apply(activity));
174
- // } catch (Throwable t) {
175
- // task.setException(FirebaseAppDistributionException.wrap(t));
176
- // }
177
- // }
178
- //
179
- // /**
180
- // * Get a {@link Task} that will succeed with a result of applying an {@link ActivityFunction} to
181
- // * the app's foregrounded {@link Activity}, when one is available.
182
- // *
183
- // * <p>The returned task will fail with a {@link FirebaseAppDistributionException} if the {@link
184
- // * ActivityFunction} throws. Otherwise it will never fail, and will wait indefinitely for a
185
- // * foreground activity before applying the function.
186
- // */
187
- // <T> Task<T> applyToForegroundActivity(ActivityFunction<T> function) {
188
- // synchronized (lock) {
189
- // TaskCompletionSource<T> task = new TaskCompletionSource<>();
190
- // if (currentActivity != null) {
191
- // applyToActivityAndCompleteTask(task, currentActivity, function);
192
- // } else {
193
- // addOnActivityResumedListener(
194
- // new OnActivityResumedListener() {
195
- // @Override
196
- // public void onResumed(Activity activity) {
197
- // applyToActivityAndCompleteTask(task, activity, function);
198
- // removeOnActivityResumedListener(this);
199
- // }
200
- // });
201
- // }
202
- //
203
- // return task.getTask();
204
- // }
205
- // }
206
- //
207
- // <T> void applyToActivityAndCompleteTask(
208
- // TaskCompletionSource<T> task, Activity activity, ActivityFunction<T> function) {
209
- // try {
210
- // task.setResult(function.apply(activity));
211
- // } catch (Throwable t) {
212
- // task.setException(FirebaseAppDistributionException.wrap(t));
213
- // }
214
- // }
215
-
216
158
void addOnActivityCreatedListener (@ NonNull OnActivityCreatedListener listener ) {
217
159
synchronized (lock ) {
218
160
this .onActivityCreatedListeners .add (listener );
0 commit comments