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 Original line 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>
    <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] -->
    <!-- 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>
    <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] -->
    <!-- Label for the notification channel containing notifications for current uninstall operations [CHAR LIMIT=40] -->
    <string name="uninstalling_notification_channel">Running uninstalls</string>
    <string name="uninstalling_notification_channel">Running uninstalls</string>
@@ -137,6 +141,8 @@
    <string name="uninstall_failed">Uninstall unsuccessful.</string>
    <string name="uninstall_failed">Uninstall unsuccessful.</string>
    <!-- [CHAR LIMIT=100] -->
    <!-- [CHAR LIMIT=100] -->
    <string name="uninstall_failed_app">Uninstalling <xliff:g id="package_label">%1$s</xliff:g> unsuccessful.</string>
    <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
    <!-- String presented to the user when uninstalling a package failed because the target package
        is a current device administrator [CHAR LIMIT=80] -->
        is a current device administrator [CHAR LIMIT=80] -->
    <string name="uninstall_failed_device_policy_manager">Can\'t uninstall active device admin
    <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.
        TV or loss of data that may result from its use.
    </string>
    </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] -->
    <!-- Label for button to continue install of an app whose source cannot be identified [CHAR LIMIT=40] -->
    <string name="anonymous_source_continue">Continue</string>
    <string name="anonymous_source_continue">Continue</string>


+31 −2
Original line number Original line Diff line number Diff line
@@ -33,8 +33,10 @@ import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.content.pm.VersionedPackage;
import android.os.Bundle;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import android.util.Log;
import android.widget.Toast;
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_APP_LABEL = "com.android.packageinstaller.extra.APP_LABEL";
    static final String EXTRA_KEEP_DATA = "com.android.packageinstaller.extra.KEEP_DATA";
    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 int mUninstallId;
    private ApplicationInfo mAppInfo;
    private ApplicationInfo mAppInfo;
@@ -76,6 +79,18 @@ public class UninstallUninstalling extends Activity implements
                boolean keepData = getIntent().getBooleanExtra(EXTRA_KEEP_DATA, false);
                boolean keepData = getIntent().getBooleanExtra(EXTRA_KEEP_DATA, false);
                UserHandle user = getIntent().getParcelableExtra(Intent.EXTRA_USER);
                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
                // Show dialog, which is the whole UI
                FragmentTransaction transaction = getFragmentManager().beginTransaction();
                FragmentTransaction transaction = getFragmentManager().beginTransaction();
                Fragment prev = getFragmentManager().findFragmentByTag("dialog");
                Fragment prev = getFragmentManager().findFragmentByTag("dialog");
@@ -83,6 +98,9 @@ public class UninstallUninstalling extends Activity implements
                    transaction.remove(prev);
                    transaction.remove(prev);
                }
                }
                DialogFragment dialog = new UninstallUninstallingFragment();
                DialogFragment dialog = new UninstallUninstallingFragment();
                Bundle args = new Bundle();
                args.putBoolean(EXTRA_IS_CLONE_USER, isCloneUser);
                dialog.setArguments(args);
                dialog.setCancelable(false);
                dialog.setCancelable(false);
                dialog.show(transaction, "dialog");
                dialog.show(transaction, "dialog");


@@ -176,9 +194,20 @@ public class UninstallUninstalling extends Activity implements
        public Dialog onCreateDialog(Bundle savedInstanceState) {
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity());
            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);
            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,
                dialogBuilder.setMessage(getActivity().getString(R.string.uninstalling_app,
                        ((UninstallUninstalling) getActivity()).mLabel));
                        ((UninstallUninstalling) getActivity()).mLabel));
            }


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


        final boolean isUpdate =
        final boolean isUpdate =
                ((dialogInfo.appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
                ((dialogInfo.appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
@@ -144,16 +145,36 @@ public class UninstallAlertDialogFragment extends DialogFragment implements
                    messageBuilder.append(
                    messageBuilder.append(
                            getString(R.string.uninstall_application_text_current_user_work_profile,
                            getString(R.string.uninstall_application_text_current_user_work_profile,
                                    userInfo.name));
                                    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 {
                } else {
                    messageBuilder.append(
                    messageBuilder.append(
                            getString(R.string.uninstall_application_text_user, userInfo.name));
                            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 {
                } else {
                    messageBuilder.append(getString(R.string.uninstall_application_text));
                    messageBuilder.append(getString(R.string.uninstall_application_text));
                }
                }
            }
            }
        }


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


@@ -192,6 +213,42 @@ public class UninstallAlertDialogFragment extends DialogFragment implements
        return dialogBuilder.create();
        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
    @Override
    public void onClick(DialogInterface dialog, int which) {
    public void onClick(DialogInterface dialog, int which) {
        if (which == Dialog.BUTTON_POSITIVE) {
        if (which == Dialog.BUTTON_POSITIVE) {