14
14
15
15
package com .google .firebase .appdistribution ;
16
16
17
+ import static com .google .firebase .appdistribution .FirebaseAppDistributionException .Status ;
17
18
import static com .google .firebase .appdistribution .FirebaseAppDistributionException .Status .NETWORK_FAILURE ;
18
19
19
20
import android .app .Activity ;
20
21
import android .content .Context ;
21
22
import android .content .Intent ;
22
23
import android .util .Log ;
23
24
import androidx .annotation .NonNull ;
25
+ import androidx .annotation .RestrictTo ;
24
26
import androidx .annotation .VisibleForTesting ;
25
27
import com .google .android .gms .tasks .CancellationTokenSource ;
26
28
import com .google .android .gms .tasks .Task ;
@@ -46,6 +48,7 @@ class UpdateApkClient {
46
48
private final Executor downloadExecutor ;
47
49
private TaskCompletionSource <Void > installTaskCompletionSource ;
48
50
private final FirebaseApp firebaseApp ;
51
+ private UpdateTaskImpl cachedUpdateTask ;
49
52
50
53
public UpdateApkClient (@ NonNull FirebaseApp firebaseApp ) {
51
54
this .downloadExecutor = Executors .newSingleThreadExecutor ();
@@ -57,51 +60,47 @@ public void updateApk(
57
60
@ NonNull String downloadUrl ,
58
61
@ NonNull Activity currentActivity ) {
59
62
60
- downloadApk (downloadUrl , updateTask )
63
+ this .cachedUpdateTask = updateTask ;
64
+ downloadApk (downloadUrl )
61
65
.addOnSuccessListener (
62
66
downloadExecutor ,
63
67
file ->
64
68
install (file .getPath (), currentActivity )
65
- .addOnSuccessListener (
66
- unused -> {
67
- postUpdateProgress (
68
- updateTask , file .length (), file .length (), UpdateStatus .DOWNLOADED );
69
- updateTask .setResult ();
70
- })
71
69
.addOnFailureListener (
72
- e ->
73
- setTaskCompletionErrorWithDefault (
74
- updateTask ,
75
- e ,
76
- new FirebaseAppDistributionException (
77
- Constants .ErrorMessages .NETWORK_ERROR ,
78
- FirebaseAppDistributionException .Status .INSTALLATION_FAILURE ))))
70
+ e -> {
71
+ postInstallationFailure (e , file .length ());
72
+ setTaskCompletionErrorWithDefault (
73
+ e ,
74
+ new FirebaseAppDistributionException (
75
+ Constants .ErrorMessages .NETWORK_ERROR ,
76
+ FirebaseAppDistributionException .Status .INSTALLATION_FAILURE ));
77
+ }))
79
78
.addOnFailureListener (
80
79
downloadExecutor ,
81
- e ->
82
- setTaskCompletionErrorWithDefault (
83
- updateTask ,
84
- e ,
85
- new FirebaseAppDistributionException (
86
- Constants . ErrorMessages . NETWORK_ERROR ,
87
- FirebaseAppDistributionException . Status . DOWNLOAD_FAILURE )) );
80
+ e -> {
81
+ setTaskCompletionErrorWithDefault (
82
+ e ,
83
+ new FirebaseAppDistributionException (
84
+ Constants . ErrorMessages . NETWORK_ERROR ,
85
+ FirebaseAppDistributionException . Status . DOWNLOAD_FAILURE ));
86
+ } );
88
87
}
89
88
90
89
@ VisibleForTesting
91
90
@ NonNull
92
- Task <File > downloadApk (@ NonNull String downloadUrl , UpdateTaskImpl updateTask ) {
91
+ Task <File > downloadApk (@ NonNull String downloadUrl ) {
93
92
if (downloadTaskCompletionSource != null
94
93
&& !downloadTaskCompletionSource .getTask ().isComplete ()) {
95
94
return downloadTaskCompletionSource .getTask ();
96
95
}
97
96
98
97
downloadTaskCompletionSource = new TaskCompletionSource <>();
99
98
100
- makeApkDownloadRequest (downloadUrl , updateTask );
99
+ makeApkDownloadRequest (downloadUrl );
101
100
return downloadTaskCompletionSource .getTask ();
102
101
}
103
102
104
- private void makeApkDownloadRequest (@ NonNull String downloadUrl , UpdateTaskImpl updateTask ) {
103
+ private void makeApkDownloadRequest (@ NonNull String downloadUrl ) {
105
104
downloadExecutor .execute (
106
105
() -> {
107
106
try {
@@ -114,9 +113,9 @@ private void makeApkDownloadRequest(@NonNull String downloadUrl, UpdateTaskImpl
114
113
FirebaseAppDistributionException .Status .DOWNLOAD_FAILURE ));
115
114
} else {
116
115
long responseLength = connection .getContentLength ();
117
- postUpdateProgress (updateTask , responseLength , 0 , UpdateStatus .PENDING );
116
+ postUpdateProgress (responseLength , 0 , UpdateStatus .PENDING );
118
117
String fileName = getApplicationName () + ".apk" ;
119
- downloadToDisk (connection .getInputStream (), responseLength , fileName , updateTask );
118
+ downloadToDisk (connection .getInputStream (), responseLength , fileName );
120
119
}
121
120
} catch (IOException | FirebaseAppDistributionException e ) {
122
121
setDownloadTaskCompletionErrorWithDefault (
@@ -128,36 +127,34 @@ private void makeApkDownloadRequest(@NonNull String downloadUrl, UpdateTaskImpl
128
127
});
129
128
}
130
129
131
- private void downloadToDisk (
132
- InputStream input , long totalSize , String fileName , UpdateTaskImpl updateTask ) {
130
+ private void downloadToDisk (InputStream input , long totalSize , String fileName ) {
133
131
134
132
File apkFile = getApkFileForApp (fileName );
135
133
apkFile .delete ();
134
+ long bytesDownloaded = 0 ;
136
135
try (BufferedOutputStream outputStream =
137
136
new BufferedOutputStream (
138
137
firebaseApp .getApplicationContext ().openFileOutput (fileName , Context .MODE_PRIVATE ))) {
139
138
140
139
byte [] data = new byte [8 * 1024 ];
141
140
int readSize = input .read (data );
142
- long downloadedSize = 0 ;
143
141
long lastMsUpdated = 0 ;
144
142
145
143
while (readSize != -1 ) {
146
144
outputStream .write (data , 0 , readSize );
147
- downloadedSize += readSize ;
145
+ bytesDownloaded += readSize ;
148
146
readSize = input .read (data );
149
147
150
148
// update progress logic for onProgressListener
151
149
long currentTimeMs = System .currentTimeMillis ();
152
150
if (currentTimeMs - lastMsUpdated > UPDATE_INTERVAL_MS ) {
153
151
lastMsUpdated = currentTimeMs ;
154
- postUpdateProgress (updateTask , totalSize , downloadedSize , UpdateStatus .DOWNLOADING );
152
+ postUpdateProgress (totalSize , bytesDownloaded , UpdateStatus .DOWNLOADING );
155
153
}
156
154
}
157
- // completion
158
- postUpdateProgress (updateTask , totalSize , downloadedSize , UpdateStatus .DOWNLOADED );
159
155
160
156
} catch (IOException e ) {
157
+ postUpdateProgress (totalSize , bytesDownloaded , UpdateStatus .DOWNLOAD_FAILED );
161
158
setDownloadTaskCompletionError (
162
159
new FirebaseAppDistributionException (
163
160
Constants .ErrorMessages .NETWORK_ERROR ,
@@ -168,12 +165,16 @@ private void downloadToDisk(
168
165
// check that file is actual JAR
169
166
new JarFile (apkFile );
170
167
} catch (Exception e ) {
168
+ postUpdateProgress (totalSize , bytesDownloaded , UpdateStatus .DOWNLOAD_FAILED );
171
169
setDownloadTaskCompletionError (
172
170
new FirebaseAppDistributionException (
173
171
Constants .ErrorMessages .NETWORK_ERROR ,
174
172
FirebaseAppDistributionException .Status .DOWNLOAD_FAILURE ));
175
173
}
176
174
175
+ // completion
176
+ postUpdateProgress (totalSize , totalSize , UpdateStatus .DOWNLOADED );
177
+
177
178
downloadTaskCompletionSource .setResult (apkFile );
178
179
}
179
180
@@ -235,6 +236,7 @@ private Task<Void> install(String path, Activity currentActivity) {
235
236
void setInstallationResult (int resultCode ) {
236
237
if (resultCode == Activity .RESULT_OK ) {
237
238
installTaskCompletionSource .setResult (null );
239
+ cachedUpdateTask .setResult ();
238
240
} else if (resultCode == Activity .RESULT_CANCELED ) {
239
241
installTaskCompletionSource .setException (
240
242
new FirebaseAppDistributionException (
@@ -248,31 +250,41 @@ void setInstallationResult(int resultCode) {
248
250
}
249
251
}
250
252
251
- private void setTaskCompletionError (
252
- UpdateTaskImpl updateTask , FirebaseAppDistributionException e ) {
253
- if (updateTask != null && !updateTask .isComplete ()) {
254
- updateTask .setException (e );
253
+ private void setTaskCompletionError (FirebaseAppDistributionException e ) {
254
+ if (cachedUpdateTask != null && !cachedUpdateTask .isComplete ()) {
255
+ cachedUpdateTask .setException (e );
255
256
}
256
257
}
257
258
258
259
private void setTaskCompletionErrorWithDefault (
259
- UpdateTaskImpl updateTask ,
260
- Exception e ,
261
- FirebaseAppDistributionException defaultFirebaseException ) {
260
+ Exception e , FirebaseAppDistributionException defaultFirebaseException ) {
262
261
if (e instanceof FirebaseAppDistributionException ) {
263
- setTaskCompletionError (updateTask , (FirebaseAppDistributionException ) e );
262
+ setTaskCompletionError ((FirebaseAppDistributionException ) e );
264
263
} else {
265
- setTaskCompletionError (updateTask , defaultFirebaseException );
264
+ setTaskCompletionError (defaultFirebaseException );
266
265
}
267
266
}
268
267
269
- private void postUpdateProgress (
270
- UpdateTaskImpl updateTask , long totalBytes , long downloadedBytes , UpdateStatus status ) {
271
- updateTask .updateProgress (
268
+ private void postUpdateProgress (long totalBytes , long downloadedBytes , UpdateStatus status ) {
269
+ cachedUpdateTask .updateProgress (
272
270
UpdateProgress .builder ()
273
271
.setApkFileTotalBytes (totalBytes )
274
272
.setApkBytesDownloaded (downloadedBytes )
275
273
.setUpdateStatus (status )
276
274
.build ());
277
275
}
276
+
277
+ private void postInstallationFailure (Exception e , long fileLength ) {
278
+ if (e instanceof FirebaseAppDistributionException
279
+ && ((FirebaseAppDistributionException ) e ).getErrorCode () == Status .INSTALLATION_CANCELED ) {
280
+ postUpdateProgress (fileLength , fileLength , UpdateStatus .INSTALL_CANCELED );
281
+ } else {
282
+ postUpdateProgress (fileLength , fileLength , UpdateStatus .INSTALL_FAILED );
283
+ }
284
+ }
285
+
286
+ @ RestrictTo (RestrictTo .Scope .TESTS )
287
+ void setCachedUpdateTask (UpdateTaskImpl updateTask ) {
288
+ this .cachedUpdateTask = updateTask ;
289
+ }
278
290
}
0 commit comments