diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index f2373446924a7..0a2f057ccb699 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -141,6 +141,7 @@ applications that come with the platform
+
diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml
index eb9ec82c95199..18b86628ea4d7 100644
--- a/packages/PackageInstaller/AndroidManifest.xml
+++ b/packages/PackageInstaller/AndroidManifest.xml
@@ -15,6 +15,7 @@
+
diff --git a/packages/PackageInstaller/res/layout/uninstall_content_view.xml b/packages/PackageInstaller/res/layout/uninstall_content_view.xml
new file mode 100644
index 0000000000000..5ecb614e72097
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/uninstall_content_view.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/PackageInstaller/res/values/strings.xml b/packages/PackageInstaller/res/values/strings.xml
index 0f065ab95e2d7..1d8747a1fda6c 100644
--- a/packages/PackageInstaller/res/values/strings.xml
+++ b/packages/PackageInstaller/res/values/strings.xml
@@ -119,6 +119,8 @@
Replace this app with the factory version? All data will be removed.
Replace this app with the factory version? All data will be removed. This affects all users of this device, including those with work profiles.
+
+ Also remove %1$s of associated media files.
Running uninstalls
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
index 1c0aec18dd307..d13bb65604af4 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
@@ -50,6 +50,8 @@ public class UninstallUninstalling extends Activity implements
"com.android.packageinstaller.ACTION_UNINSTALL_COMMIT";
static final String EXTRA_APP_LABEL = "com.android.packageinstaller.extra.APP_LABEL";
+ static final String EXTRA_CLEAR_CONTRIBUTED_FILES =
+ "com.android.packageinstaller.extra.CLEAR_CONTRIBUTED_FILES";
private int mUninstallId;
private ApplicationInfo mAppInfo;
@@ -72,6 +74,8 @@ public class UninstallUninstalling extends Activity implements
if (savedInstanceState == null) {
boolean allUsers = getIntent().getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS,
false);
+ boolean clearContributedFiles = getIntent().getBooleanExtra(
+ EXTRA_CLEAR_CONTRIBUTED_FILES, false);
UserHandle user = getIntent().getParcelableExtra(Intent.EXTRA_USER);
// Show dialog, which is the whole UI
@@ -95,12 +99,15 @@ public class UninstallUninstalling extends Activity implements
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, mUninstallId,
broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ int flags = allUsers ? PackageManager.DELETE_ALL_USERS : 0;
+ flags |= clearContributedFiles ? PackageManager.DELETE_CONTRIBUTED_MEDIA : 0;
+
try {
ActivityThread.getPackageManager().getPackageInstaller().uninstall(
new VersionedPackage(mAppInfo.packageName,
PackageManager.VERSION_CODE_HIGHEST),
- getPackageName(), allUsers ? PackageManager.DELETE_ALL_USERS : 0,
- pendingIntent.getIntentSender(), user.getIdentifier());
+ getPackageName(), flags, pendingIntent.getIntentSender(),
+ user.getIdentifier());
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
index 1a01dc019bf7d..0fa8c9a688c77 100755
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
@@ -285,7 +285,7 @@ public class UninstallerActivity extends Activity {
fragment.show(ft, "dialog");
}
- public void startUninstallProgress() {
+ public void startUninstallProgress(boolean clearContributedFiles) {
boolean returnResult = getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false);
CharSequence label = mDialogInfo.appInfo.loadSafeLabel(getPackageManager());
@@ -310,6 +310,8 @@ public class UninstallerActivity extends Activity {
newIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, mDialogInfo.allUsers);
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mDialogInfo.appInfo);
newIntent.putExtra(UninstallUninstalling.EXTRA_APP_LABEL, label);
+ newIntent.putExtra(UninstallUninstalling.EXTRA_CLEAR_CONTRIBUTED_FILES,
+ clearContributedFiles);
newIntent.putExtra(PackageInstaller.EXTRA_CALLBACK, mDialogInfo.callback);
if (returnResult) {
@@ -358,12 +360,14 @@ public class UninstallerActivity extends Activity {
try {
Log.i(TAG, "Uninstalling extras=" + broadcastIntent.getExtras());
+ int flags = mDialogInfo.allUsers ? PackageManager.DELETE_ALL_USERS : 0;
+ flags |= clearContributedFiles ? PackageManager.DELETE_CONTRIBUTED_MEDIA : 0;
+
ActivityThread.getPackageManager().getPackageInstaller().uninstall(
new VersionedPackage(mDialogInfo.appInfo.packageName,
PackageManager.VERSION_CODE_HIGHEST),
- getPackageName(), mDialogInfo.allUsers
- ? PackageManager.DELETE_ALL_USERS : 0,
- pendingIntent.getIntentSender(), mDialogInfo.user.getIdentifier());
+ getPackageName(), flags, pendingIntent.getIntentSender(),
+ mDialogInfo.user.getIdentifier());
} catch (Exception e) {
notificationManager.cancel(uninstallId);
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
index e0ca74eb99c99..e4e12759211d6 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
@@ -16,6 +16,9 @@
package com.android.packageinstaller.handheld;
+import static android.text.format.Formatter.formatFileSize;
+
+import android.annotation.NonNull;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
@@ -24,14 +27,41 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Bundle;
+import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.MediaStore;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.TextView;
import com.android.packageinstaller.R;
import com.android.packageinstaller.UninstallerActivity;
+import java.io.IOException;
+import java.util.List;
+
public class UninstallAlertDialogFragment extends DialogFragment implements
DialogInterface.OnClickListener {
+ private CheckBox mClearContributedFiles;
+
+ /**
+ * Get number of bytes of the combined files contributed by the package.
+ *
+ * @param pkg The package that might have contibuted files.
+ * @param user The user the package belongs to.
+ *
+ * @return The number of bytes.
+ */
+ private long getContributedMediaSize(@NonNull String pkg, @NonNull UserHandle user) {
+ try {
+ return MediaStore.getContributedMediaSize(getContext(), pkg, user);
+ } catch (IOException e) {
+ return 0;
+ }
+ }
+
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final PackageManager pm = getActivity().getPackageManager();
@@ -76,14 +106,44 @@ public class UninstallAlertDialogFragment extends DialogFragment implements
dialogBuilder.setTitle(appLabel);
dialogBuilder.setPositiveButton(android.R.string.ok, this);
dialogBuilder.setNegativeButton(android.R.string.cancel, this);
- dialogBuilder.setMessage(messageBuilder.toString());
+
+ String pkg = dialogInfo.appInfo.packageName;
+ long contributedFileSize = 0;
+ if (dialogInfo.allUsers) {
+ List users = userManager.getUsers();
+
+ int numUsers = users.size();
+ for (int i = 0; i < numUsers; i++) {
+ UserHandle user = UserHandle.of(users.get(i).id);
+
+ contributedFileSize += getContributedMediaSize(pkg, user);
+ }
+ } else {
+ contributedFileSize = getContributedMediaSize(pkg, dialogInfo.user);
+ }
+
+ if (contributedFileSize == 0) {
+ dialogBuilder.setMessage(messageBuilder.toString());
+ } else {
+ LayoutInflater inflater = getContext().getSystemService(LayoutInflater.class);
+ ViewGroup content = (ViewGroup) inflater.inflate(R.layout.uninstall_content_view, null);
+
+ ((TextView) content.requireViewById(R.id.message)).setText(messageBuilder.toString());
+ mClearContributedFiles = content.requireViewById(R.id.checkbox);
+ mClearContributedFiles.setText(getString(R.string.uninstall_remove_contributed_files,
+ formatFileSize(getContext(), contributedFileSize)));
+
+ dialogBuilder.setView(content);
+ }
+
return dialogBuilder.create();
}
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == Dialog.BUTTON_POSITIVE) {
- ((UninstallerActivity) getActivity()).startUninstallProgress();
+ ((UninstallerActivity) getActivity()).startUninstallProgress(
+ mClearContributedFiles != null && mClearContributedFiles.isChecked());
} else {
((UninstallerActivity) getActivity()).dispatchAborted();
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/television/UninstallAlertFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/television/UninstallAlertFragment.java
index 828e5dbcfe5bb..21d25f5b030fd 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/television/UninstallAlertFragment.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/television/UninstallAlertFragment.java
@@ -99,7 +99,7 @@ public class UninstallAlertFragment extends GuidedStepFragment {
public void onGuidedActionClicked(GuidedAction action) {
if (isAdded()) {
if (action.getId() == GuidedAction.ACTION_ID_OK) {
- ((UninstallerActivity) getActivity()).startUninstallProgress();
+ ((UninstallerActivity) getActivity()).startUninstallProgress(false);
getActivity().finish();
} else {
((UninstallerActivity) getActivity()).dispatchAborted();