24
24
import androidx .annotation .GuardedBy ;
25
25
import androidx .annotation .NonNull ;
26
26
import androidx .annotation .Nullable ;
27
- import androidx .annotation .RestrictTo ;
28
27
import androidx .annotation .VisibleForTesting ;
29
28
import com .google .android .gms .tasks .CancellationTokenSource ;
30
29
import com .google .android .gms .tasks .Task ;
43
42
44
43
/** Client class that handles updateApp functionality for APKs in {@link UpdateAppClient}. */
45
44
class UpdateApkClient {
46
-
47
- private final int UPDATE_INTERVAL_MS = 250 ;
45
+ private static final int UPDATE_INTERVAL_MS = 250 ;
48
46
private static final String TAG = "FADUpdateAppClient" ;
49
47
private static final String REQUEST_METHOD = "GET" ;
50
48
private final FirebaseAppDistributionNotificationsManager appDistributionNotificationsManager ;
@@ -53,13 +51,15 @@ class UpdateApkClient {
53
51
private final Executor downloadExecutor ;
54
52
private TaskCompletionSource <Void > installTaskCompletionSource ;
55
53
private final FirebaseApp firebaseApp ;
54
+
55
+ @ GuardedBy ("updateTaskLock" )
56
56
private UpdateTaskImpl cachedUpdateTask ;
57
- private boolean showDownloadInNotificationManager = false ;
58
57
59
58
@ GuardedBy ("activityLock" )
60
59
private Activity currentActivity ;
61
60
62
61
private final Object activityLock = new Object ();
62
+ private final Object updateTaskLock = new Object ();
63
63
64
64
public UpdateApkClient (@ NonNull FirebaseApp firebaseApp ) {
65
65
this .downloadExecutor = Executors .newSingleThreadExecutor ();
@@ -68,20 +68,25 @@ public UpdateApkClient(@NonNull FirebaseApp firebaseApp) {
68
68
new FirebaseAppDistributionNotificationsManager (firebaseApp );
69
69
}
70
70
71
- public void updateApk (
72
- @ NonNull UpdateTaskImpl updateTask ,
73
- @ NonNull String downloadUrl ,
74
- @ NonNull boolean showDownloadInNotificationManager ) {
75
- this .showDownloadInNotificationManager = showDownloadInNotificationManager ;
76
- this .cachedUpdateTask = updateTask ;
77
- downloadApk (downloadUrl )
71
+ public synchronized UpdateTaskImpl updateApk (
72
+ @ NonNull String downloadUrl , boolean showDownloadNotificationManager ) {
73
+ synchronized (updateTaskLock ) {
74
+ if (cachedUpdateTask != null && !cachedUpdateTask .isComplete ()) {
75
+ return cachedUpdateTask ;
76
+ }
77
+
78
+ cachedUpdateTask = new UpdateTaskImpl ();
79
+ }
80
+
81
+ downloadApk (downloadUrl , showDownloadNotificationManager )
78
82
.addOnSuccessListener (
79
83
downloadExecutor ,
80
84
file ->
81
85
install (file .getPath ())
82
86
.addOnFailureListener (
83
87
e -> {
84
- postInstallationFailure (e , file .length ());
88
+ postInstallationFailure (
89
+ e , file .length (), showDownloadNotificationManager );
85
90
setTaskCompletionErrorWithDefault (
86
91
e ,
87
92
new FirebaseAppDistributionException (
@@ -97,23 +102,28 @@ public void updateApk(
97
102
Constants .ErrorMessages .NETWORK_ERROR ,
98
103
FirebaseAppDistributionException .Status .DOWNLOAD_FAILURE ));
99
104
});
105
+
106
+ synchronized (updateTaskLock ) {
107
+ return cachedUpdateTask ;
108
+ }
100
109
}
101
110
102
111
@ VisibleForTesting
103
112
@ NonNull
104
- Task <File > downloadApk (@ NonNull String downloadUrl ) {
113
+ Task <File > downloadApk (@ NonNull String downloadUrl , boolean showDownloadNotificationManager ) {
105
114
if (downloadTaskCompletionSource != null
106
115
&& !downloadTaskCompletionSource .getTask ().isComplete ()) {
107
116
return downloadTaskCompletionSource .getTask ();
108
117
}
109
118
110
119
downloadTaskCompletionSource = new TaskCompletionSource <>();
111
120
112
- makeApkDownloadRequest (downloadUrl );
121
+ makeApkDownloadRequest (downloadUrl , showDownloadNotificationManager );
113
122
return downloadTaskCompletionSource .getTask ();
114
123
}
115
124
116
- private void makeApkDownloadRequest (@ NonNull String downloadUrl ) {
125
+ private void makeApkDownloadRequest (
126
+ @ NonNull String downloadUrl , boolean showDownloadNotificationManager ) {
117
127
downloadExecutor .execute (
118
128
() -> {
119
129
try {
@@ -126,9 +136,14 @@ private void makeApkDownloadRequest(@NonNull String downloadUrl) {
126
136
FirebaseAppDistributionException .Status .DOWNLOAD_FAILURE ));
127
137
} else {
128
138
long responseLength = connection .getContentLength ();
129
- postUpdateProgress (responseLength , 0 , UpdateStatus .PENDING );
139
+ postUpdateProgress (
140
+ responseLength , 0 , UpdateStatus .PENDING , showDownloadNotificationManager );
130
141
String fileName = getApplicationName () + ".apk" ;
131
- downloadToDisk (connection .getInputStream (), responseLength , fileName );
142
+ downloadToDisk (
143
+ connection .getInputStream (),
144
+ responseLength ,
145
+ fileName ,
146
+ showDownloadNotificationManager );
132
147
}
133
148
} catch (IOException | FirebaseAppDistributionException e ) {
134
149
setDownloadTaskCompletionErrorWithDefault (
@@ -140,7 +155,8 @@ private void makeApkDownloadRequest(@NonNull String downloadUrl) {
140
155
});
141
156
}
142
157
143
- private void downloadToDisk (InputStream input , long totalSize , String fileName ) {
158
+ private void downloadToDisk (
159
+ InputStream input , long totalSize , String fileName , boolean showDownloadNotificationManager ) {
144
160
145
161
File apkFile = getApkFileForApp (fileName );
146
162
apkFile .delete ();
@@ -162,12 +178,20 @@ private void downloadToDisk(InputStream input, long totalSize, String fileName)
162
178
long currentTimeMs = System .currentTimeMillis ();
163
179
if (currentTimeMs - lastMsUpdated > UPDATE_INTERVAL_MS ) {
164
180
lastMsUpdated = currentTimeMs ;
165
- postUpdateProgress (totalSize , bytesDownloaded , UpdateStatus .DOWNLOADING );
181
+ postUpdateProgress (
182
+ totalSize ,
183
+ bytesDownloaded ,
184
+ UpdateStatus .DOWNLOADING ,
185
+ showDownloadNotificationManager );
166
186
}
167
187
}
168
188
169
189
} catch (IOException e ) {
170
- postUpdateProgress (totalSize , bytesDownloaded , UpdateStatus .DOWNLOAD_FAILED );
190
+ postUpdateProgress (
191
+ totalSize ,
192
+ bytesDownloaded ,
193
+ UpdateStatus .DOWNLOAD_FAILED ,
194
+ showDownloadNotificationManager );
171
195
setDownloadTaskCompletionError (
172
196
new FirebaseAppDistributionException (
173
197
Constants .ErrorMessages .NETWORK_ERROR ,
@@ -178,15 +202,20 @@ private void downloadToDisk(InputStream input, long totalSize, String fileName)
178
202
// check that file is actual JAR
179
203
new JarFile (apkFile );
180
204
} catch (Exception e ) {
181
- postUpdateProgress (totalSize , bytesDownloaded , UpdateStatus .DOWNLOAD_FAILED );
205
+ postUpdateProgress (
206
+ totalSize ,
207
+ bytesDownloaded ,
208
+ UpdateStatus .DOWNLOAD_FAILED ,
209
+ showDownloadNotificationManager );
182
210
setDownloadTaskCompletionError (
183
211
new FirebaseAppDistributionException (
184
212
Constants .ErrorMessages .NETWORK_ERROR ,
185
213
FirebaseAppDistributionException .Status .DOWNLOAD_FAILURE ));
186
214
}
187
215
188
216
// completion
189
- postUpdateProgress (totalSize , totalSize , UpdateStatus .DOWNLOADED );
217
+ postUpdateProgress (
218
+ totalSize , totalSize , UpdateStatus .DOWNLOADED , showDownloadNotificationManager );
190
219
191
220
downloadTaskCompletionSource .setResult (apkFile );
192
221
}
@@ -257,7 +286,10 @@ private Task<Void> install(String path) {
257
286
void setInstallationResult (int resultCode ) {
258
287
if (resultCode == Activity .RESULT_OK ) {
259
288
installTaskCompletionSource .setResult (null );
260
- cachedUpdateTask .setResult ();
289
+
290
+ synchronized (updateTaskLock ) {
291
+ cachedUpdateTask .setResult ();
292
+ }
261
293
} else if (resultCode == Activity .RESULT_CANCELED ) {
262
294
installTaskCompletionSource .setException (
263
295
new FirebaseAppDistributionException (
@@ -272,8 +304,10 @@ void setInstallationResult(int resultCode) {
272
304
}
273
305
274
306
private void setTaskCompletionError (FirebaseAppDistributionException e ) {
275
- if (cachedUpdateTask != null && !cachedUpdateTask .isComplete ()) {
276
- cachedUpdateTask .setException (e );
307
+ synchronized (updateTaskLock ) {
308
+ if (cachedUpdateTask != null && !cachedUpdateTask .isComplete ()) {
309
+ cachedUpdateTask .setException (e );
310
+ }
277
311
}
278
312
}
279
313
@@ -287,24 +321,33 @@ private void setTaskCompletionErrorWithDefault(
287
321
}
288
322
289
323
@ VisibleForTesting
290
- void postUpdateProgress (long totalBytes , long downloadedBytes , UpdateStatus status ) {
291
- cachedUpdateTask .updateProgress (
292
- UpdateProgress .builder ()
293
- .setApkFileTotalBytes (totalBytes )
294
- .setApkBytesDownloaded (downloadedBytes )
295
- .setUpdateStatus (status )
296
- .build ());
297
- if (showDownloadInNotificationManager ) {
324
+ void postUpdateProgress (
325
+ long totalBytes ,
326
+ long downloadedBytes ,
327
+ UpdateStatus status ,
328
+ boolean showDownloadNotificationManager ) {
329
+ synchronized (updateTaskLock ) {
330
+ cachedUpdateTask .updateProgress (
331
+ UpdateProgress .builder ()
332
+ .setApkFileTotalBytes (totalBytes )
333
+ .setApkBytesDownloaded (downloadedBytes )
334
+ .setUpdateStatus (status )
335
+ .build ());
336
+ }
337
+ if (showDownloadNotificationManager ) {
298
338
appDistributionNotificationsManager .updateNotification (totalBytes , downloadedBytes , status );
299
339
}
300
340
}
301
341
302
- private void postInstallationFailure (Exception e , long fileLength ) {
342
+ private void postInstallationFailure (
343
+ Exception e , long fileLength , boolean showDownloadNotificationManager ) {
303
344
if (e instanceof FirebaseAppDistributionException
304
345
&& ((FirebaseAppDistributionException ) e ).getErrorCode () == Status .INSTALLATION_CANCELED ) {
305
- postUpdateProgress (fileLength , fileLength , UpdateStatus .INSTALL_CANCELED );
346
+ postUpdateProgress (
347
+ fileLength , fileLength , UpdateStatus .INSTALL_CANCELED , showDownloadNotificationManager );
306
348
} else {
307
- postUpdateProgress (fileLength , fileLength , UpdateStatus .INSTALL_FAILED );
349
+ postUpdateProgress (
350
+ fileLength , fileLength , UpdateStatus .INSTALL_FAILED , showDownloadNotificationManager );
308
351
}
309
352
}
310
353
@@ -320,9 +363,4 @@ void setCurrentActivity(@Nullable Activity activity) {
320
363
this .currentActivity = activity ;
321
364
}
322
365
}
323
-
324
- @ RestrictTo (RestrictTo .Scope .TESTS )
325
- void setCachedUpdateTask (UpdateTaskImpl updateTask ) {
326
- this .cachedUpdateTask = updateTask ;
327
- }
328
366
}
0 commit comments