16
16
17
17
import static com .google .firebase .appdistribution .FirebaseAppDistributionException .Status .DOWNLOAD_FAILURE ;
18
18
import static com .google .firebase .appdistribution .FirebaseAppDistributionException .Status .NETWORK_FAILURE ;
19
+ import static com .google .firebase .appdistribution .TaskUtils .combineWithResultOf ;
20
+ import static com .google .firebase .appdistribution .TaskUtils .runAsyncInTask ;
19
21
import static com .google .firebase .appdistribution .TaskUtils .safeSetTaskException ;
20
22
21
23
import android .app .Activity ;
22
- import android .content .Context ;
23
24
import android .content .Intent ;
24
25
import android .net .Uri ;
25
26
import androidx .annotation .GuardedBy ;
@@ -42,29 +43,28 @@ class AabUpdater {
42
43
private final HttpsUrlConnectionFactory httpsUrlConnectionFactory ;
43
44
private final Executor executor ;
44
45
46
+ private final Object updateAabLock = new Object ();
47
+
45
48
@ GuardedBy ("updateAabLock" )
46
49
private UpdateTaskImpl cachedUpdateTask ;
47
50
48
51
@ GuardedBy ("updateAabLock" )
49
52
private AppDistributionReleaseInternal aabReleaseInProgress ;
50
53
51
- private final Object updateAabLock = new Object ();
52
- private final Context context ;
54
+ @ GuardedBy ( "updateAabLock" )
55
+ private boolean hasBeenSentToPlayForCurrentTask = false ;
53
56
54
- AabUpdater (@ NonNull Context context ) {
57
+ AabUpdater () {
55
58
this (
56
- context ,
57
59
FirebaseAppDistributionLifecycleNotifier .getInstance (),
58
60
new HttpsUrlConnectionFactory (),
59
61
Executors .newSingleThreadExecutor ());
60
62
}
61
63
62
64
AabUpdater (
63
- @ NonNull Context context ,
64
65
@ NonNull FirebaseAppDistributionLifecycleNotifier lifecycleNotifier ,
65
66
@ NonNull HttpsUrlConnectionFactory httpsUrlConnectionFactory ,
66
67
@ NonNull Executor executor ) {
67
- this .context = context ;
68
68
this .lifecycleNotifier = lifecycleNotifier ;
69
69
this .httpsUrlConnectionFactory = httpsUrlConnectionFactory ;
70
70
lifecycleNotifier .addOnActivityStartedListener (this ::onActivityStarted );
@@ -76,9 +76,13 @@ void onActivityStarted(Activity activity) {
76
76
if (activity instanceof SignInResultActivity || activity instanceof InstallActivity ) {
77
77
return ;
78
78
}
79
- // If app resumes and aab update task is in progress, assume that installation didn't happen so
80
- // cancel the task
81
- this .tryCancelAabUpdateTask ();
79
+ // If app resumes and update is in progress, assume that installation didn't happen and cancel
80
+ // the task
81
+ synchronized (updateAabLock ) {
82
+ if (awaitingUpdateFromPlay ()) {
83
+ this .tryCancelAabUpdateTask ();
84
+ }
85
+ }
82
86
}
83
87
84
88
UpdateTaskImpl updateAab (@ NonNull AppDistributionReleaseInternal newRelease ) {
@@ -89,7 +93,18 @@ UpdateTaskImpl updateAab(@NonNull AppDistributionReleaseInternal newRelease) {
89
93
90
94
cachedUpdateTask = new UpdateTaskImpl ();
91
95
aabReleaseInProgress = newRelease ;
92
- redirectToPlayForAabUpdate (newRelease .getDownloadUrl ());
96
+ hasBeenSentToPlayForCurrentTask = false ;
97
+
98
+ // On a background thread, fetch the redirect URL and open it in the Play app
99
+ runAsyncInTask (executor , () -> fetchDownloadRedirectUrl (newRelease .getDownloadUrl ()))
100
+ .onSuccessTask (
101
+ executor ,
102
+ combineWithResultOf (executor , () -> lifecycleNotifier .getForegroundActivity ()))
103
+ .addOnSuccessListener (
104
+ executor ,
105
+ urlAndActivity ->
106
+ openRedirectUrlInPlay (urlAndActivity .first (), urlAndActivity .second ()))
107
+ .addOnFailureListener (executor , this ::setUpdateTaskCompletionError );
93
108
94
109
return cachedUpdateTask ;
95
110
}
@@ -138,38 +153,30 @@ private static boolean isRedirectResponse(int responseCode) {
138
153
return responseCode >= 300 && responseCode < 400 ;
139
154
}
140
155
141
- private void redirectToPlayForAabUpdate (String downloadUrl ) {
142
- // The 302 redirect is obtained here to open the play store directly and avoid opening chrome
143
- executor .execute ( // Execute the network calls on a background thread
144
- () -> {
145
- String redirectUrl ;
146
- try {
147
- redirectUrl = fetchDownloadRedirectUrl (downloadUrl );
148
- } catch (FirebaseAppDistributionException e ) {
149
- setUpdateTaskCompletionError (e );
150
- return ;
151
- }
152
-
153
- Intent updateIntent = new Intent (Intent .ACTION_VIEW );
154
- updateIntent .setData (Uri .parse (redirectUrl ));
155
- updateIntent .addFlags (Intent .FLAG_ACTIVITY_NEW_TASK );
156
- LogWrapper .getInstance ().v (TAG + "Redirecting to play" );
157
-
158
- synchronized (updateAabLock ) {
159
- context .startActivity (updateIntent );
160
- cachedUpdateTask .updateProgress (
161
- UpdateProgress .builder ()
162
- .setApkBytesDownloaded (-1 )
163
- .setApkFileTotalBytes (-1 )
164
- .setUpdateStatus (UpdateStatus .REDIRECTED_TO_PLAY )
165
- .build ());
166
- }
167
- });
156
+ private void openRedirectUrlInPlay (String redirectUrl , Activity hostActivity ) {
157
+ Intent updateIntent = new Intent (Intent .ACTION_VIEW );
158
+ updateIntent .setData (Uri .parse (redirectUrl ));
159
+ updateIntent .addFlags (Intent .FLAG_ACTIVITY_NEW_TASK );
160
+ LogWrapper .getInstance ().v (TAG + "Redirecting to play" );
161
+
162
+ // Launch the intent outside of the synchronized block because we don't want to risk the
163
+ // activity leaving the foreground while we wait for the lock.
164
+ hostActivity .startActivity (updateIntent );
165
+
166
+ synchronized (updateAabLock ) {
167
+ cachedUpdateTask .updateProgress (
168
+ UpdateProgress .builder ()
169
+ .setApkBytesDownloaded (-1 )
170
+ .setApkFileTotalBytes (-1 )
171
+ .setUpdateStatus (UpdateStatus .REDIRECTED_TO_PLAY )
172
+ .build ());
173
+ hasBeenSentToPlayForCurrentTask = true ;
174
+ }
168
175
}
169
176
170
- private void setUpdateTaskCompletionError (FirebaseAppDistributionException e ) {
177
+ private void setUpdateTaskCompletionError (Exception e ) {
171
178
synchronized (updateAabLock ) {
172
- safeSetTaskException (cachedUpdateTask , e );
179
+ safeSetTaskException (cachedUpdateTask , FirebaseAppDistributionException . wrap ( e ) );
173
180
}
174
181
}
175
182
@@ -183,4 +190,12 @@ void tryCancelAabUpdateTask() {
183
190
ReleaseUtils .convertToAppDistributionRelease (aabReleaseInProgress )));
184
191
}
185
192
}
193
+
194
+ private boolean awaitingUpdateFromPlay () {
195
+ synchronized (updateAabLock ) {
196
+ return cachedUpdateTask != null
197
+ && !cachedUpdateTask .isComplete ()
198
+ && hasBeenSentToPlayForCurrentTask ;
199
+ }
200
+ }
186
201
}
0 commit comments