Skip to content

Commit c56a976

Browse files
manny-jimenezManny Jimenez
andauthored
FAD Remove chrome redirect when updating Aabs (#3075)
* FAD Adding in redirect tests * FAD Fixing copyright and other errors * FAD Responding to first round of feedback * FAD Chaniging redirect comment * FAD Chaniging redirect comment location * FAD Adding tests to ensure updateAAb and updateApk return task when called * FAD Changing testing constructor to package private Co-authored-by: Manny Jimenez <[email protected]>
1 parent a247a21 commit c56a976

File tree

4 files changed

+372
-114
lines changed

4 files changed

+372
-114
lines changed
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.appdistribution;
16+
17+
import static com.google.firebase.appdistribution.FirebaseAppDistributionException.Status.NETWORK_FAILURE;
18+
import static com.google.firebase.appdistribution.TaskUtils.safeSetTaskException;
19+
20+
import android.app.Activity;
21+
import android.content.Intent;
22+
import android.net.Uri;
23+
import androidx.annotation.GuardedBy;
24+
import androidx.annotation.NonNull;
25+
import androidx.annotation.Nullable;
26+
import com.google.firebase.appdistribution.internal.AppDistributionReleaseInternal;
27+
import java.io.IOException;
28+
import java.net.URL;
29+
import java.util.concurrent.Executor;
30+
import java.util.concurrent.Executors;
31+
import javax.net.ssl.HttpsURLConnection;
32+
33+
/** Client class that handles updateApp functionality for AABs in {@link UpdateAppClient}. */
34+
class UpdateAabClient {
35+
private static final String TAG = "UpdateAabClient:";
36+
37+
private final Executor updateExecutor;
38+
39+
@GuardedBy("updateAabLock")
40+
private UpdateTaskImpl cachedUpdateTask;
41+
42+
@GuardedBy("updateAabLock")
43+
private Activity currentActivity;
44+
45+
@GuardedBy("updateAabLock")
46+
private AppDistributionReleaseInternal aabReleaseInProgress;
47+
48+
private final Object updateAabLock = new Object();
49+
50+
public UpdateAabClient() {
51+
this(Executors.newSingleThreadExecutor());
52+
}
53+
54+
public UpdateAabClient(@NonNull Executor updateExecutor) {
55+
this.updateExecutor = updateExecutor;
56+
}
57+
58+
public UpdateTaskImpl updateAab(@NonNull AppDistributionReleaseInternal newRelease) {
59+
synchronized (updateAabLock) {
60+
if (cachedUpdateTask != null && !cachedUpdateTask.isComplete()) {
61+
return cachedUpdateTask;
62+
}
63+
64+
cachedUpdateTask = new UpdateTaskImpl();
65+
aabReleaseInProgress = newRelease;
66+
redirectToPlayForAabUpdate(newRelease.getDownloadUrl());
67+
68+
return cachedUpdateTask;
69+
}
70+
}
71+
72+
HttpsURLConnection openHttpsUrlConnection(String downloadUrl)
73+
throws FirebaseAppDistributionException {
74+
HttpsURLConnection httpsURLConnection;
75+
76+
try {
77+
URL url = new URL(downloadUrl);
78+
httpsURLConnection = (HttpsURLConnection) url.openConnection();
79+
} catch (IOException e) {
80+
throw new FirebaseAppDistributionException(
81+
Constants.ErrorMessages.NETWORK_ERROR, NETWORK_FAILURE, e);
82+
}
83+
return httpsURLConnection;
84+
}
85+
86+
private void redirectToPlayForAabUpdate(String downloadUrl) {
87+
synchronized (updateAabLock) {
88+
if (currentActivity == null) {
89+
safeSetTaskException(
90+
cachedUpdateTask,
91+
new FirebaseAppDistributionException(
92+
Constants.ErrorMessages.APP_BACKGROUNDED,
93+
FirebaseAppDistributionException.Status.DOWNLOAD_FAILURE));
94+
return;
95+
}
96+
}
97+
98+
// The 302 redirect is obtained here to open the play store directly and avoid opening chrome
99+
updateExecutor.execute(
100+
() -> {
101+
HttpsURLConnection connection;
102+
String redirect;
103+
try {
104+
connection = openHttpsUrlConnection(downloadUrl);
105+
106+
// To get url to play without redirect we do this connection
107+
connection.setInstanceFollowRedirects(false);
108+
redirect = connection.getHeaderField("Location");
109+
connection.disconnect();
110+
connection.getInputStream().close();
111+
} catch (FirebaseAppDistributionException | IOException e) {
112+
setUpdateTaskCompletionErrorWithDefault(
113+
e,
114+
new FirebaseAppDistributionException(
115+
Constants.ErrorMessages.NETWORK_ERROR,
116+
FirebaseAppDistributionException.Status.DOWNLOAD_FAILURE));
117+
return;
118+
}
119+
120+
if (!redirect.isEmpty()) {
121+
Intent updateIntent = new Intent(Intent.ACTION_VIEW);
122+
updateIntent.setData(Uri.parse(redirect));
123+
updateIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
124+
LogWrapper.getInstance().v(TAG + "Redirecting to play");
125+
126+
synchronized (updateAabLock) {
127+
currentActivity.startActivity(updateIntent);
128+
cachedUpdateTask.updateProgress(
129+
UpdateProgress.builder()
130+
.setApkBytesDownloaded(-1)
131+
.setApkFileTotalBytes(-1)
132+
.setUpdateStatus(UpdateStatus.REDIRECTED_TO_PLAY)
133+
.build());
134+
}
135+
} else {
136+
setUpdateTaskCompletionError(
137+
new FirebaseAppDistributionException(
138+
Constants.ErrorMessages.NETWORK_ERROR,
139+
FirebaseAppDistributionException.Status.DOWNLOAD_FAILURE));
140+
}
141+
});
142+
}
143+
144+
void setCurrentActivity(@Nullable Activity activity) {
145+
synchronized (updateAabLock) {
146+
this.currentActivity = activity;
147+
}
148+
}
149+
150+
private void setUpdateTaskCompletionError(FirebaseAppDistributionException e) {
151+
synchronized (updateAabLock) {
152+
safeSetTaskException(cachedUpdateTask, e);
153+
}
154+
}
155+
156+
private void setUpdateTaskCompletionErrorWithDefault(
157+
Exception e, FirebaseAppDistributionException defaultFirebaseException) {
158+
if (e instanceof FirebaseAppDistributionException) {
159+
setUpdateTaskCompletionError((FirebaseAppDistributionException) e);
160+
} else {
161+
setUpdateTaskCompletionError(defaultFirebaseException);
162+
}
163+
}
164+
165+
void tryCancelAabUpdateTask() {
166+
synchronized (updateAabLock) {
167+
safeSetTaskException(
168+
cachedUpdateTask,
169+
new FirebaseAppDistributionException(
170+
Constants.ErrorMessages.UPDATE_CANCELED,
171+
FirebaseAppDistributionException.Status.INSTALLATION_CANCELED,
172+
ReleaseUtils.convertToAppDistributionRelease(aabReleaseInProgress)));
173+
}
174+
}
175+
}

firebase-app-distribution/src/main/java/com/google/firebase/appdistribution/UpdateAppClient.java

Lines changed: 13 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,11 @@
1515
package com.google.firebase.appdistribution;
1616

1717
import static com.google.firebase.appdistribution.FirebaseAppDistributionException.Status.UPDATE_NOT_AVAILABLE;
18-
import static com.google.firebase.appdistribution.TaskUtils.safeSetTaskException;
1918

2019
import android.app.Activity;
21-
import android.content.Intent;
22-
import android.net.Uri;
23-
import androidx.annotation.GuardedBy;
2420
import androidx.annotation.NonNull;
2521
import androidx.annotation.Nullable;
22+
import androidx.annotation.VisibleForTesting;
2623
import com.google.firebase.FirebaseApp;
2724
import com.google.firebase.appdistribution.internal.AppDistributionReleaseInternal;
2825

@@ -31,23 +28,22 @@ public class UpdateAppClient {
3128

3229
private final UpdateApkClient updateApkClient;
3330
private final InstallApkClient installApkClient;
31+
private final UpdateAabClient updateAabClient;
3432
private static final String TAG = "UpdateAppClient";
3533

36-
@GuardedBy("activityLock")
37-
private Activity currentActivity;
38-
3934
private final Object activityLock = new Object();
40-
private final Object updateAabLock = new Object();
41-
42-
@GuardedBy("updateAabLock")
43-
private UpdateTaskImpl cachedAabUpdateTask;
44-
45-
@GuardedBy("updateAabLock")
46-
private AppDistributionReleaseInternal aabReleaseInProgress;
4735

4836
public UpdateAppClient(@NonNull FirebaseApp firebaseApp) {
4937
this.installApkClient = new InstallApkClient();
5038
this.updateApkClient = new UpdateApkClient(firebaseApp, installApkClient);
39+
this.updateAabClient = new UpdateAabClient();
40+
}
41+
42+
@VisibleForTesting
43+
UpdateAppClient(UpdateApkClient updateApkClient, UpdateAabClient updateAabClient) {
44+
this.installApkClient = new InstallApkClient();
45+
this.updateApkClient = updateApkClient;
46+
this.updateAabClient = updateAabClient;
5147
}
5248

5349
@NonNull
@@ -71,66 +67,19 @@ synchronized UpdateTask updateApp(
7167
}
7268

7369
if (newRelease.getBinaryType() == BinaryType.AAB) {
74-
synchronized (updateAabLock) {
75-
if (cachedAabUpdateTask != null && !cachedAabUpdateTask.isComplete()) {
76-
return cachedAabUpdateTask;
77-
}
78-
79-
cachedAabUpdateTask = new UpdateTaskImpl();
80-
aabReleaseInProgress = newRelease;
81-
redirectToPlayForAabUpdate(newRelease.getDownloadUrl());
82-
83-
return cachedAabUpdateTask;
84-
}
70+
return this.updateAabClient.updateAab(newRelease);
8571
} else {
8672
return this.updateApkClient.updateApk(newRelease, showDownloadInNotificationManager);
8773
}
8874
}
8975

90-
private void redirectToPlayForAabUpdate(String downloadUrl) {
91-
Activity currentActivity = getCurrentActivity();
92-
93-
if (currentActivity == null) {
94-
synchronized (updateAabLock) {
95-
safeSetTaskException(
96-
cachedAabUpdateTask,
97-
new FirebaseAppDistributionException(
98-
Constants.ErrorMessages.APP_BACKGROUNDED,
99-
FirebaseAppDistributionException.Status.DOWNLOAD_FAILURE));
100-
return;
101-
}
102-
}
103-
104-
Intent updateIntent = new Intent(Intent.ACTION_VIEW);
105-
Uri uri = Uri.parse(downloadUrl);
106-
updateIntent.setData(uri);
107-
updateIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
108-
currentActivity.startActivity(updateIntent);
109-
110-
synchronized (updateAabLock) {
111-
cachedAabUpdateTask.updateProgress(
112-
UpdateProgress.builder()
113-
.setApkBytesDownloaded(-1)
114-
.setApkFileTotalBytes(-1)
115-
.setUpdateStatus(UpdateStatus.REDIRECTED_TO_PLAY)
116-
.build());
117-
}
118-
}
119-
12076
void trySetInstallTaskError() {
12177
this.installApkClient.trySetInstallTaskError();
12278
}
12379

124-
@Nullable
125-
Activity getCurrentActivity() {
126-
synchronized (activityLock) {
127-
return this.currentActivity;
128-
}
129-
}
130-
13180
void setCurrentActivity(@Nullable Activity activity) {
13281
synchronized (activityLock) {
133-
this.currentActivity = activity;
82+
this.updateAabClient.setCurrentActivity(activity);
13483
this.installApkClient.setCurrentActivity(activity);
13584
}
13685
}
@@ -142,13 +91,6 @@ private UpdateTask getErrorUpdateTask(Exception e) {
14291
}
14392

14493
void tryCancelAabUpdateTask() {
145-
synchronized (updateAabLock) {
146-
safeSetTaskException(
147-
cachedAabUpdateTask,
148-
new FirebaseAppDistributionException(
149-
Constants.ErrorMessages.UPDATE_CANCELED,
150-
FirebaseAppDistributionException.Status.INSTALLATION_CANCELED,
151-
ReleaseUtils.convertToAppDistributionRelease(aabReleaseInProgress)));
152-
}
94+
this.updateAabClient.tryCancelAabUpdateTask();
15395
}
15496
}

0 commit comments

Comments
 (0)