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

Commit f914ed7c authored by Ivan Chiang's avatar Ivan Chiang
Browse files

[PM] Don't preserve the label in the stage data (2/N)

If we preserve the label in the stage data, if the system language is
changed, then the label may not be updated. Because the data is not
updated with the configuration changes.

Flag: android.content.pm.use_pia_v2
Test: manual. Change the system language
Bug: 441658036
Change-Id: I079a317c4e3ecb8acc12163783c8d78621b38478
parent 77113082
Loading
Loading
Loading
Loading
+61 −82
Original line number Diff line number Diff line
@@ -220,9 +220,10 @@ class UninstallRepository(private val context: Context) {
    }

    fun generateUninstallDetails(): UninstallStage {
        val messageBuilder = StringBuilder()
        var dialogTitle = context.getString(R.string.title_uninstall)
        var positiveButtonText = context.getString(R.string.button_uninstall)
        var messageResId: Int? = null
        var dialogTitleResId = R.string.title_uninstall
        var positiveButtonResId = R.string.button_uninstall
        var isDifferentActivityName = false

        targetAppLabel = targetAppInfo!!.loadSafeLabel(packageManager)

@@ -231,12 +232,9 @@ class UninstallRepository(private val context: Context) {
        if (targetActivityInfo != null) {
            val activityLabel = targetActivityInfo!!.loadSafeLabel(packageManager)
            if (!activityLabel.contentEquals(targetAppLabel)) {
                messageBuilder.append(
                    context.getString(
                        R.string.message_uninstall_activity,
                        activityLabel, targetAppLabel)
                )
                dialogTitle = context.getString(R.string.title_uninstall)
                isDifferentActivityName = true
                messageResId = R.string.message_uninstall_activity
                dialogTitleResId = R.string.title_uninstall
            }
        }

@@ -247,43 +245,30 @@ class UninstallRepository(private val context: Context) {
        val myUserHandle = Process.myUserHandle()
        val isSingleUserOnDevice = isSingleUserOnDevice()

        var isOtherUser = false
        var userName: String? = null

        if (isUpdatedSystemApp) {
            var messageString = ""
            if (isSingleUserOnDevice) {
                dialogTitle = context.getString(
                    R.string.title_uninstall_updates_system_app)
                messageString = context.getString(
                    R.string.message_uninstall_updates_system_app)
                dialogTitleResId = R.string.title_uninstall_updates_system_app
                messageResId = R.string.message_uninstall_updates_system_app
            } else {
                dialogTitle = context.getString(
                    R.string.title_uninstall_updates_system_app_all_users)
                messageString = context.getString(
                    R.string.message_uninstall_updates_system_app_all_users)
            }
            positiveButtonText = context.getString(
                R.string.button_uninstall_updates_system_app)

            if (messageString.isNotEmpty()) {
                messageBuilder.append(messageString)
                dialogTitleResId = R.string.title_uninstall_updates_system_app_all_users
                messageResId = R.string.message_uninstall_updates_system_app_all_users
            }
            positiveButtonResId = R.string.button_uninstall_updates_system_app
        } else if (uninstallFromAllUsers && !isSingleUserOnDevice) {
            var messageString = ""
            if (isArchive) {
                messageString = context.getString(R.string.message_archive_all_users)
                dialogTitle = context.getString(R.string.title_archive_all_users)
                messageResId = R.string.message_archive_all_users
                dialogTitleResId = R.string.title_archive_all_users
            } else {
                dialogTitle = context.getString(R.string.title_uninstall_all_users)
            }

            if (messageString.isNotEmpty()) {
                messageBuilder.append(messageString)
                dialogTitleResId = R.string.title_uninstall_all_users
            }
        } else if (myUserHandle == UserHandle.SYSTEM &&
            hasClonedInstance(targetAppInfo!!.packageName, uninstalledUser!!)
        ) {
            dialogTitle = context.getString(R.string.title_uninstall)
            messageBuilder.append(context.getString(
                R.string.message_uninstall_with_clone_instance))
            dialogTitleResId = R.string.title_uninstall
            messageResId = R.string.message_uninstall_with_clone_instance
        } else {
            val isCrossUserUninstalledRequest = myUserHandle != uninstalledUser
            val isSameProfileGroup =
@@ -296,62 +281,49 @@ class UninstallRepository(private val context: Context) {
            val isPrivateSpaceFeatureEnabled = Flags.allowPrivateProfile()
                    && MultiuserFlags.enablePrivateSpaceFeatures()

            var messageString = ""
            if ((isPrivateSpaceFeatureEnabled)
                && (userManager.isPrivateProfile
                        || (isTargetUserAProfile && userManagerForTargetUser.isPrivateProfile))) {
                if (isArchive) {
                    messageString = context.getString(R.string.message_archive_private_space)
                    dialogTitle = context.getString(R.string.title_archive)
                    messageResId = R.string.message_archive_private_space
                    dialogTitleResId = R.string.title_archive
                } else {
                    messageString = context.getString(R.string.message_uninstall_private_space)
                    dialogTitle = context.getString(R.string.title_uninstall)
                    messageResId = R.string.message_uninstall_private_space
                    dialogTitleResId = R.string.title_uninstall
                }
            } else if (userManager.isManagedProfile
                    || (isTargetUserAProfile && userManagerForTargetUser.isManagedProfile)) {
                if (isArchive) {
                    messageString = context.getString(R.string.message_archive_work_profile)
                    dialogTitle = context.getString(R.string.title_archive)
                    messageResId = R.string.message_archive_work_profile
                    dialogTitleResId = R.string.title_archive
                } else {
                    messageString = context.getString(R.string.message_uninstall_work_profile)
                    dialogTitle = context.getString(R.string.title_uninstall)
                    messageResId = R.string.message_uninstall_work_profile
                    dialogTitleResId = R.string.title_uninstall
                }
            } else if (userManager.isCloneProfile
                    || (isTargetUserAProfile && userManagerForTargetUser.isCloneProfile)) {
                isClonedApp = true
                messageString = context.getString(R.string.message_delete_clone_app,
                    targetAppLabel)
                dialogTitle = context.getString(R.string.title_uninstall_clone)
                positiveButtonText = context.getString(R.string.button_delete)
                messageResId = R.string.message_delete_clone_app
                dialogTitleResId = R.string.title_uninstall_clone
                positiveButtonResId = R.string.button_delete
            } else if (isCrossUserUninstalledRequest && !isTargetUserAProfile) {
                // App is being uninstalled from a different, but non-profile user
                val userName = userManagerForTargetUser!!.userName
                userName = userManagerForTargetUser!!.userName
                isOtherUser = true
                if (isArchive) {
                    messageString = context.getString(R.string.message_archive_other_user)
                    dialogTitle = context.getString(R.string.title_archive_other_user,
                        userName)
                    messageResId = R.string.message_archive_other_user
                    dialogTitleResId = R.string.title_archive_other_user
                } else {
                    dialogTitle = context.getString(R.string.title_uninstall_other_user,
                        userName)
                    dialogTitleResId = R.string.title_uninstall_other_user
                }
            } else if (isArchive) {
                dialogTitle = context.getString(R.string.title_archive)
                messageString = context.getString(R.string.message_archive)
            }

            if (messageString.isNotEmpty()) {
                messageBuilder.append(messageString)
                dialogTitleResId = R.string.title_archive
                messageResId = R.string.message_archive
            }
        }

        if (isArchive) {
            positiveButtonText = context.getString(R.string.button_archive)
        }

        val message = if (messageBuilder.isNotEmpty()) {
            messageBuilder.toString()
        } else {
            null
            positiveButtonResId = R.string.button_archive
        }

        val pkgInfo = try {
@@ -369,11 +341,6 @@ class UninstallRepository(private val context: Context) {
        // correctly badged icon (e.g badging for work profile, private space)
        val userContext = context.createContextAsUser(uninstalledUser!!, 0)
        val appSnippet: PackageUtil.AppSnippet? = pkgInfo?.let { getAppSnippet(userContext, it) }
        appSnippet?.label = if (isClonedApp) {
            context.getString(R.string.string_cloned_app_label, targetAppLabel)
        } else {
            targetAppLabel.toString()
        }

        var suggestToKeepAppData = pkgInfo?.applicationInfo != null
                && (pkgInfo.applicationInfo?.hasFragileUserData() == true)
@@ -387,7 +354,19 @@ class UninstallRepository(private val context: Context) {
            )
        }

        return UninstallUserActionRequired(dialogTitle, message, positiveButtonText, appDataSize, appSnippet)
        return UninstallUserActionRequired(
            dialogTitleResId,
            messageResId,
            positiveButtonResId,
            appDataSize,
            appSnippet,
            isClonedApp,
            isDifferentActivityName,
            isOtherUser,
            userName,
            targetAppInfo!!,
            targetActivityInfo
        )
    }

    /**
@@ -549,7 +528,8 @@ class UninstallRepository(private val context: Context) {
            intent.putExtra(Intent.EXTRA_INSTALL_RESULT, legacyStatus)
            if (status == PackageInstaller.STATUS_SUCCESS) {
                uninstallResult.setValue(
                    UninstallSuccess(resultIntent = intent, activityResultCode = Activity.RESULT_OK)
                    UninstallSuccess(appInfo = targetAppInfo!!, resultIntent = intent,
                        activityResultCode = Activity.RESULT_OK)
                )
            } else {
                uninstallResult.setValue(
@@ -565,16 +545,15 @@ 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
            )
            val messageResId = if (isClonedApp) {
                R.string.uninstall_done_clone_app
            } else {
                context.getString(R.string.uninstall_done_app, targetAppLabel)
                R.string.uninstall_done_app
            }
            uninstallResult.setValue(
                UninstallSuccess(activityResultCode = legacyStatus, message = statusMessage)
            uninstallResult.value = UninstallSuccess(
                appInfo = targetAppInfo!!,
                activityResultCode = legacyStatus,
                messageResId = messageResId
            )
        } else {
            val uninstallFailureChannel = NotificationChannel(
+57 −7
Original line number Diff line number Diff line
@@ -17,7 +17,10 @@ package com.android.packageinstaller.v2.model

import android.app.Activity
import android.app.Notification
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
import android.graphics.drawable.Drawable
import com.android.packageinstaller.R

@@ -36,25 +39,72 @@ sealed class UninstallStage(val stageCode: Int) {
class UninstallReady : UninstallStage(STAGE_READY)

data class UninstallUserActionRequired(
    val title: String,
    val message: String? = null,
    val buttonText: String,
    val titleResId: Int,
    val messageResId: Int? = null,
    val positiveButtonResId: Int,
    val appDataSize: Long = 0,
    val appSnippet: PackageUtil.AppSnippet? = null,
    val isClonedApp: Boolean = false,
    val isDifferentActivityName: Boolean = false,
    val isOtherUser: Boolean = false,
    val userName: String? = null,
    val targetAppInfo: ApplicationInfo,
    val targetActivityInfo: ActivityInfo? = null,
) : UninstallStage(STAGE_USER_ACTION_REQUIRED) {

    val appIcon: Drawable?
        get() = appSnippet?.icon

    val appLabel: String?
        get() = appSnippet?.let { appSnippet.label as String? }
    fun getAppLabel(context: Context): String {
        val appLabel = targetAppInfo.loadSafeLabel(context.packageManager) as String
        return if (isClonedApp) {
            context.getString(R.string.string_cloned_app_label, appLabel)
        } else {
            appLabel
        }
    }

    fun getMessage(context: Context): String? {
        return messageResId?.let {
            if (isDifferentActivityName && targetActivityInfo != null) {
                val activityLabel = targetActivityInfo.loadSafeLabel(context.packageManager)
                val appLabel = targetAppInfo.loadSafeLabel(context.packageManager)
                context.getString(it, activityLabel, appLabel)
            } else if (isClonedApp) {
                val appLabel = targetAppInfo.loadSafeLabel(context.packageManager)
                context.getString(it, appLabel)
            } else {
                context.getString(it)
            }
        }
    }

    fun getTitle(context: Context): String {
        return titleResId.let {
            if (isOtherUser && userName != null) {
                context.getString(it, userName)
            } else {
                context.getString(it)
            }
        }
    }
}

data class UninstallSuccess(
    val appInfo: ApplicationInfo,
    val resultIntent: Intent? = null,
    val activityResultCode: Int = 0,
    val message: String? = null,
) : UninstallStage(STAGE_SUCCESS)
    val messageResId: Int? = null,
    val isCloneApp: Boolean = false,
) : UninstallStage(STAGE_SUCCESS) {

    fun getMessage(context: Context): String? {
        return messageResId?.let {
            val appLabel = appInfo.loadSafeLabel(context.packageManager)
            context.getString(it, appLabel)
        }
    }
}

data class UninstallFailed(
    val returnResult: Boolean,
+3 −2
Original line number Diff line number Diff line
@@ -136,8 +136,9 @@ class UninstallLaunch : FragmentActivity(), UninstallActionListener {

            UninstallStage.STAGE_SUCCESS -> {
                val success = uninstallStage as UninstallSuccess
                if (success.message != null) {
                    Toast.makeText(this, success.message, Toast.LENGTH_LONG).show()
                val message = success.getMessage(this)
                if (message != null) {
                    Toast.makeText(this, message, Toast.LENGTH_LONG).show()
                }
                setResult(success.activityResultCode, success.resultIntent, true)
            }
+6 −5
Original line number Diff line number Diff line
@@ -171,15 +171,16 @@ public class UninstallationFragment extends DialogFragment {

        // Set app icon and label
        mAppIcon.setImageDrawable(uninstallStage.getAppIcon());
        mAppLabelTextView.setText(uninstallStage.getAppLabel());
        mAppLabelTextView.setText(uninstallStage.getAppLabel(requireContext()));

        // Set title
        dialog.setTitle(uninstallStage.getTitle());
        dialog.setTitle(uninstallStage.getTitle(requireContext()));

        // Set custom message
        if (uninstallStage.getMessage() != null) {
        final String message = uninstallStage.getMessage(requireContext());
        if (message != null) {
            mCustomMessageTextView.setVisibility(View.VISIBLE);
            mCustomMessageTextView.setText(uninstallStage.getMessage());
            mCustomMessageTextView.setText(message);
        } else {
            mCustomMessageTextView.setVisibility(View.GONE);
        }
@@ -199,7 +200,7 @@ public class UninstallationFragment extends DialogFragment {
        Button positiveButton = UiUtil.getAlertDialogPositiveButton(dialog);
        if (positiveButton != null) {
            positiveButton.setVisibility(View.VISIBLE);
            positiveButton.setText(uninstallStage.getButtonText());
            positiveButton.setText(uninstallStage.getPositiveButtonResId());
            positiveButton.setOnClickListener(view -> {
                // Set clickable of the button to false to avoid the user clicks it
                // more than once quickly