[Spa] Fix State<T> as a parameter of SwitchPreference

Bug: 292036686
Test: manual - with Settings
Test: unit tests
Change-Id: I003f3b7f29117258da6ae3c48039fb50c2bee95c
This commit is contained in:
Chaohui Wang
2023-11-03 23:42:05 +08:00
parent 6584f32b6a
commit eedc7fd52d
9 changed files with 37 additions and 39 deletions

View File

@@ -38,7 +38,6 @@ import com.android.settings.R
import com.android.settings.network.apn.ApnNetworkTypes.getNetworkTypeDisplayNames import com.android.settings.network.apn.ApnNetworkTypes.getNetworkTypeDisplayNames
import com.android.settings.network.apn.ApnNetworkTypes.getNetworkTypeSelectedOptionsState import com.android.settings.network.apn.ApnNetworkTypes.getNetworkTypeSelectedOptionsState
import com.android.settingslib.spa.framework.common.SettingsPageProvider import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.widget.editor.SettingsExposedDropdownMenuBox import com.android.settingslib.spa.widget.editor.SettingsExposedDropdownMenuBox
import com.android.settingslib.spa.widget.editor.SettingsExposedDropdownMenuCheckBox import com.android.settingslib.spa.widget.editor.SettingsExposedDropdownMenuCheckBox
import com.android.settingslib.spa.widget.editor.SettingsOutlinedTextField import com.android.settingslib.spa.widget.editor.SettingsOutlinedTextField
@@ -186,10 +185,8 @@ fun ApnPage(apnDataInit: ApnData, apnDataCur: MutableState<ApnData>, uriInit: Ur
SwitchPreference( SwitchPreference(
object : SwitchPreferenceModel { object : SwitchPreferenceModel {
override val title = context.resources.getString(R.string.carrier_enabled) override val title = context.resources.getString(R.string.carrier_enabled)
override val changeable = override val changeable = { apnData.apnEnableEnabled }
stateOf(apnData.apnEnableEnabled) override val checked = { apnData.apnEnable }
override val checked =
stateOf(apnData.apnEnable)
override val onCheckedChange = { newChecked: Boolean -> override val onCheckedChange = { newChecked: Boolean ->
apnData = apnData.copy(apnEnable = newChecked) apnData = apnData.copy(apnEnable = newChecked)
} }

View File

@@ -28,7 +28,7 @@ import android.permission.PermissionControllerManager.HIBERNATION_ELIGIBILITY_UN
import android.provider.DeviceConfig import android.provider.DeviceConfig
import android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION import android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -56,18 +56,14 @@ fun HibernationSwitchPreference(app: ApplicationInfo) {
val presenter = remember { HibernationSwitchPresenter(context, app) } val presenter = remember { HibernationSwitchPresenter(context, app) }
if (!presenter.isAvailable()) return if (!presenter.isAvailable()) return
val isEligibleState = presenter.isEligibleFlow.collectAsStateWithLifecycle(initialValue = false) val isEligibleState by presenter.isEligibleFlow.collectAsStateWithLifecycle(initialValue = false)
val isCheckedState = presenter.isCheckedFlow.collectAsStateWithLifecycle(initialValue = null) val isCheckedState = presenter.isCheckedFlow.collectAsStateWithLifecycle(initialValue = null)
SwitchPreference(remember { SwitchPreference(remember {
object : SwitchPreferenceModel { object : SwitchPreferenceModel {
override val title = context.getString(R.string.unused_apps_switch) override val title = context.getString(R.string.unused_apps_switch)
override val summary = { context.getString(R.string.unused_apps_switch_summary) } override val summary = { context.getString(R.string.unused_apps_switch_summary) }
override val changeable = isEligibleState override val changeable = { isEligibleState }
override val checked = { if (changeable()) isCheckedState.value else false }
override val checked = derivedStateOf {
if (!changeable.value) false else isCheckedState.value
}
override val onCheckedChange = presenter::onCheckedChange override val onCheckedChange = presenter::onCheckedChange
} }
}) })

View File

@@ -24,10 +24,9 @@ import android.content.Context
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.os.PowerExemptionManager import android.os.PowerExemptionManager
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.android.settingslib.R import com.android.settingslib.R
import com.android.settingslib.spa.framework.compose.stateOf import com.android.settingslib.spa.livedata.observeAsCallback
import com.android.settingslib.spaprivileged.model.app.AppRecord import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.model.app.IPackageManagers import com.android.settingslib.spaprivileged.model.app.IPackageManagers
import com.android.settingslib.spaprivileged.model.app.PackageManagers import com.android.settingslib.spaprivileged.model.app.PackageManagers
@@ -79,9 +78,10 @@ class AlarmsAndRemindersAppListModel(
} }
@Composable @Composable
override fun isAllowed(record: AlarmsAndRemindersAppRecord) = override fun isAllowed(record: AlarmsAndRemindersAppRecord): () -> Boolean? = when {
if (record.isTrumped) stateOf(true) record.isTrumped -> ({ true })
else record.controller.isAllowed.observeAsState() else -> record.controller.isAllowed.observeAsCallback()
}
override fun isChangeable(record: AlarmsAndRemindersAppRecord) = record.isChangeable override fun isChangeable(record: AlarmsAndRemindersAppRecord) = record.isChangeable

View File

@@ -24,8 +24,8 @@ import android.content.Context
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.os.UserManager import android.os.UserManager
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import com.android.settings.R import com.android.settings.R
import com.android.settingslib.spa.livedata.observeAsCallback
import com.android.settingslib.spaprivileged.model.app.AppOpsController import com.android.settingslib.spaprivileged.model.app.AppOpsController
import com.android.settingslib.spaprivileged.model.app.AppRecord import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.model.app.userId import com.android.settingslib.spaprivileged.model.app.userId
@@ -79,7 +79,7 @@ class InstallUnknownAppsListModel(private val context: Context) :
@Composable @Composable
override fun isAllowed(record: InstallUnknownAppsRecord) = override fun isAllowed(record: InstallUnknownAppsRecord) =
record.appOpsController.isAllowed.observeAsState() record.appOpsController.isAllowed.observeAsCallback()
override fun isChangeable(record: InstallUnknownAppsRecord) = override fun isChangeable(record: InstallUnknownAppsRecord) =
isChangeable(record, getPotentialPackageNames(record.app.userId)) isChangeable(record, getPotentialPackageNames(record.app.userId))

View File

@@ -23,8 +23,8 @@ import android.content.pm.PackageManager.PackageInfoFlags
import android.nfc.NfcAdapter import android.nfc.NfcAdapter
import android.util.Log import android.util.Log
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import com.android.settings.R import com.android.settings.R
import com.android.settingslib.spa.livedata.observeAsCallback
import com.android.settingslib.spaprivileged.model.app.AppRecord import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.model.app.userId import com.android.settingslib.spaprivileged.model.app.userId
import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListModel import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListModel
@@ -100,7 +100,7 @@ class NfcTagAppsSettingsListModel(private val context: Context) :
@Composable @Composable
override fun isAllowed(record: NfcTagAppsSettingsRecord) = override fun isAllowed(record: NfcTagAppsSettingsRecord) =
record.controller.isAllowed.observeAsState() record.controller.isAllowed.observeAsCallback()
override fun isChangeable(record: NfcTagAppsSettingsRecord) = true override fun isChangeable(record: NfcTagAppsSettingsRecord) = true

View File

@@ -25,8 +25,8 @@ import android.content.pm.PackageManager.GET_ACTIVITIES
import android.content.pm.PackageManager.PackageInfoFlags import android.content.pm.PackageManager.PackageInfoFlags
import android.util.Log import android.util.Log
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import com.android.settings.R import com.android.settings.R
import com.android.settingslib.spa.livedata.observeAsCallback
import com.android.settingslib.spaprivileged.model.app.AppOpsController import com.android.settingslib.spaprivileged.model.app.AppOpsController
import com.android.settingslib.spaprivileged.model.app.AppRecord import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.model.app.installed import com.android.settingslib.spaprivileged.model.app.installed
@@ -90,7 +90,7 @@ class PictureInPictureListModel(private val context: Context) :
@Composable @Composable
override fun isAllowed(record: PictureInPictureRecord) = override fun isAllowed(record: PictureInPictureRecord) =
record.appOpsController.isAllowed.observeAsState() record.appOpsController.isAllowed.observeAsCallback()
override fun isChangeable(record: PictureInPictureRecord) = record.isSupport override fun isChangeable(record: PictureInPictureRecord) = record.isSupport

View File

@@ -20,8 +20,9 @@ import android.content.pm.PackageManager
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.AirplanemodeActive import androidx.compose.material.icons.outlined.AirplanemodeActive
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
@@ -37,11 +38,12 @@ fun AirplaneModePreference() {
val context = LocalContext.current val context = LocalContext.current
val controller = remember { AirplaneModeController(context) } val controller = remember { AirplaneModeController(context) }
if (!controller.isAvailable()) return if (!controller.isAvailable()) return
SwitchPreference(object : SwitchPreferenceModel { val checked by controller.airplaneModeState.observeAsState(
override val title = context.getString(R.string.airplane_mode)
override val checked = controller.airplaneModeState.observeAsState(
initial = controller.isAirplaneModeOn() initial = controller.isAirplaneModeOn()
) )
SwitchPreference(object : SwitchPreferenceModel {
override val title = context.getString(R.string.airplane_mode)
override val checked = { checked }
override val onCheckedChange = { newChecked: Boolean -> override val onCheckedChange = { newChecked: Boolean ->
controller.setChecked(newChecked) controller.setChecked(newChecked)
} }

View File

@@ -21,7 +21,7 @@ import android.content.Context
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.icu.text.RelativeDateTimeFormatter import android.icu.text.RelativeDateTimeFormatter
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState import androidx.compose.runtime.produceState
import com.android.settings.R import com.android.settings.R
import com.android.settings.applications.AppInfoBase import com.android.settings.applications.AppInfoBase
@@ -29,6 +29,7 @@ import com.android.settings.notification.app.AppNotificationSettings
import com.android.settings.spa.notification.SpinnerItem.Companion.toSpinnerItem import com.android.settings.spa.notification.SpinnerItem.Companion.toSpinnerItem
import com.android.settingslib.spa.framework.util.asyncFilter import com.android.settingslib.spa.framework.util.asyncFilter
import com.android.settingslib.spa.framework.util.asyncForEach import com.android.settingslib.spa.framework.util.asyncForEach
import com.android.settingslib.spa.livedata.observeAsCallback
import com.android.settingslib.spa.widget.ui.SpinnerOption import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.model.app.AppEntry import com.android.settingslib.spaprivileged.model.app.AppEntry
import com.android.settingslib.spaprivileged.model.app.AppListModel import com.android.settingslib.spaprivileged.model.app.AppListModel
@@ -36,9 +37,11 @@ import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.template.app.AppListItemModel import com.android.settingslib.spaprivileged.template.app.AppListItemModel
import com.android.settingslib.spaprivileged.template.app.AppListTwoTargetSwitchItem import com.android.settingslib.spaprivileged.template.app.AppListTwoTargetSwitchItem
import com.android.settingslib.utils.StringUtil import com.android.settingslib.utils.StringUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
data class AppNotificationsRecord( data class AppNotificationsRecord(
override val app: ApplicationInfo, override val app: ApplicationInfo,
@@ -117,12 +120,15 @@ class AppNotificationsListModel(
@Composable @Composable
override fun AppListItemModel<AppNotificationsRecord>.AppItem() { override fun AppListItemModel<AppNotificationsRecord>.AppItem() {
val changeable by produceState(initialValue = false) {
withContext(Dispatchers.Default) {
value = repository.isChangeable(record.app)
}
}
AppListTwoTargetSwitchItem( AppListTwoTargetSwitchItem(
onClick = { navigateToAppNotificationSettings(app = record.app) }, onClick = { navigateToAppNotificationSettings(app = record.app) },
checked = record.controller.isEnabled.observeAsState(), checked = record.controller.isEnabled.observeAsCallback(),
changeable = produceState(initialValue = false) { changeable = { changeable },
value = repository.isChangeable(record.app)
},
onCheckedChange = record.controller::setEnabled, onCheckedChange = record.controller::setEnabled,
) )
} }

View File

@@ -18,11 +18,8 @@ package com.android.settings.spa.app.specialaccess
import android.Manifest import android.Manifest
import android.app.AppOpsManager import android.app.AppOpsManager
import android.app.AppOpsManager.MODE_ALLOWED
import android.app.AppOpsManager.MODE_DEFAULT
import android.content.Context import android.content.Context
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import androidx.compose.runtime.State
import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.junit4.createComposeRule
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
@@ -40,9 +37,9 @@ import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule import org.mockito.junit.MockitoRule
import org.mockito.Mockito.`when` as whenever
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@@ -248,9 +245,9 @@ class WifiControlAppListModelTest {
} }
private fun getIsAllowed(record: AppOpPermissionRecord): Boolean? { private fun getIsAllowed(record: AppOpPermissionRecord): Boolean? {
lateinit var isAllowedState: State<Boolean?> lateinit var isAllowedState: () -> Boolean?
composeTestRule.setContent { isAllowedState = listModel.isAllowed(record) } composeTestRule.setContent { isAllowedState = listModel.isAllowed(record) }
return isAllowedState.value return isAllowedState()
} }
private companion object { private companion object {