Update archive's button `enable` property whenever hibernation toggle
has changed its value

Test: AppArchiveButtonTest

Bug: 304257274
Change-Id: I95b8a2219a7d04437b5c7d217a520e8c8b05d395
diff --git a/src/com/android/settings/spa/app/appinfo/AppArchiveButton.kt b/src/com/android/settings/spa/app/appinfo/AppArchiveButton.kt
index 913da65..0eef9c3 100644
--- a/src/com/android/settings/spa/app/appinfo/AppArchiveButton.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppArchiveButton.kt
@@ -33,10 +33,15 @@
 import com.android.settingslib.spa.widget.button.ActionButton
 import com.android.settingslib.spaprivileged.framework.compose.DisposableBroadcastReceiverAsUser
 import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
 
-class AppArchiveButton(packageInfoPresenter: PackageInfoPresenter) {
+class AppArchiveButton(
+    packageInfoPresenter: PackageInfoPresenter,
+    private val isHibernationSwitchEnabledStateFlow: MutableStateFlow<Boolean>,
+) {
     private companion object {
         private const val LOG_TAG = "AppArchiveButton"
         private const val INTENT_ACTION = "com.android.settings.archive.action"
@@ -65,18 +70,20 @@
             text = context.getString(R.string.archive),
             imageVector = Icons.Outlined.CloudUpload,
             enabled = remember(app) {
-                flow {
-                    emit(
-                        app.isActionButtonEnabled() && appButtonRepository.isAllowUninstallOrArchive(
-                            context,
-                            app
-                        )
-                    )
+                isHibernationSwitchEnabledStateFlow.asStateFlow().map {
+                    it && isActionButtonEnabledForApp(app)
                 }.flowOn(Dispatchers.Default)
             }.collectAsStateWithLifecycle(false).value
         ) { onArchiveClicked(app) }
     }
 
+    private fun isActionButtonEnabledForApp(app: ApplicationInfo): Boolean {
+        return app.isActionButtonEnabled() && appButtonRepository.isAllowUninstallOrArchive(
+            context,
+            app
+        )
+    }
+
     private fun ApplicationInfo.isActionButtonEnabled(): Boolean {
         return !isArchived
             && userPackageManager.isAppArchivable(packageName)
diff --git a/src/com/android/settings/spa/app/appinfo/AppButtonRepository.kt b/src/com/android/settings/spa/app/appinfo/AppButtonRepository.kt
index f01c31c..5fa9436 100644
--- a/src/com/android/settings/spa/app/appinfo/AppButtonRepository.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppButtonRepository.kt
@@ -23,6 +23,7 @@
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageManager
 import android.content.pm.ResolveInfo
+import android.util.Log
 import com.android.settingslib.RestrictedLockUtils
 import com.android.settingslib.RestrictedLockUtilsInternal
 import com.android.settingslib.Utils
diff --git a/src/com/android/settings/spa/app/appinfo/AppButtons.kt b/src/com/android/settings/spa/app/appinfo/AppButtons.kt
index c0fa313..dcce1d9 100644
--- a/src/com/android/settings/spa/app/appinfo/AppButtons.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppButtons.kt
@@ -25,6 +25,7 @@
 import com.android.settingslib.applications.AppUtils
 import com.android.settingslib.spa.widget.button.ActionButton
 import com.android.settingslib.spa.widget.button.ActionButtons
+import kotlinx.coroutines.flow.MutableStateFlow
 
 @Composable
 /**
@@ -32,10 +33,17 @@
  */
 fun AppButtons(
     packageInfoPresenter: PackageInfoPresenter,
+    isHibernationSwitchEnabledStateFlow: MutableStateFlow<Boolean>,
     featureFlags: FeatureFlags = FeatureFlagsImpl()
 ) {
     if (remember(packageInfoPresenter) { packageInfoPresenter.isMainlineModule() }) return
-    val presenter = remember { AppButtonsPresenter(packageInfoPresenter, featureFlags) }
+    val presenter = remember {
+        AppButtonsPresenter(
+            packageInfoPresenter,
+            isHibernationSwitchEnabledStateFlow,
+            featureFlags
+        )
+    }
     ActionButtons(actionButtons = presenter.getActionButtons())
 }
 
@@ -44,6 +52,7 @@
 
 private class AppButtonsPresenter(
     private val packageInfoPresenter: PackageInfoPresenter,
+    isHibernationSwitchEnabledStateFlow: MutableStateFlow<Boolean>,
     private val featureFlags: FeatureFlags
 ) {
     private val appLaunchButton = AppLaunchButton(packageInfoPresenter)
@@ -52,7 +61,8 @@
     private val appUninstallButton = AppUninstallButton(packageInfoPresenter)
     private val appClearButton = AppClearButton(packageInfoPresenter)
     private val appForceStopButton = AppForceStopButton(packageInfoPresenter)
-    private val appArchiveButton = AppArchiveButton(packageInfoPresenter)
+    private val appArchiveButton =
+        AppArchiveButton(packageInfoPresenter, isHibernationSwitchEnabledStateFlow)
     private val appRestoreButton = AppRestoreButton(packageInfoPresenter)
 
     @Composable
diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
index 9291892..dba6184 100644
--- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
@@ -50,6 +50,7 @@
 import com.android.settingslib.spa.widget.ui.Category
 import com.android.settingslib.spaprivileged.model.app.toRoute
 import com.android.settingslib.spaprivileged.template.app.AppInfoProvider
+import kotlinx.coroutines.flow.MutableStateFlow
 
 private const val PACKAGE_NAME = "packageName"
 private const val USER_ID = "userId"
@@ -133,10 +134,11 @@
         val packageInfo = packageInfoState.value ?: return@RegularScaffold
         val app = packageInfo.applicationInfo ?: return@RegularScaffold
         val appInfoProvider = remember(packageInfo) { AppInfoProvider(packageInfo) }
+        val isHibernationSwitchEnabledStateFlow = MutableStateFlow(false)
 
         appInfoProvider.AppInfo()
 
-        AppButtons(packageInfoPresenter)
+        AppButtons(packageInfoPresenter, isHibernationSwitchEnabledStateFlow)
 
         AppSettingsPreference(app)
         AppAllServicesPreference(app)
@@ -152,7 +154,7 @@
         DefaultAppShortcuts(app)
 
         Category(title = stringResource(R.string.unused_apps_category)) {
-            HibernationSwitchPreference(app)
+            HibernationSwitchPreference(app, isHibernationSwitchEnabledStateFlow)
         }
 
         Category(title = stringResource(R.string.advanced_apps)) {
diff --git a/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt b/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt
index 324fa06..4f47266 100644
--- a/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt
@@ -48,11 +48,15 @@
 import kotlin.coroutines.suspendCoroutine
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.withContext
 
 @Composable
-fun HibernationSwitchPreference(app: ApplicationInfo) {
+fun HibernationSwitchPreference(
+    app: ApplicationInfo,
+    isHibernationSwitchEnabledStateFlow: MutableStateFlow<Boolean>
+) {
     val context = LocalContext.current
     val presenter = remember(app) { HibernationSwitchPresenter(context, app) }
     if (!presenter.isAvailable()) return
@@ -73,7 +77,14 @@
                     context.getString(R.string.unused_apps_switch_summary)
             }
             override val changeable = { isEligibleState }
-            override val checked = { if (changeable()) isCheckedState.value else false }
+            override val checked = {
+                val result = if (changeable()) isCheckedState.value else false
+                result.also { isChecked ->
+                    isChecked?.let {
+                        isHibernationSwitchEnabledStateFlow.value = it
+                    }
+                }
+            }
             override val onCheckedChange = presenter::onCheckedChange
         }
     })
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppArchiveButtonTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppArchiveButtonTest.kt
index cc5e365..df1f153 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppArchiveButtonTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppArchiveButtonTest.kt
@@ -26,8 +26,10 @@
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settings.R
+import com.android.settingslib.spa.testutils.delay
 import com.android.settingslib.spa.widget.button.ActionButton
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableStateFlow
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -52,6 +54,8 @@
 
     private val packageInstaller = mock<PackageInstaller>()
 
+    private val isHibernationSwitchEnabledStateFlow = MutableStateFlow(true)
+
     private lateinit var appArchiveButton: AppArchiveButton
 
     @Before
@@ -60,7 +64,7 @@
         whenever(packageInfoPresenter.userPackageManager).thenReturn(userPackageManager)
         whenever(userPackageManager.packageInstaller).thenReturn(packageInstaller)
         whenever(packageInfoPresenter.packageName).thenReturn(PACKAGE_NAME)
-        appArchiveButton = AppArchiveButton(packageInfoPresenter)
+        appArchiveButton = AppArchiveButton(packageInfoPresenter, isHibernationSwitchEnabledStateFlow)
     }
 
     @Test
@@ -90,6 +94,20 @@
     }
 
     @Test
+    fun appArchiveButton_whenIsHibernationSwitchDisabled_isDisabled() {
+        val app = ApplicationInfo().apply {
+            packageName = PACKAGE_NAME
+            isArchived = false
+            flags = ApplicationInfo.FLAG_INSTALLED
+        }
+        whenever(userPackageManager.isAppArchivable(app.packageName)).thenReturn(true)
+        isHibernationSwitchEnabledStateFlow.value = false
+        val enabledActionButton = setContent(app)
+
+        assertThat(enabledActionButton.enabled).isFalse()
+    }
+
+    @Test
     fun appArchiveButton_displaysRightTextAndIcon() {
         val app = ApplicationInfo().apply {
             packageName = PACKAGE_NAME
@@ -126,6 +144,7 @@
         composeTestRule.setContent {
             actionButton = appArchiveButton.getActionButton(app)
         }
+        composeTestRule.delay()
         return actionButton
     }
 
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonsTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonsTest.kt
index 6d22c92..733e1a4 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonsTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonsTest.kt
@@ -68,6 +68,7 @@
     private lateinit var packageInstaller: PackageInstaller
 
     private val featureFlags = FakeFeatureFlagsImpl()
+    private val isHibernationSwitchEnabledStateFlow = MutableStateFlow(true)
 
     @Before
     fun setUp() {
@@ -175,7 +176,7 @@
     private fun setContent(packageInfo: PackageInfo = PACKAGE_INFO) {
         whenever(packageInfoPresenter.flow).thenReturn(MutableStateFlow(packageInfo))
         composeTestRule.setContent {
-            AppButtons(packageInfoPresenter, featureFlags)
+            AppButtons(packageInfoPresenter, isHibernationSwitchEnabledStateFlow, featureFlags)
         }
 
         composeTestRule.delay()
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
index 57e31da..cc2c1e1 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
@@ -70,6 +70,7 @@
 import org.mockito.junit.MockitoJUnit
 import org.mockito.junit.MockitoRule
 import java.util.function.IntConsumer
+import kotlinx.coroutines.flow.MutableStateFlow
 import org.mockito.Mockito.`when` as whenever
 
 @RunWith(AndroidJUnit4::class)
@@ -99,6 +100,8 @@
     private val hibernationTargetsPreSConfig =
         TestDeviceConfig(NAMESPACE_APP_HIBERNATION, PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS)
 
+    private val isHibernationSwitchEnabledStateFlow = MutableStateFlow(true)
+
     @Before
     fun setUp() {
         hibernationEnabledConfig.override(true)
@@ -234,7 +237,7 @@
     private fun setContent(app: ApplicationInfo = TARGET_R_APP) {
         composeTestRule.setContent {
             CompositionLocalProvider(LocalContext provides context) {
-                HibernationSwitchPreference(app)
+                HibernationSwitchPreference(app, isHibernationSwitchEnabledStateFlow)
             }
         }
     }