Stop app when toggling backcompat setting

- Add method to stop package
- Backcompat setting takes two launches right now to take effect.
stop application when backcompat setting is toggled.

Test: m Settings && adb install -r $ANDROID_PRODUCT_OUT/system_ext/priv-app/Settings/Settings.apk
Bug: 389696304
Flag: EXEMPT bug_fix
Change-Id: Iadc8030fe34f66e7eaf854513b14aeb78a556308
This commit is contained in:
Pawan Wagh
2025-02-24 19:42:20 +00:00
parent 165f4ea76e
commit a63c370eb6
4 changed files with 68 additions and 7 deletions

View File

@@ -13097,7 +13097,11 @@
<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)
} }