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

Commit b12714e6 authored by Himanshu Gupta's avatar Himanshu Gupta
Browse files

Adding custom text for Private Space app uninstall.

A similar change was merged as ag/25450443, this
is the equivalent of same in UninstallRepositary.

Bug: 319250810
Test: Manual
Change-Id: I733eec3f1f7bdc7edbcac885c853218a8b2d5f74
parent 12be52d0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -11053,6 +11053,7 @@ package android.os {
    field public static final String USER_TYPE_FULL_SYSTEM = "android.os.usertype.full.SYSTEM";
    field public static final String USER_TYPE_PROFILE_CLONE = "android.os.usertype.profile.CLONE";
    field public static final String USER_TYPE_PROFILE_MANAGED = "android.os.usertype.profile.MANAGED";
    field @FlaggedApi("android.os.allow_private_profile") public static final String USER_TYPE_PROFILE_PRIVATE = "android.os.usertype.profile.PRIVATE";
    field public static final String USER_TYPE_SYSTEM_HEADLESS = "android.os.usertype.system.HEADLESS";
  }
+0 −1
Original line number Diff line number Diff line
@@ -2454,7 +2454,6 @@ package android.os {
    method public boolean isVisibleBackgroundUsersOnDefaultDisplaySupported();
    method public boolean isVisibleBackgroundUsersSupported();
    method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo preCreateUser(@NonNull String) throws android.os.UserManager.UserOperationException;
    field @FlaggedApi("android.os.allow_private_profile") public static final String USER_TYPE_PROFILE_PRIVATE = "android.os.usertype.profile.PRIVATE";
  }

  public final class VibrationAttributes implements android.os.Parcelable {
+5 −2
Original line number Diff line number Diff line
@@ -180,11 +180,14 @@ public class UserManager {


    /**
     * User type representing a private profile.
     * User type representing a private profile. Private profile is a user profile that can be used
     * as an alternative user-space to install and use sensitive apps.
     * UI surfaces can adopt an alternative strategy to show apps belonging to this profile, in line
     * with their sensitive nature.
     * @hide
     */
    @FlaggedApi(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE)
    @TestApi
    @SystemApi
    public static final String USER_TYPE_PROFILE_PRIVATE = "android.os.usertype.profile.PRIVATE";

    /**
+97 −83
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.content.pm.VersionedPackage
import android.graphics.drawable.Icon
import android.os.Build
import android.os.Bundle
import android.os.Flags
import android.os.Process
import android.os.UserHandle
import android.os.UserManager
@@ -97,16 +98,17 @@ class UninstallRepository(private val context: Context) {
            }
        }

        if (getMaxTargetSdkVersionForUid(context, callingUid) >= Build.VERSION_CODES.P
            && !isPermissionGranted(
        if (getMaxTargetSdkVersionForUid(context, callingUid) >= Build.VERSION_CODES.P &&
            !isPermissionGranted(
                context, Manifest.permission.REQUEST_DELETE_PACKAGES, callingUid
            )
            && !isPermissionGranted(context, Manifest.permission.DELETE_PACKAGES, callingUid)
            ) &&
            !isPermissionGranted(context, Manifest.permission.DELETE_PACKAGES, callingUid)
        ) {
            Log.e(
                LOG_TAG, "Uid " + callingUid + " does not have "
                    + Manifest.permission.REQUEST_DELETE_PACKAGES + " or "
                    + Manifest.permission.DELETE_PACKAGES
                LOG_TAG,
                "Uid " + callingUid + " does not have " +
                    Manifest.permission.REQUEST_DELETE_PACKAGES + " or " +
                    Manifest.permission.DELETE_PACKAGES
            )
            return UninstallAborted(UninstallAborted.ABORT_REASON_GENERIC_ERROR)
        }
@@ -138,8 +140,9 @@ class UninstallRepository(private val context: Context) {
            val profiles = userManager!!.userProfiles
            if (!profiles.contains(uninstalledUser)) {
                Log.e(
                    LOG_TAG, "User " + Process.myUserHandle() + " can't request uninstall "
                        + "for user " + uninstalledUser
                    LOG_TAG,
                    "User " + Process.myUserHandle() + " can't request uninstall " +
                        "for user " + uninstalledUser
                )
                return UninstallAborted(UninstallAborted.ABORT_REASON_USER_NOT_ALLOWED)
            }
@@ -202,9 +205,13 @@ class UninstallRepository(private val context: Context) {
        val isSingleUser = isSingleUser()

        if (isUpdate) {
            messageBuilder.append(context.getString(
                    if (isSingleUser) R.string.uninstall_update_text
                    else R.string.uninstall_update_text_multiuser
            messageBuilder.append(
                context.getString(
                    if (isSingleUser) {
                        R.string.uninstall_update_text
                    } else {
                        R.string.uninstall_update_text_multiuser
                    }
                )
            )
        } else if (uninstallFromAllUsers && !isSingleUser) {
@@ -214,42 +221,42 @@ class UninstallRepository(private val context: Context) {
            val customUserManager = context.createContextAsUser(uninstalledUser!!, 0)
                .getSystemService(UserManager::class.java)
            val userName = customUserManager!!.userName

            val uninstalledUserType = getUninstalledUserType(myUserHandle, uninstalledUser!!)
            val messageString: String
            when (uninstalledUserType) {
                UserManager.USER_TYPE_PROFILE_MANAGED -> {
            var messageString = context.getString(
                    R.string.uninstall_application_text_user,
                userName
            )
            if (userManager!!.isSameProfileGroup(myUserHandle, uninstalledUser!!)) {
                if (customUserManager!!.isManagedProfile()) {
                    messageString = context.getString(
                            R.string.uninstall_application_text_current_user_work_profile, userName
                    )
                }

                UserManager.USER_TYPE_PROFILE_CLONE -> {
                } else if (customUserManager!!.isCloneProfile()){
                    isClonedApp = true
                    messageString = context.getString(
                            R.string.uninstall_application_text_current_user_clone_profile
                    )
                }

                else -> {
                } else if (Flags.allowPrivateProfile() && customUserManager!!.isPrivateProfile()) {
                    // TODO(b/324244123): Get these Strings from a User Property API.
                    messageString = context.getString(
                        R.string.uninstall_application_text_user, userName
                            R.string.uninstall_application_text_current_user_private_profile
                    )
                }

            }
            messageBuilder.append(messageString)
        } else if (isCloneProfile(uninstalledUser!!)) {
            isClonedApp = true
            messageBuilder.append(context.getString(
            messageBuilder.append(
                context.getString(
                    R.string.uninstall_application_text_current_user_clone_profile
                )
            )
        } else if (myUserHandle == UserHandle.SYSTEM
            && hasClonedInstance(targetAppInfo!!.packageName)
        } else if (myUserHandle == UserHandle.SYSTEM &&
            hasClonedInstance(targetAppInfo!!.packageName)
        ) {
            messageBuilder.append(context.getString(
                    R.string.uninstall_application_text_with_clone_instance, targetAppLabel
            messageBuilder.append(
                context.getString(
                    R.string.uninstall_application_text_with_clone_instance,
                    targetAppLabel
                )
            )
        } else {
@@ -296,31 +303,6 @@ class UninstallRepository(private val context: Context) {
        return userCount == 1 || (UserManager.isHeadlessSystemUserMode() && userCount == 2)
    }

    /**
     * Returns the type of the user from where an app is being uninstalled. We are concerned with
     * only USER_TYPE_PROFILE_MANAGED and USER_TYPE_PROFILE_CLONE and whether the user and profile
     * belong to the same profile group.
     */
    private fun getUninstalledUserType(
        myUserHandle: UserHandle,
        uninstalledUserHandle: UserHandle
    ): String? {
        if (!userManager!!.isSameProfileGroup(myUserHandle, uninstalledUserHandle)) {
            return null
        }
        val customUserManager = context.createContextAsUser(uninstalledUserHandle, 0)
            .getSystemService(UserManager::class.java)
        val userTypes =
            arrayOf(UserManager.USER_TYPE_PROFILE_MANAGED, UserManager.USER_TYPE_PROFILE_CLONE)

        for (userType in userTypes) {
            if (customUserManager!!.isUserOfType(userType)) {
                return userType
            }
        }
        return null
    }

    private fun hasClonedInstance(packageName: String): Boolean {
        // Check if clone user is present on the device.
        var cloneUser: UserHandle? = null
@@ -334,8 +316,8 @@ class UninstallRepository(private val context: Context) {
        }
        // Check if another instance of given package exists in clone user profile.
        return try {
            cloneUser != null
                && packageManager.getPackageUidAsUser(
            cloneUser != null &&
                packageManager.getPackageUidAsUser(
                packageName, PackageManager.PackageInfoFlags.of(0), cloneUser.identifier
                ) > 0
        } catch (e: PackageManager.NameNotFoundException) {
@@ -382,7 +364,9 @@ class UninstallRepository(private val context: Context) {
        val storageStatsManager = context.getSystemService(StorageStatsManager::class.java)
        try {
            val stats = storageStatsManager!!.queryStatsForPackage(
                packageManager.getApplicationInfo(pkg, 0).storageUuid, pkg, user
                packageManager.getApplicationInfo(pkg, 0).storageUuid,
                pkg,
                user
            )
            return stats.getDataBytes()
        } catch (e: Exception) {
@@ -423,17 +407,24 @@ class UninstallRepository(private val context: Context) {
        broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, uninstallId)
        broadcastIntent.setPackage(context.packageName)
        val pendingIntent = PendingIntent.getBroadcast(
            context, uninstallId, broadcastIntent,
            context,
            uninstallId,
            broadcastIntent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
        )
        if (!startUninstall(
                targetPackageName!!, uninstalledUser!!, pendingIntent, uninstallFromAllUsers,
                targetPackageName!!,
                uninstalledUser!!,
                pendingIntent,
                uninstallFromAllUsers,
                keepData
            )
        ) {
            handleUninstallResult(
                PackageInstaller.STATUS_FAILURE,
                PackageManager.DELETE_FAILED_INTERNAL_ERROR, null, 0
                PackageManager.DELETE_FAILED_INTERNAL_ERROR,
                null,
                0
            )
        }
    }
@@ -474,9 +465,14 @@ class UninstallRepository(private val context: Context) {

        // Caller did not want the result back. So, we either show a Toast, or a Notification.
        if (status == PackageInstaller.STATUS_SUCCESS) {
            val statusMessage = if (isClonedApp) context.getString(
                R.string.uninstall_done_clone_app, targetAppLabel
            ) else context.getString(R.string.uninstall_done_app, targetAppLabel)
            val statusMessage = if (isClonedApp) {
                context.getString(
                R.string.uninstall_done_clone_app,
                    targetAppLabel
            )
            } else {
                context.getString(R.string.uninstall_done_app, targetAppLabel)
            }
            uninstallResult.setValue(
                UninstallSuccess(activityResultCode = legacyStatus, message = statusMessage)
            )
@@ -499,27 +495,32 @@ class UninstallRepository(private val context: Context) {
                        findUserOfDeviceAdmin(myUserHandle, targetPackageName!!)
                    if (otherBlockingUserHandle == null) {
                        Log.d(
                            LOG_TAG, "Uninstall failed because $targetPackageName"
                                + " is a device admin"
                            LOG_TAG,
                            "Uninstall failed because $targetPackageName" +
                                " is a device admin"
                        )
                        addDeviceManagerButton(context, uninstallFailedNotification)
                        setBigText(
                            uninstallFailedNotification, context.getString(
                            uninstallFailedNotification,
                            context.getString(
                                R.string.uninstall_failed_device_policy_manager
                            )
                        )
                    } else {
                        Log.d(
                            LOG_TAG, "Uninstall failed because $targetPackageName"
                                + " is a device admin of user $otherBlockingUserHandle"
                            LOG_TAG,
                            "Uninstall failed because $targetPackageName" +
                                " is a device admin of user $otherBlockingUserHandle"
                        )
                        val userName = context.createContextAsUser(otherBlockingUserHandle, 0)
                            .getSystemService(UserManager::class.java)!!.userName
                        setBigText(
                            uninstallFailedNotification, String.format(
                            uninstallFailedNotification,
                            String.format(
                                context.getString(
                                    R.string.uninstall_failed_device_policy_manager_of_user
                                ), userName
                                ),
                                userName
                            )
                        )
                    }
@@ -528,7 +529,9 @@ class UninstallRepository(private val context: Context) {
                PackageManager.DELETE_FAILED_OWNER_BLOCKED -> {
                    val otherBlockingUserHandle = findBlockingUser(targetPackageName!!)
                    val isProfileOfOrSame = isProfileOfOrSame(
                        userManager!!, myUserHandle, otherBlockingUserHandle
                        userManager!!,
                        myUserHandle,
                        otherBlockingUserHandle
                    )
                    if (isProfileOfOrSame) {
                        addDeviceManagerButton(context, uninstallFailedNotification)
@@ -538,15 +541,19 @@ class UninstallRepository(private val context: Context) {
                    var bigText: String? = null
                    if (otherBlockingUserHandle == null) {
                        Log.d(
                            LOG_TAG, "Uninstall failed for $targetPackageName " +
                            LOG_TAG,
                            "Uninstall failed for $targetPackageName " +
                                "with code $status no blocking user"
                        )
                    } else if (otherBlockingUserHandle === UserHandle.SYSTEM) {
                        bigText = context.getString(R.string.uninstall_blocked_device_owner)
                    } else {
                        bigText = context.getString(
                            if (uninstallFromAllUsers) R.string.uninstall_all_blocked_profile_owner
                            else R.string.uninstall_blocked_profile_owner
                            if (uninstallFromAllUsers) {
                                R.string.uninstall_all_blocked_profile_owner
                            } else {
                                R.string.uninstall_blocked_profile_owner
                            }
                        )
                    }
                    bigText?.let { setBigText(uninstallFailedNotification, it) }
@@ -554,8 +561,9 @@ class UninstallRepository(private val context: Context) {

                else -> {
                    Log.d(
                        LOG_TAG, "Uninstall blocked for $targetPackageName"
                            + " with legacy code $legacyStatus"
                        LOG_TAG,
                        "Uninstall blocked for $targetPackageName" +
                            " with legacy code $legacyStatus"
                    )
                }
            }
@@ -639,7 +647,9 @@ class UninstallRepository(private val context: Context) {
                Icon.createWithResource(context, R.drawable.ic_settings_multiuser),
                context.getString(R.string.manage_users),
                PendingIntent.getActivity(
                    context, 0, getUserSettingsIntent(),
                    context,
                    0,
                    getUserSettingsIntent(),
                    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
                )
            )
@@ -668,7 +678,9 @@ class UninstallRepository(private val context: Context) {
                Icon.createWithResource(context, R.drawable.ic_lock),
                context.getString(R.string.manage_device_administrators),
                PendingIntent.getActivity(
                    context, 0, getDeviceManagerIntent(),
                    context,
                    0,
                    getDeviceManagerIntent(),
                    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
                )
            )
@@ -706,7 +718,8 @@ class UninstallRepository(private val context: Context) {
            context.createContextAsUser(targetUser, 0)
                .packageManager.packageInstaller.uninstall(
                    VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
                    flags, pendingIntent.intentSender
                    flags,
                    pendingIntent.intentSender
                )
            true
        } catch (e: IllegalArgumentException) {
@@ -719,7 +732,8 @@ class UninstallRepository(private val context: Context) {
        if (callback != null) {
            callback!!.onUninstallComplete(
                targetPackageName!!,
                PackageManager.DELETE_FAILED_ABORTED, "Cancelled by user"
                PackageManager.DELETE_FAILED_ABORTED,
                "Cancelled by user"
            )
        }
    }