Merge "Stop app when toggling backcompat setting" into main

This commit is contained in:
Treehugger Robot
2025-03-02 16:59:40 -08:00
committed by Android (Google) Code Review
4 changed files with 68 additions and 7 deletions

View File

@@ -13148,7 +13148,11 @@ Data usage charges may apply.</string>
<string name="page_agnostic_notification_action">Read more</string> <string name="page_agnostic_notification_action">Read more</string>
<string name= "enable_16k_app_compat_title">Run app with page size compat mode</string> <string name= "enable_16k_app_compat_title">Run app with page size compat mode</string>
<string name= "enable_16k_app_compat_details">App will be run in page size compatibility mode on 16 KB device when toggled.</string> <string name= "enable_16k_app_compat_details">App will be forced stopped and run in page size compatibility mode on 16 KB device when toggled.</string>
<string name="stop_app_dlg_title">Stop app?</string>
<!-- [CHAR LIMIT=200] Manage applications, text for dialog when killing persistent apps-->
<string name="stop_app_dlg_text">Application will be stopped to apply page size compat setting.</string>
<!-- DSU Loader. Do not translate. --> <!-- DSU Loader. Do not translate. -->

View File

@@ -170,7 +170,7 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) {
InteractAcrossProfilesDetailsPreference(app) InteractAcrossProfilesDetailsPreference(app)
AlarmsAndRemindersAppListProvider.InfoPageEntryItem(app) AlarmsAndRemindersAppListProvider.InfoPageEntryItem(app)
WriteSystemPreferencesAppListProvider.InfoPageEntryItem(app) WriteSystemPreferencesAppListProvider.InfoPageEntryItem(app)
Enable16KbAppCompatPreference(app) Enable16KbAppCompatPreference(app, packageInfoPresenter)
} }
Category(title = stringResource(R.string.app_install_details_group_title)) { Category(title = stringResource(R.string.app_install_details_group_title)) {

View File

@@ -16,8 +16,12 @@
package com.android.settings.spa.app.appinfo package com.android.settings.spa.app.appinfo
import android.app.AlertDialog
import android.app.settings.SettingsEnums
import android.content.Context import android.content.Context
import android.content.DialogInterface
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.os.UserManager
import android.util.Log import android.util.Log
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@@ -26,17 +30,23 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settings.R import com.android.settings.R
import com.android.settings.development.Enable16kUtils import com.android.settings.development.Enable16kUtils
import com.android.settings.flags.Flags import com.android.settings.flags.Flags
import com.android.settingslib.RestrictedLockUtils
import com.android.settingslib.RestrictedLockUtilsInternal
import com.android.settingslib.spa.framework.compose.OverridableFlow import com.android.settingslib.spa.framework.compose.OverridableFlow
import com.android.settingslib.spa.widget.dialog.AlertDialogButton
import com.android.settingslib.spa.widget.dialog.rememberAlertDialogPresenter
import com.android.settingslib.spa.widget.preference.SwitchPreference import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import com.android.settingslib.spaprivileged.model.app.userId
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
@Composable @Composable
fun Enable16KbAppCompatPreference( fun Enable16KbAppCompatPreference(
app: ApplicationInfo app: ApplicationInfo,
packageInfoPresenter: PackageInfoPresenter
) { ) {
val context = LocalContext.current val context = LocalContext.current
val presenter = remember(app) { Enable16KbAppCompatSwitchPresenter(context, app) } val presenter = remember(app) { Enable16KbAppCompatSwitchPresenter(context, app, packageInfoPresenter) }
if (!presenter.isAvailable()) return if (!presenter.isAvailable()) return
val isCheckedState = presenter.isCheckedFlow.collectAsStateWithLifecycle(initialValue = null) val isCheckedState = presenter.isCheckedFlow.collectAsStateWithLifecycle(initialValue = null)
@@ -58,7 +68,9 @@ fun Enable16KbAppCompatPreference(
}) })
} }
private class Enable16KbAppCompatSwitchPresenter(context: Context, private val app: ApplicationInfo) {
private class Enable16KbAppCompatSwitchPresenter(private val context: Context, private val app: ApplicationInfo,
private val packageInfoPresenter: PackageInfoPresenter) {
private val packageManager = context.packageManager private val packageManager = context.packageManager
fun isAvailable(): Boolean { fun isAvailable(): Boolean {
return Enable16kUtils.isUsing16kbPages() && Flags.pageSizeAppCompatSetting() return Enable16kUtils.isUsing16kbPages() && Flags.pageSizeAppCompatSetting()
@@ -69,13 +81,48 @@ private class Enable16KbAppCompatSwitchPresenter(context: Context, private val a
}) })
val isCheckedFlow = isChecked.flow val isCheckedFlow = isChecked.flow
fun onCheckedChange(newChecked: Boolean) { fun onCheckedChange(newChecked: Boolean) {
try { try {
packageManager.setPageSizeAppCompatFlagsSettingsOverride(app.packageName, newChecked) getForceStopRestriction(app)?.let { admin ->
isChecked.override(newChecked) RestrictedLockUtils.sendShowAdminSupportDetailsIntent(context, admin)
return
}
showDialog(newChecked)
} catch (e: RuntimeException) { } catch (e: RuntimeException) {
Log.e("Enable16KbAppCompat", "Failed to set" + Log.e("Enable16KbAppCompat", "Failed to set" +
"setPageSizeAppCompatModeSettingsOverride", e); "setPageSizeAppCompatModeSettingsOverride", e);
} }
} }
fun updatePageSizeCompat(newChecked: Boolean) {
packageManager.setPageSizeAppCompatFlagsSettingsOverride(app.packageName, newChecked)
isChecked.override(newChecked)
packageInfoPresenter.stopPackage()
}
fun getForceStopRestriction(app: ApplicationInfo): RestrictedLockUtils.EnforcedAdmin? = when {
packageManager.isPackageStateProtected(app.packageName, app.userId) -> {
RestrictedLockUtilsInternal.getDeviceOwner(context) ?: RestrictedLockUtils.EnforcedAdmin()
}
else -> RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
context, UserManager.DISALLOW_APPS_CONTROL, app.userId
)
}
fun showDialog(newChecked: Boolean) {
// Uses the same string from 'Force Stop' action button.
val builder =
AlertDialog.Builder(context)
.setTitle(R.string.stop_app_dlg_title)
.setMessage(R.string.stop_app_dlg_text)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.okay, DialogInterface.OnClickListener { dialog, _ ->
updatePageSizeCompat(newChecked)
dialog.dismiss()
})
.create();
builder.show();
}
} }

View File

@@ -185,6 +185,16 @@ class PackageInfoPresenter(
} }
} }
/* stops application without durable effects of the full-scale "forec stop" */
fun stopPackage() {
requireAuthAndExecute {
coroutineScope.launch(Dispatchers.Default) {
Log.d(TAG, "Stopping package $packageName for user")
context.activityManager.stopPackageForUser(packageName)
}
}
}
fun logAction(category: Int) { fun logAction(category: Int) {
metricsFeatureProvider.action(context, category, packageName) metricsFeatureProvider.action(context, category, packageName)
} }