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();