diff --git a/src/com/android/settings/applications/AppsPreferenceController.java b/src/com/android/settings/applications/AppsPreferenceController.java index 37ec0bbf0a1..963376662b7 100644 --- a/src/com/android/settings/applications/AppsPreferenceController.java +++ b/src/com/android/settings/applications/AppsPreferenceController.java @@ -16,6 +16,8 @@ package com.android.settings.applications; +import static com.android.settings.spa.app.appinfo.AppInfoSettingsProvider.startAppInfoSettings; + import android.app.Application; import android.app.usage.UsageStats; import android.content.Context; @@ -33,7 +35,6 @@ import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceScreen; import com.android.settings.R; -import com.android.settings.applications.appinfo.AppInfoDashboardFragment; import com.android.settings.core.BasePreferenceController; import com.android.settingslib.Utils; import com.android.settingslib.applications.ApplicationsState; @@ -208,9 +209,7 @@ public class AppsPreferenceController extends BasePreferenceController implement RelativeDateTimeFormatter.Style.SHORT)); pref.setOrder(showAppsCount++); pref.setOnPreferenceClickListener(preference -> { - AppInfoBase.startAppInfoFragment(AppInfoDashboardFragment.class, - mContext.getString(R.string.application_info_label), - pkgName, appEntry.info.uid, + startAppInfoSettings(pkgName, appEntry.info.uid, mHost, 1001 /*RequestCode*/, getMetricsCategory()); return true; }); diff --git a/src/com/android/settings/spa/app/appinfo/AppButtons.kt b/src/com/android/settings/spa/app/appinfo/AppButtons.kt index cbe2f1a9d42..831149132f2 100644 --- a/src/com/android/settings/spa/app/appinfo/AppButtons.kt +++ b/src/com/android/settings/spa/app/appinfo/AppButtons.kt @@ -18,8 +18,9 @@ package com.android.settings.spa.app.appinfo import android.content.pm.ApplicationInfo import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember +import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.settingslib.applications.AppUtils import com.android.settingslib.spa.widget.button.ActionButton import com.android.settingslib.spa.widget.button.ActionButtons @@ -44,12 +45,13 @@ private class AppButtonsPresenter(private val packageInfoPresenter: PackageInfoP private val appClearButton = AppClearButton(packageInfoPresenter) private val appForceStopButton = AppForceStopButton(packageInfoPresenter) + @OptIn(ExperimentalLifecycleComposeApi::class) @Composable fun rememberActionsButtons() = remember { packageInfoPresenter.flow.map { packageInfo -> if (packageInfo != null) getActionButtons(packageInfo.applicationInfo) else emptyList() } - }.collectAsState(initial = emptyList()) + }.collectAsStateWithLifecycle(initialValue = emptyList()) private fun getActionButtons(app: ApplicationInfo): List = listOfNotNull( appLaunchButton.getActionButton(app), diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt index 1f7cc4dc607..d59a4f72c86 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -19,21 +19,29 @@ package com.android.settings.spa.app.appinfo import android.app.settings.SettingsEnums import android.content.pm.ApplicationInfo import android.os.Bundle +import android.os.UserHandle +import android.util.FeatureFlagUtils import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import androidx.fragment.app.Fragment +import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavType import androidx.navigation.navArgument import com.android.settings.R +import com.android.settings.applications.AppInfoBase +import com.android.settings.applications.appinfo.AppInfoDashboardFragment +import com.android.settings.spa.SpaActivity.Companion.startSpaActivity import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider import com.android.settings.spa.app.specialaccess.DisplayOverOtherAppsAppListProvider import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.compose.LifecycleEffect import com.android.settingslib.spa.framework.compose.navigator import com.android.settingslib.spa.widget.scaffold.RegularScaffold import com.android.settingslib.spa.widget.ui.Category @@ -75,11 +83,42 @@ object AppInfoSettingsProvider : SettingsPageProvider { * Expose route to enable enter from non-SPA pages. */ fun getRoute(packageName: String, userId: Int): String = "$name/$packageName/$userId" + + /** + * Starts the App Info Settings page from non-SPA. + * + * Will starts SPA version if flag [FeatureFlagUtils.SETTINGS_ENABLE_SPA] is true. + */ + @JvmStatic + fun startAppInfoSettings( + packageName: String, + uid: Int, + source: Fragment, + request: Int, + sourceMetricsCategory: Int, + ) { + val context = source.context ?: return + if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_ENABLE_SPA)) { + context.startSpaActivity(getRoute(packageName, UserHandle.getUserId(uid))) + } else { + AppInfoBase.startAppInfoFragment( + AppInfoDashboardFragment::class.java, + context.getString(R.string.application_info_label), + packageName, + uid, + source, + request, + sourceMetricsCategory, + ) + } + } } +@OptIn(ExperimentalLifecycleComposeApi::class) @Composable private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { - val packageInfo = packageInfoPresenter.flow.collectAsState().value ?: return + LifecycleEffect(onStart = { packageInfoPresenter.reloadPackageInfo() }) + val packageInfo = packageInfoPresenter.flow.collectAsStateWithLifecycle().value ?: return val app = packageInfo.applicationInfo RegularScaffold( title = stringResource(R.string.application_info_label), diff --git a/src/com/android/settings/spa/app/appinfo/AppSettingsPreference.kt b/src/com/android/settings/spa/app/appinfo/AppSettingsPreference.kt index d700641a161..09957ca05a5 100644 --- a/src/com/android/settings/spa/app/appinfo/AppSettingsPreference.kt +++ b/src/com/android/settings/spa/app/appinfo/AppSettingsPreference.kt @@ -49,7 +49,7 @@ import kotlinx.coroutines.plus fun AppSettingsPreference(app: ApplicationInfo) { val context = LocalContext.current val coroutineScope = rememberCoroutineScope() - val presenter = remember { AppSettingsPresenter(context, app, coroutineScope) } + val presenter = remember(app) { AppSettingsPresenter(context, app, coroutineScope) } if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return Preference(object : PreferenceModel { diff --git a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt index 51426a1bdfe..a03fec727f4 100644 --- a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt +++ b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt @@ -59,11 +59,7 @@ class PackageInfoPresenter( val flow: StateFlow = _flow - init { - notifyChange() - } - - private fun notifyChange() { + fun reloadPackageInfo() { coroutineScope.launch(Dispatchers.IO) { _flow.value = getPackageInfo() } @@ -83,7 +79,7 @@ class PackageInfoPresenter( val packageInfo = flow.value if (packageInfo != null && packageInfo.applicationInfo.isSystemApp) { // System app still exists after uninstalling the updates, refresh the page. - notifyChange() + reloadPackageInfo() } else { navController.navigateBack() } @@ -98,7 +94,7 @@ class PackageInfoPresenter( userPackageManager.setApplicationEnabledSetting( packageName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 0 ) - notifyChange() + reloadPackageInfo() } } @@ -109,7 +105,7 @@ class PackageInfoPresenter( userPackageManager.setApplicationEnabledSetting( packageName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0 ) - notifyChange() + reloadPackageInfo() } } @@ -124,7 +120,7 @@ class PackageInfoPresenter( logAction(SettingsEnums.ACTION_SETTINGS_CLEAR_INSTANT_APP) coroutineScope.launch(Dispatchers.IO) { userPackageManager.deletePackageAsUser(packageName, null, 0, userId) - notifyChange() + reloadPackageInfo() } } @@ -134,7 +130,7 @@ class PackageInfoPresenter( coroutineScope.launch(Dispatchers.Default) { Log.d(TAG, "Stopping package $packageName") context.activityManager.forceStopPackageAsUser(packageName, userId) - notifyChange() + reloadPackageInfo() } } diff --git a/src/com/android/settings/widget/EntityHeaderController.java b/src/com/android/settings/widget/EntityHeaderController.java index 51911c0ed1e..8a2403cf3c0 100644 --- a/src/com/android/settings/widget/EntityHeaderController.java +++ b/src/com/android/settings/widget/EntityHeaderController.java @@ -16,6 +16,8 @@ package com.android.settings.widget; +import static com.android.settings.spa.app.appinfo.AppInfoSettingsProvider.startAppInfoSettings; + import android.annotation.IdRes; import android.annotation.UserIdInt; import android.app.Activity; @@ -40,8 +42,6 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.settings.R; import com.android.settings.Utils; -import com.android.settings.applications.AppInfoBase; -import com.android.settings.applications.appinfo.AppInfoDashboardFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -292,17 +292,9 @@ public class EntityHeaderController { Log.w(TAG, "Missing ingredients to build app info link, skip"); return; } - entityHeaderContent.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - AppInfoBase.startAppInfoFragment( - AppInfoDashboardFragment.class, - mActivity.getString(R.string.application_info_label), - mPackageName, mUid, mFragment, 0 /* request */, - mMetricsCategory); - } - }); - return; + entityHeaderContent.setOnClickListener(v -> startAppInfoSettings( + mPackageName, mUid, mFragment, 0 /* request */, + mMetricsCategory)); } /**