Merge changes from topic "LifecycleEffect"

* changes:
  Redirect to AppInfoSettings when SPA is on
  Reload package info for each time enter App Info
This commit is contained in:
TreeHugger Robot
2023-01-11 05:35:07 +00:00
committed by Android (Google) Code Review
6 changed files with 60 additions and 32 deletions

View File

@@ -16,6 +16,8 @@
package com.android.settings.applications; package com.android.settings.applications;
import static com.android.settings.spa.app.appinfo.AppInfoSettingsProvider.startAppInfoSettings;
import android.app.Application; import android.app.Application;
import android.app.usage.UsageStats; import android.app.usage.UsageStats;
import android.content.Context; import android.content.Context;
@@ -33,7 +35,6 @@ import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.Utils; import com.android.settingslib.Utils;
import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState;
@@ -208,9 +209,7 @@ public class AppsPreferenceController extends BasePreferenceController implement
RelativeDateTimeFormatter.Style.SHORT)); RelativeDateTimeFormatter.Style.SHORT));
pref.setOrder(showAppsCount++); pref.setOrder(showAppsCount++);
pref.setOnPreferenceClickListener(preference -> { pref.setOnPreferenceClickListener(preference -> {
AppInfoBase.startAppInfoFragment(AppInfoDashboardFragment.class, startAppInfoSettings(pkgName, appEntry.info.uid,
mContext.getString(R.string.application_info_label),
pkgName, appEntry.info.uid,
mHost, 1001 /*RequestCode*/, getMetricsCategory()); mHost, 1001 /*RequestCode*/, getMetricsCategory());
return true; return true;
}); });

View File

@@ -18,8 +18,9 @@ package com.android.settings.spa.app.appinfo
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember 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.applications.AppUtils
import com.android.settingslib.spa.widget.button.ActionButton import com.android.settingslib.spa.widget.button.ActionButton
import com.android.settingslib.spa.widget.button.ActionButtons 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 appClearButton = AppClearButton(packageInfoPresenter)
private val appForceStopButton = AppForceStopButton(packageInfoPresenter) private val appForceStopButton = AppForceStopButton(packageInfoPresenter)
@OptIn(ExperimentalLifecycleComposeApi::class)
@Composable @Composable
fun rememberActionsButtons() = remember { fun rememberActionsButtons() = remember {
packageInfoPresenter.flow.map { packageInfo -> packageInfoPresenter.flow.map { packageInfo ->
if (packageInfo != null) getActionButtons(packageInfo.applicationInfo) else emptyList() if (packageInfo != null) getActionButtons(packageInfo.applicationInfo) else emptyList()
} }
}.collectAsState(initial = emptyList()) }.collectAsStateWithLifecycle(initialValue = emptyList())
private fun getActionButtons(app: ApplicationInfo): List<ActionButton> = listOfNotNull( private fun getActionButtons(app: ApplicationInfo): List<ActionButton> = listOfNotNull(
appLaunchButton.getActionButton(app), appLaunchButton.getActionButton(app),

View File

@@ -19,21 +19,29 @@ package com.android.settings.spa.app.appinfo
import android.app.settings.SettingsEnums import android.app.settings.SettingsEnums
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.os.Bundle import android.os.Bundle
import android.os.UserHandle
import android.util.FeatureFlagUtils
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource 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.NavType
import androidx.navigation.navArgument import androidx.navigation.navArgument
import com.android.settings.R 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.AlarmsAndRemindersAppListProvider
import com.android.settings.spa.app.specialaccess.DisplayOverOtherAppsAppListProvider import com.android.settings.spa.app.specialaccess.DisplayOverOtherAppsAppListProvider
import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider
import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider
import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
import com.android.settingslib.spa.framework.common.SettingsPageProvider 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.framework.compose.navigator
import com.android.settingslib.spa.widget.scaffold.RegularScaffold import com.android.settingslib.spa.widget.scaffold.RegularScaffold
import com.android.settingslib.spa.widget.ui.Category import com.android.settingslib.spa.widget.ui.Category
@@ -75,11 +83,42 @@ object AppInfoSettingsProvider : SettingsPageProvider {
* Expose route to enable enter from non-SPA pages. * Expose route to enable enter from non-SPA pages.
*/ */
fun getRoute(packageName: String, userId: Int): String = "$name/$packageName/$userId" 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 @Composable
private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { 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 val app = packageInfo.applicationInfo
RegularScaffold( RegularScaffold(
title = stringResource(R.string.application_info_label), title = stringResource(R.string.application_info_label),

View File

@@ -49,7 +49,7 @@ import kotlinx.coroutines.plus
fun AppSettingsPreference(app: ApplicationInfo) { fun AppSettingsPreference(app: ApplicationInfo) {
val context = LocalContext.current val context = LocalContext.current
val coroutineScope = rememberCoroutineScope() 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 if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
Preference(object : PreferenceModel { Preference(object : PreferenceModel {

View File

@@ -59,11 +59,7 @@ class PackageInfoPresenter(
val flow: StateFlow<PackageInfo?> = _flow val flow: StateFlow<PackageInfo?> = _flow
init { fun reloadPackageInfo() {
notifyChange()
}
private fun notifyChange() {
coroutineScope.launch(Dispatchers.IO) { coroutineScope.launch(Dispatchers.IO) {
_flow.value = getPackageInfo() _flow.value = getPackageInfo()
} }
@@ -83,7 +79,7 @@ class PackageInfoPresenter(
val packageInfo = flow.value val packageInfo = flow.value
if (packageInfo != null && packageInfo.applicationInfo.isSystemApp) { if (packageInfo != null && packageInfo.applicationInfo.isSystemApp) {
// System app still exists after uninstalling the updates, refresh the page. // System app still exists after uninstalling the updates, refresh the page.
notifyChange() reloadPackageInfo()
} else { } else {
navController.navigateBack() navController.navigateBack()
} }
@@ -98,7 +94,7 @@ class PackageInfoPresenter(
userPackageManager.setApplicationEnabledSetting( userPackageManager.setApplicationEnabledSetting(
packageName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 0 packageName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 0
) )
notifyChange() reloadPackageInfo()
} }
} }
@@ -109,7 +105,7 @@ class PackageInfoPresenter(
userPackageManager.setApplicationEnabledSetting( userPackageManager.setApplicationEnabledSetting(
packageName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0 packageName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0
) )
notifyChange() reloadPackageInfo()
} }
} }
@@ -124,7 +120,7 @@ class PackageInfoPresenter(
logAction(SettingsEnums.ACTION_SETTINGS_CLEAR_INSTANT_APP) logAction(SettingsEnums.ACTION_SETTINGS_CLEAR_INSTANT_APP)
coroutineScope.launch(Dispatchers.IO) { coroutineScope.launch(Dispatchers.IO) {
userPackageManager.deletePackageAsUser(packageName, null, 0, userId) userPackageManager.deletePackageAsUser(packageName, null, 0, userId)
notifyChange() reloadPackageInfo()
} }
} }
@@ -134,7 +130,7 @@ class PackageInfoPresenter(
coroutineScope.launch(Dispatchers.Default) { coroutineScope.launch(Dispatchers.Default) {
Log.d(TAG, "Stopping package $packageName") Log.d(TAG, "Stopping package $packageName")
context.activityManager.forceStopPackageAsUser(packageName, userId) context.activityManager.forceStopPackageAsUser(packageName, userId)
notifyChange() reloadPackageInfo()
} }
} }

View File

@@ -16,6 +16,8 @@
package com.android.settings.widget; package com.android.settings.widget;
import static com.android.settings.spa.app.appinfo.AppInfoSettingsProvider.startAppInfoSettings;
import android.annotation.IdRes; import android.annotation.IdRes;
import android.annotation.UserIdInt; import android.annotation.UserIdInt;
import android.app.Activity; import android.app.Activity;
@@ -40,8 +42,6 @@ import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Utils; 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.settings.overlay.FeatureFactory;
import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.core.lifecycle.Lifecycle; 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"); Log.w(TAG, "Missing ingredients to build app info link, skip");
return; return;
} }
entityHeaderContent.setOnClickListener(new View.OnClickListener() { entityHeaderContent.setOnClickListener(v -> startAppInfoSettings(
@Override mPackageName, mUid, mFragment, 0 /* request */,
public void onClick(View v) { mMetricsCategory));
AppInfoBase.startAppInfoFragment(
AppInfoDashboardFragment.class,
mActivity.getString(R.string.application_info_label),
mPackageName, mUid, mFragment, 0 /* request */,
mMetricsCategory);
}
});
return;
} }
/** /**