Skip to content

Commit 66d7848

Browse files
authored
Merge branch 'google:master' into apksig_8.5.1
2 parents 6070a2b + e5819d7 commit 66d7848

File tree

156 files changed

+8220
-1199
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

156 files changed

+8220
-1199
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,4 @@ https://developer.android.com/studio/command-line/bundletool
4646

4747
## Releases
4848

49-
Latest release: [1.17.0](https://github.com/google/bundletool/releases)
49+
Latest release: [1.18.0](https://github.com/google/bundletool/releases)

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
release_version = 1.17.0
1+
release_version = 1.18.0

src/main/dex_src/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Contains the source-code for any .dex files in bundletool.
2+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Source-code for java/com/android/tools/build/bundletool/archive/dex/classes.dex
2+
which is used to build APKs with build-mode ARCHIVE.
3+
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*
2+
* Copyright (C) 2021 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License
15+
*/
16+
17+
package com.google.android.archive;
18+
19+
import static java.util.concurrent.TimeUnit.SECONDS;
20+
21+
import android.annotation.SuppressLint;
22+
import android.app.Activity;
23+
import android.app.AlertDialog;
24+
import android.content.ActivityNotFoundException;
25+
import android.content.DialogInterface;
26+
import android.content.Intent;
27+
import android.content.pm.PackageManager.NameNotFoundException;
28+
import android.os.Build.VERSION;
29+
import android.os.Build.VERSION_CODES;
30+
import android.os.Bundle;
31+
import android.util.Log;
32+
import java.util.concurrent.Executors;
33+
import java.util.concurrent.ScheduledExecutorService;
34+
import java.util.concurrent.ScheduledFuture;
35+
36+
/** Activity that triggers the reactivation of an app through the app store. */
37+
public class ReactivateActivity extends Activity implements DialogInterface.OnClickListener {
38+
39+
private static final String TAG = "ReactivateActivity";
40+
41+
private static final String EXTRA_DATA = "archive.extra.data";
42+
43+
private final ScheduledExecutorService scheduledExecutorService =
44+
Executors.newScheduledThreadPool(1);
45+
46+
private String appStorePackageName;
47+
private boolean processingError;
48+
private int retryCount = 0;
49+
50+
private ScheduledFuture<?> unhibernateFuture;
51+
52+
@Override
53+
protected void onCreate(Bundle savedInstanceState) {
54+
handleSplashScreen(this);
55+
super.onCreate(savedInstanceState);
56+
appStorePackageName = getAppStorePackageName();
57+
}
58+
59+
@Override
60+
public void onResume() {
61+
super.onResume();
62+
// Ensures we don't try to send another intent immediately after the first one failed, instead
63+
// an error dialog is shown.
64+
if (processingError) {
65+
return;
66+
}
67+
startUnhibernateActivityForResult();
68+
}
69+
70+
/** Returns true if the targeted Store is installed and enabled. */
71+
private boolean isStoreInstalled() {
72+
try {
73+
return getPackageManager().getApplicationInfo(appStorePackageName, 0).enabled;
74+
} catch (NameNotFoundException e) {
75+
return false;
76+
}
77+
}
78+
79+
private AlertDialog buildErrorDialog() {
80+
AlertDialog.Builder dialog =
81+
new AlertDialog.Builder(this)
82+
.setTitle("Installation failed")
83+
.setCancelable(false)
84+
.setNeutralButton("Close", this)
85+
.setMessage(
86+
String.format(
87+
"To open %s you must first complete its download from an official app store.",
88+
getAppName()));
89+
90+
if (isStoreInstalled()) {
91+
dialog.setPositiveButton("Retry", this);
92+
}
93+
94+
return dialog.create();
95+
}
96+
97+
private String getAppName() {
98+
return getApplicationInfo().loadLabel(getPackageManager()).toString();
99+
}
100+
101+
@Override
102+
public void onClick(DialogInterface ignored, int buttonType) {
103+
processingError = false;
104+
switch (buttonType) {
105+
case DialogInterface.BUTTON_POSITIVE:
106+
startUnhibernateActivityForResult();
107+
break;
108+
case DialogInterface.BUTTON_NEUTRAL:
109+
default:
110+
// Nothing specific, just close the app.
111+
finish();
112+
break;
113+
}
114+
}
115+
116+
/**
117+
* The archived stub is built with the activity flag noHistory, so this can only be triggered if
118+
* the app store is not installed.
119+
*/
120+
@Override
121+
public void onActivityResult(int ignored1, int resultCode, Intent ignored2) {
122+
if (resultCode == Activity.RESULT_CANCELED) {
123+
Log.i(
124+
TAG,
125+
String.format(
126+
"Couldn't reach the app store %s to unarchive, retry count: %s",
127+
appStorePackageName, retryCount));
128+
if (unhibernateFuture != null && retryCount++ < 3) {
129+
unhibernateFuture =
130+
scheduledExecutorService.schedule(this::startUnhibernateActivityForResult, 5, SECONDS);
131+
} else {
132+
processingError = true;
133+
buildErrorDialog().show();
134+
unhibernateFuture = null;
135+
retryCount = 0;
136+
}
137+
} else {
138+
// This should not be reachable due to the noHistory activity flag.
139+
finish();
140+
}
141+
}
142+
143+
/**
144+
* Getting resource by id does not work because classes.dex is prebuild and
145+
* reactivation_app_store_package_name resource is added dynamically with the next available id.
146+
*/
147+
@SuppressLint("DiscouragedApi")
148+
private String getAppStorePackageName() {
149+
return getResources()
150+
.getString(
151+
getResources()
152+
.getIdentifier("reactivation_app_store_package_name", "string", getPackageName()));
153+
}
154+
155+
@SuppressLint("DiscouragedApi")
156+
private int getSplashScreenLayoutResId() {
157+
return getResources()
158+
.getIdentifier(
159+
"com_android_vending_archive_splash_screen_layout", "layout", getPackageName());
160+
}
161+
162+
private void handleSplashScreen(ReactivateActivity activity) {
163+
if (VERSION.SDK_INT < VERSION_CODES.S) {
164+
int splashLayoutResId = getSplashScreenLayoutResId();
165+
if (splashLayoutResId != 0) {
166+
activity.setContentView(splashLayoutResId);
167+
}
168+
}
169+
}
170+
171+
private void startUnhibernateActivityForResult() {
172+
Log.i(TAG, "Unarchiving package: " + getPackageName());
173+
Intent intent = new Intent();
174+
intent.setAction("com.google.android.STORE_ARCHIVE");
175+
intent.setPackage(appStorePackageName);
176+
177+
// Forward any attached data to the app store for consideration.
178+
if (getIntent() != null && getIntent().getData() != null) {
179+
intent.putExtra(EXTRA_DATA, getIntent().getData());
180+
}
181+
182+
try {
183+
startActivityForResult(intent, /* flags= */ 0);
184+
} catch (ActivityNotFoundException e) {
185+
// We handle this case in onActivityResult, because a RESULT_CANCELED is emitted.
186+
}
187+
}
188+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (C) 2021 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License
15+
*/
16+
17+
package com.google.android.archive;
18+
19+
import android.content.BroadcastReceiver;
20+
import android.content.Context;
21+
import android.content.Intent;
22+
import java.io.File;
23+
24+
/** Clears up the app's cache once it has been archived. */
25+
public class UpdateBroadcastReceiver extends BroadcastReceiver {
26+
27+
@Override
28+
public void onReceive(Context context, Intent intent) {
29+
if (intent.getAction().equals(Intent.ACTION_MY_PACKAGE_REPLACED)) {
30+
deleteDir(context.getCacheDir());
31+
}
32+
}
33+
34+
private static void deleteDir(File dir) {
35+
File[] contents = dir.listFiles();
36+
if (contents != null) {
37+
for (File file : contents) {
38+
deleteDir(file);
39+
}
40+
}
41+
dir.delete();
42+
}
43+
}

0 commit comments

Comments
 (0)