@@ -58,17 +58,13 @@ class FirebaseAppDistributionImpl implements FirebaseAppDistribution {
58
58
private final AabUpdater aabUpdater ;
59
59
private final SignInStorage signInStorage ;
60
60
61
- private final Object updateIfNewReleaseTaskLock = new Object ();
62
-
63
- @ GuardedBy ("updateIfNewReleaseTaskLock" )
64
- private UpdateTaskImpl cachedUpdateIfNewReleaseTask ;
65
-
66
61
private final Object cachedNewReleaseLock = new Object ();
67
62
68
63
@ GuardedBy ("cachedNewReleaseLock" )
69
64
private AppDistributionReleaseInternal cachedNewRelease ;
70
65
71
- private Task <AppDistributionRelease > cachedCheckForNewReleaseTask ;
66
+ private TaskCache <UpdateTask > updateIfNewReleaseAvailableTaskCache = new TaskCache <>();
67
+ private TaskCache <Task <AppDistributionRelease >> checkForNewReleaseTaskCache = new TaskCache <>();
72
68
private AlertDialog updateConfirmationDialog ;
73
69
private AlertDialog signInConfirmationDialog ;
74
70
@ Nullable private Activity dialogHostActivity = null ;
@@ -105,54 +101,57 @@ class FirebaseAppDistributionImpl implements FirebaseAppDistribution {
105
101
// TODO(b/261014422): Use an explicit executor in continuations.
106
102
@ SuppressLint ("TaskMainThread" )
107
103
public UpdateTask updateIfNewReleaseAvailable () {
108
- synchronized (updateIfNewReleaseTaskLock ) {
109
- if (updateIfNewReleaseAvailableIsTaskInProgress ()) {
110
- return cachedUpdateIfNewReleaseTask ;
111
- }
112
- cachedUpdateIfNewReleaseTask = new UpdateTaskImpl ();
113
- remakeSignInConfirmationDialog = false ;
114
- remakeUpdateConfirmationDialog = false ;
115
- dialogHostActivity = null ;
116
- }
117
- lifecycleNotifier
118
- .applyToForegroundActivityTask (this ::showSignInConfirmationDialog )
119
- .onSuccessTask (unused -> signInTester ())
120
- .onSuccessTask (unused -> checkForNewRelease ())
121
- .continueWithTask (
122
- task -> {
123
- if (!task .isSuccessful ()) {
124
- postProgressToCachedUpdateIfNewReleaseTask (
125
- UpdateProgressImpl .builder ()
126
- .setApkBytesDownloaded (UNKNOWN_RELEASE_FILE_SIZE )
127
- .setApkFileTotalBytes (UNKNOWN_RELEASE_FILE_SIZE )
128
- .setUpdateStatus (UpdateStatus .NEW_RELEASE_CHECK_FAILED )
129
- .build ());
130
- }
131
- // if the task failed, this get() will cause the error to propagate to the handler
132
- // below
133
- AppDistributionRelease release = task .getResult ();
134
- if (release == null ) {
135
- postProgressToCachedUpdateIfNewReleaseTask (
136
- UpdateProgressImpl .builder ()
137
- .setApkFileTotalBytes (UNKNOWN_RELEASE_FILE_SIZE )
138
- .setApkBytesDownloaded (UNKNOWN_RELEASE_FILE_SIZE )
139
- .setUpdateStatus (UpdateStatus .NEW_RELEASE_NOT_AVAILABLE )
140
- .build ());
141
- setCachedUpdateIfNewReleaseResult ();
142
- return Tasks .forResult (null );
143
- }
144
- return lifecycleNotifier .applyToForegroundActivityTask (
145
- activity -> showUpdateConfirmationDialog (activity , release ));
146
- })
147
- .onSuccessTask (
148
- unused ->
149
- updateApp (true )
150
- .addOnProgressListener (this ::postProgressToCachedUpdateIfNewReleaseTask ))
151
- .addOnFailureListener (this ::setCachedUpdateIfNewReleaseCompletionError );
152
-
153
- synchronized (updateIfNewReleaseTaskLock ) {
154
- return cachedUpdateIfNewReleaseTask ;
155
- }
104
+ return updateIfNewReleaseAvailableTaskCache .getOrCreateTask (
105
+ () -> {
106
+ UpdateTaskImpl updateTask = new UpdateTaskImpl ();
107
+ remakeSignInConfirmationDialog = false ;
108
+ remakeUpdateConfirmationDialog = false ;
109
+ dialogHostActivity = null ;
110
+
111
+ lifecycleNotifier
112
+ .applyToForegroundActivityTask (this ::showSignInConfirmationDialog )
113
+ .onSuccessTask (unused -> signInTester ())
114
+ .onSuccessTask (unused -> checkForNewRelease ())
115
+ .continueWithTask (
116
+ task -> {
117
+ if (!task .isSuccessful ()) {
118
+ postProgressToCachedUpdateIfNewReleaseTask (
119
+ updateTask ,
120
+ UpdateProgressImpl .builder ()
121
+ .setApkBytesDownloaded (UNKNOWN_RELEASE_FILE_SIZE )
122
+ .setApkFileTotalBytes (UNKNOWN_RELEASE_FILE_SIZE )
123
+ .setUpdateStatus (UpdateStatus .NEW_RELEASE_CHECK_FAILED )
124
+ .build ());
125
+ }
126
+ // if the task failed, this get() will cause the error to propagate to the
127
+ // handler below
128
+ AppDistributionRelease release = task .getResult ();
129
+ if (release == null ) {
130
+ postProgressToCachedUpdateIfNewReleaseTask (
131
+ updateTask ,
132
+ UpdateProgressImpl .builder ()
133
+ .setApkFileTotalBytes (UNKNOWN_RELEASE_FILE_SIZE )
134
+ .setApkBytesDownloaded (UNKNOWN_RELEASE_FILE_SIZE )
135
+ .setUpdateStatus (UpdateStatus .NEW_RELEASE_NOT_AVAILABLE )
136
+ .build ());
137
+ setCachedUpdateIfNewReleaseResult (updateTask );
138
+ return Tasks .forResult (null );
139
+ }
140
+ return lifecycleNotifier .applyToForegroundActivityTask (
141
+ activity -> showUpdateConfirmationDialog (activity , release ));
142
+ })
143
+ .onSuccessTask (
144
+ unused ->
145
+ updateApp (true )
146
+ .addOnProgressListener (
147
+ updateProgress ->
148
+ postProgressToCachedUpdateIfNewReleaseTask (
149
+ updateTask , updateProgress )))
150
+ .addOnFailureListener (
151
+ exception -> setCachedUpdateIfNewReleaseCompletionError (updateTask , exception ));
152
+
153
+ return updateTask ;
154
+ });
156
155
}
157
156
158
157
@ NonNull
@@ -224,37 +223,35 @@ public void signOutTester() {
224
223
// TODO(b/261014422): Use an explicit executor in continuations.
225
224
@ SuppressLint ("TaskMainThread" )
226
225
public synchronized Task <AppDistributionRelease > checkForNewRelease () {
227
- if (cachedCheckForNewReleaseTask != null && !cachedCheckForNewReleaseTask .isComplete ()) {
228
- LogWrapper .getInstance ().v ("Response in progress" );
229
- return cachedCheckForNewReleaseTask ;
230
- }
231
- if (!isTesterSignedIn ()) {
232
- return Tasks .forException (
233
- new FirebaseAppDistributionException ("Tester is not signed in" , AUTHENTICATION_FAILURE ));
234
- }
226
+ return checkForNewReleaseTaskCache .getOrCreateTask (
227
+ () -> {
228
+ if (!isTesterSignedIn ()) {
229
+ return Tasks .forException (
230
+ new FirebaseAppDistributionException (
231
+ "Tester is not signed in" , AUTHENTICATION_FAILURE ));
232
+ }
235
233
236
- cachedCheckForNewReleaseTask =
237
- newReleaseFetcher
238
- .checkForNewRelease ()
239
- .onSuccessTask (
240
- appDistributionReleaseInternal -> {
241
- setCachedNewRelease (appDistributionReleaseInternal );
242
- return Tasks .forResult (
243
- ReleaseUtils .convertToAppDistributionRelease (appDistributionReleaseInternal ));
244
- })
245
- .addOnFailureListener (
246
- e -> {
247
- if (e instanceof FirebaseAppDistributionException
248
- && ((FirebaseAppDistributionException ) e ).getErrorCode ()
249
- == AUTHENTICATION_FAILURE ) {
250
- // If CheckForNewRelease returns authentication error, the FID is no longer
251
- // valid or does not have access to the latest release. So sign out the tester
252
- // to force FID re-registration
253
- signOutTester ();
254
- }
255
- });
256
-
257
- return cachedCheckForNewReleaseTask ;
234
+ return newReleaseFetcher
235
+ .checkForNewRelease ()
236
+ .onSuccessTask (
237
+ appDistributionReleaseInternal -> {
238
+ setCachedNewRelease (appDistributionReleaseInternal );
239
+ return Tasks .forResult (
240
+ ReleaseUtils .convertToAppDistributionRelease (
241
+ appDistributionReleaseInternal ));
242
+ })
243
+ .addOnFailureListener (
244
+ e -> {
245
+ if (e instanceof FirebaseAppDistributionException
246
+ && ((FirebaseAppDistributionException ) e ).getErrorCode ()
247
+ == AUTHENTICATION_FAILURE ) {
248
+ // If CheckForNewRelease returns authentication error, the FID is no longer
249
+ // valid or does not have access to the latest release. So sign out the tester
250
+ // to force FID re-registration
251
+ signOutTester ();
252
+ }
253
+ });
254
+ });
258
255
}
259
256
260
257
@ Override
@@ -411,25 +408,20 @@ private Task<Void> showUpdateConfirmationDialog(
411
408
return showUpdateDialogTask .getTask ();
412
409
}
413
410
414
- private void setCachedUpdateIfNewReleaseCompletionError (Exception e ) {
415
- synchronized (updateIfNewReleaseTaskLock ) {
416
- safeSetTaskException (cachedUpdateIfNewReleaseTask , e );
417
- }
411
+ private void setCachedUpdateIfNewReleaseCompletionError (UpdateTaskImpl updateTask , Exception e ) {
412
+ safeSetTaskException (updateTask , e );
418
413
dismissDialogs ();
419
414
}
420
415
421
- private void postProgressToCachedUpdateIfNewReleaseTask (UpdateProgress progress ) {
422
- synchronized (updateIfNewReleaseTaskLock ) {
423
- if (cachedUpdateIfNewReleaseTask != null && !cachedUpdateIfNewReleaseTask .isComplete ()) {
424
- cachedUpdateIfNewReleaseTask .updateProgress (progress );
425
- }
416
+ private void postProgressToCachedUpdateIfNewReleaseTask (
417
+ UpdateTaskImpl updateTask , UpdateProgress progress ) {
418
+ if (updateTask != null && !updateTask .isComplete ()) {
419
+ updateTask .updateProgress (progress );
426
420
}
427
421
}
428
422
429
- private void setCachedUpdateIfNewReleaseResult () {
430
- synchronized (updateIfNewReleaseTaskLock ) {
431
- safeSetTaskResult (cachedUpdateIfNewReleaseTask );
432
- }
423
+ private void setCachedUpdateIfNewReleaseResult (UpdateTaskImpl updateTask ) {
424
+ safeSetTaskResult (updateTask );
433
425
dismissDialogs ();
434
426
}
435
427
@@ -448,12 +440,6 @@ private UpdateTaskImpl getErrorUpdateTask(Exception e) {
448
440
return updateTask ;
449
441
}
450
442
451
- private boolean updateIfNewReleaseAvailableIsTaskInProgress () {
452
- synchronized (updateIfNewReleaseTaskLock ) {
453
- return cachedUpdateIfNewReleaseTask != null && !cachedUpdateIfNewReleaseTask .isComplete ();
454
- }
455
- }
456
-
457
443
private boolean awaitingSignInDialogConfirmation () {
458
444
return (showSignInDialogTask != null
459
445
&& !showSignInDialogTask .getTask ().isComplete ()
0 commit comments