Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee4078d6 authored by Ankita Vyas's avatar Ankita Vyas Committed by Android (Google) Code Review
Browse files

Merge "Include clone app's presence in uninstall dialogues."

parents d1a89f56 67c25db0
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -119,6 +119,10 @@
    <string name="uninstall_update_text_multiuser">Replace this app with the factory version? All data will be removed. This affects all users of this device, including those with work profiles.</string>
    <!-- Label of a checkbox that allows to keep the data (e.g. files, settings) of the app on uninstall [CHAR LIMIT=none] -->
    <string name="uninstall_keep_data">Keep <xliff:g id="size" example="1.5MB">%1$s</xliff:g> of app data.</string>
    <!--  [CHAR LIMIT=none] -->
    <string name="uninstall_application_text_current_user_clone_profile">Do you want to delete this app?</string>
    <!--  [CHAR LIMIT=none] -->
    <string name="uninstall_application_text_with_clone_instance">Do you want to uninstall this app? <xliff:g id="package_label">%1$s</xliff:g> clone will also be deleted.</string>

    <!-- Label for the notification channel containing notifications for current uninstall operations [CHAR LIMIT=40] -->
    <string name="uninstalling_notification_channel">Running uninstalls</string>
@@ -137,6 +141,8 @@
    <string name="uninstall_failed">Uninstall unsuccessful.</string>
    <!-- [CHAR LIMIT=100] -->
    <string name="uninstall_failed_app">Uninstalling <xliff:g id="package_label">%1$s</xliff:g> unsuccessful.</string>
    <!-- [CHAR LIMIT=100] -->
    <string name="uninstalling_cloned_app">Deleting <xliff:g id="package_label">%1$s</xliff:g> clone\u2026</string>
    <!-- String presented to the user when uninstalling a package failed because the target package
        is a current device administrator [CHAR LIMIT=80] -->
    <string name="uninstall_failed_device_policy_manager">Can\'t uninstall active device admin
@@ -219,6 +225,9 @@
        TV or loss of data that may result from its use.
    </string>

    <!-- Label for cloned app in uninstall dialogue [CHAR LIMIT=40] -->
    <string name="cloned_app_label"><xliff:g id="package_label">%1$s</xliff:g> Clone</string>

    <!-- Label for button to continue install of an app whose source cannot be identified [CHAR LIMIT=40] -->
    <string name="anonymous_source_continue">Continue</string>

+31 −2
Original line number Diff line number Diff line
@@ -33,8 +33,10 @@ import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import android.widget.Toast;

@@ -51,6 +53,7 @@ public class UninstallUninstalling extends Activity implements

    static final String EXTRA_APP_LABEL = "com.android.packageinstaller.extra.APP_LABEL";
    static final String EXTRA_KEEP_DATA = "com.android.packageinstaller.extra.KEEP_DATA";
    public static final String EXTRA_IS_CLONE_USER = "isCloneUser";

    private int mUninstallId;
    private ApplicationInfo mAppInfo;
@@ -76,6 +79,18 @@ public class UninstallUninstalling extends Activity implements
                boolean keepData = getIntent().getBooleanExtra(EXTRA_KEEP_DATA, false);
                UserHandle user = getIntent().getParcelableExtra(Intent.EXTRA_USER);

                boolean isCloneUser = false;
                if (user == null) {
                    user = Process.myUserHandle();
                }

                UserManager customUserManager = UninstallUninstalling.this
                        .createContextAsUser(UserHandle.of(user.getIdentifier()), 0)
                        .getSystemService(UserManager.class);
                if (customUserManager.isUserOfType(UserManager.USER_TYPE_PROFILE_CLONE)) {
                    isCloneUser = true;
                }

                // Show dialog, which is the whole UI
                FragmentTransaction transaction = getFragmentManager().beginTransaction();
                Fragment prev = getFragmentManager().findFragmentByTag("dialog");
@@ -83,6 +98,9 @@ public class UninstallUninstalling extends Activity implements
                    transaction.remove(prev);
                }
                DialogFragment dialog = new UninstallUninstallingFragment();
                Bundle args = new Bundle();
                args.putBoolean(EXTRA_IS_CLONE_USER, isCloneUser);
                dialog.setArguments(args);
                dialog.setCancelable(false);
                dialog.show(transaction, "dialog");

@@ -176,9 +194,20 @@ public class UninstallUninstalling extends Activity implements
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity());

            Bundle bundle = getArguments();
            boolean isCloneUser = false;
            if (bundle != null) {
                isCloneUser = bundle.getBoolean(EXTRA_IS_CLONE_USER);
            }

            dialogBuilder.setCancelable(false);
            if (isCloneUser) {
                dialogBuilder.setMessage(getActivity().getString(R.string.uninstalling_cloned_app,
                        ((UninstallUninstalling) getActivity()).mLabel));
            } else {
                dialogBuilder.setMessage(getActivity().getString(R.string.uninstalling_app,
                        ((UninstallUninstalling) getActivity()).mLabel));
            }

            Dialog dialog = dialogBuilder.create();
            dialog.setCanceledOnTouchOutside(false);
+59 −2
Original line number Diff line number Diff line
@@ -123,6 +123,7 @@ public class UninstallAlertDialogFragment extends DialogFragment implements
                messageBuilder.append(" ").append(appLabel).append(".\n\n");
            }
        }
        boolean isClonedApp = false;

        final boolean isUpdate =
                ((dialogInfo.appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
@@ -144,16 +145,36 @@ public class UninstallAlertDialogFragment extends DialogFragment implements
                    messageBuilder.append(
                            getString(R.string.uninstall_application_text_current_user_work_profile,
                                    userInfo.name));
                } else if (userInfo.isCloneProfile()
                        && userInfo.profileGroupId == myUserHandle.getIdentifier()) {
                    isClonedApp = true;
                    messageBuilder.append(getString(
                            R.string.uninstall_application_text_current_user_clone_profile));
                } else {
                    messageBuilder.append(
                            getString(R.string.uninstall_application_text_user, userInfo.name));
                }
            } else if (isCloneProfile(myUserHandle)) {
                isClonedApp = true;
                messageBuilder.append(getString(
                        R.string.uninstall_application_text_current_user_clone_profile));
            } else {
                if (Process.myUserHandle().equals(UserHandle.SYSTEM)
                        && hasClonedInstance(dialogInfo.appInfo.packageName)) {
                    messageBuilder.append(getString(
                            R.string.uninstall_application_text_with_clone_instance,
                            appLabel));
                } else {
                    messageBuilder.append(getString(R.string.uninstall_application_text));
                }
            }
        }

        if (isClonedApp) {
            dialogBuilder.setTitle(getString(R.string.cloned_app_label, appLabel));
        } else {
            dialogBuilder.setTitle(appLabel);
        }
        dialogBuilder.setPositiveButton(android.R.string.ok, this);
        dialogBuilder.setNegativeButton(android.R.string.cancel, this);

@@ -192,6 +213,42 @@ public class UninstallAlertDialogFragment extends DialogFragment implements
        return dialogBuilder.create();
    }

    private boolean isCloneProfile(UserHandle userHandle) {
        UserManager customUserManager = getContext()
                .createContextAsUser(UserHandle.of(userHandle.getIdentifier()), 0)
                .getSystemService(UserManager.class);
        if (customUserManager.isUserOfType(UserManager.USER_TYPE_PROFILE_CLONE)) {
            return true;
        }
        return false;
    }

    private boolean hasClonedInstance(String packageName) {
        // Check if clone user is present on the device.
        UserHandle cloneUser = null;
        UserManager userManager = getContext().getSystemService(UserManager.class);
        List<UserHandle> profiles = userManager.getUserProfiles();
        for (UserHandle userHandle : profiles) {
            if (!Process.myUserHandle().equals(UserHandle.SYSTEM) && isCloneProfile(userHandle)) {
                cloneUser = userHandle;
                break;
            }
        }

        // Check if another instance of given package exists in clone user profile.
        if (cloneUser != null) {
            try {
                if (getContext().getPackageManager()
                        .getPackageUidAsUser(packageName, cloneUser.getIdentifier()) > 0) {
                    return true;
                }
            } catch (PackageManager.NameNotFoundException e) {
                return false;
            }
        }
        return false;
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        if (which == Dialog.BUTTON_POSITIVE) {