Use MobileDataEnabledFlow in BillingCyclePreference
To easily collect the mobile data enabled setting changes. Bug: 308903704 Test: manual - on Mobile Settings Test: unit test Change-Id: Ic449ce14fad38513b1e13facc6a192d30318c7b0
This commit is contained in:
@@ -16,15 +16,21 @@ package com.android.settings.datausage
|
|||||||
|
|
||||||
import android.app.settings.SettingsEnums
|
import android.app.settings.SettingsEnums
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.net.NetworkTemplate
|
import android.net.NetworkTemplate
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import androidx.preference.Preference
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.core.SubSettingLauncher
|
import com.android.settings.core.SubSettingLauncher
|
||||||
import com.android.settings.datausage.lib.BillingCycleRepository
|
import com.android.settings.datausage.lib.BillingCycleRepository
|
||||||
import com.android.settings.network.MobileDataEnabledListener
|
import com.android.settings.network.mobileDataEnabledFlow
|
||||||
|
import com.android.settings.spa.preference.ComposePreference
|
||||||
|
import com.android.settingslib.spa.widget.preference.Preference
|
||||||
|
import com.android.settingslib.spa.widget.preference.PreferenceModel
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preference which displays billing cycle of subscription
|
* Preference which displays billing cycle of subscription
|
||||||
@@ -36,45 +42,31 @@ class BillingCyclePreference @JvmOverloads constructor(
|
|||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet?,
|
attrs: AttributeSet?,
|
||||||
private val repository: BillingCycleRepository = BillingCycleRepository(context),
|
private val repository: BillingCycleRepository = BillingCycleRepository(context),
|
||||||
) : Preference(context, attrs), TemplatePreference {
|
) : ComposePreference(context, attrs), TemplatePreference {
|
||||||
private lateinit var template: NetworkTemplate
|
|
||||||
private var subId = 0
|
|
||||||
|
|
||||||
private val listener = MobileDataEnabledListener(context) {
|
|
||||||
updateEnabled()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setTemplate(template: NetworkTemplate, subId: Int) {
|
override fun setTemplate(template: NetworkTemplate, subId: Int) {
|
||||||
this.template = template
|
setContent {
|
||||||
this.subId = subId
|
val isModifiable by remember {
|
||||||
summary = null
|
context.mobileDataEnabledFlow(subId).map { repository.isModifiable(subId) }
|
||||||
updateEnabled()
|
}.collectAsStateWithLifecycle(initialValue = false)
|
||||||
intent = intent
|
|
||||||
|
Preference(object : PreferenceModel {
|
||||||
|
override val title = stringResource(R.string.billing_cycle)
|
||||||
|
override val enabled = { isModifiable }
|
||||||
|
override val onClick = { launchBillingCycleSettings(template) }
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAttached() {
|
private fun launchBillingCycleSettings(template: NetworkTemplate) {
|
||||||
super.onAttached()
|
|
||||||
listener.start(subId)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetached() {
|
|
||||||
listener.stop()
|
|
||||||
super.onDetached()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateEnabled() {
|
|
||||||
isEnabled = repository.isModifiable(subId)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getIntent(): Intent {
|
|
||||||
val args = Bundle().apply {
|
val args = Bundle().apply {
|
||||||
putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, template)
|
putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, template)
|
||||||
}
|
}
|
||||||
return SubSettingLauncher(context).apply {
|
SubSettingLauncher(context).apply {
|
||||||
setDestination(BillingCycleSettings::class.java.name)
|
setDestination(BillingCycleSettings::class.java.name)
|
||||||
setArguments(args)
|
setArguments(args)
|
||||||
setTitleRes(R.string.billing_cycle)
|
setTitleRes(R.string.billing_cycle)
|
||||||
setSourceMetricsCategory(SettingsEnums.PAGE_UNKNOWN)
|
setSourceMetricsCategory(SettingsEnums.PAGE_UNKNOWN)
|
||||||
}.toIntent()
|
}.launch()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,7 @@ package com.android.settings.spa.preference
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.platform.ComposeView
|
import androidx.compose.ui.platform.ComposeView
|
||||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||||
@@ -26,13 +27,23 @@ import androidx.preference.PreferenceViewHolder
|
|||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settingslib.spa.framework.theme.SettingsTheme
|
import com.android.settingslib.spa.framework.theme.SettingsTheme
|
||||||
|
|
||||||
class ComposePreference @JvmOverloads constructor(
|
open class ComposePreference @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = 0,
|
defStyleAttr: Int = 0,
|
||||||
defStyleRes: Int = 0,
|
defStyleRes: Int = 0,
|
||||||
) : Preference(context, attrs, defStyleAttr, defStyleRes) {
|
) : Preference(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
var content: @Composable () -> Unit = {}
|
private var content: @Composable () -> Unit = {}
|
||||||
|
|
||||||
|
fun setContent(content: @Composable () -> Unit) {
|
||||||
|
this.content = content
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
@Composable
|
||||||
|
fun Content() {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
layoutResource = R.layout.preference_compose
|
layoutResource = R.layout.preference_compose
|
||||||
|
@@ -29,7 +29,7 @@ abstract class ComposePreferenceController(context: Context, preferenceKey: Stri
|
|||||||
override fun displayPreference(screen: PreferenceScreen) {
|
override fun displayPreference(screen: PreferenceScreen) {
|
||||||
super.displayPreference(screen)
|
super.displayPreference(screen)
|
||||||
preference = screen.findPreference(preferenceKey)!!
|
preference = screen.findPreference(preferenceKey)!!
|
||||||
preference.content = { Content() }
|
preference.setContent { Content() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@@ -18,40 +18,69 @@ package com.android.settings.datausage
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.NetworkTemplate
|
import android.net.NetworkTemplate
|
||||||
|
import androidx.compose.ui.test.assertIsDisplayed
|
||||||
|
import androidx.compose.ui.test.assertIsEnabled
|
||||||
|
import androidx.compose.ui.test.assertIsNotEnabled
|
||||||
|
import androidx.compose.ui.test.junit4.createComposeRule
|
||||||
|
import androidx.compose.ui.test.onNodeWithText
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import com.android.settings.R
|
||||||
import com.android.settings.datausage.lib.BillingCycleRepository
|
import com.android.settings.datausage.lib.BillingCycleRepository
|
||||||
import com.google.common.truth.Truth.assertThat
|
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.kotlin.doReturn
|
import org.mockito.kotlin.doReturn
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
|
import org.mockito.kotlin.stub
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class BillingCyclePreferenceTest {
|
class BillingCyclePreferenceTest {
|
||||||
|
@get:Rule
|
||||||
|
val composeTestRule = createComposeRule()
|
||||||
|
|
||||||
private val mockBillingCycleRepository = mock<BillingCycleRepository> {
|
private val mockBillingCycleRepository = mock<BillingCycleRepository>()
|
||||||
on { isModifiable(SUB_ID) } doReturn false
|
|
||||||
}
|
|
||||||
|
|
||||||
private val context: Context = ApplicationProvider.getApplicationContext()
|
private val context: Context = ApplicationProvider.getApplicationContext()
|
||||||
|
|
||||||
private val preference = BillingCyclePreference(context, null, mockBillingCycleRepository)
|
private val preference = BillingCyclePreference(context, null, mockBillingCycleRepository)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun isEnabled_initialState() {
|
fun setTemplate_titleDisplayed() {
|
||||||
val enabled = preference.isEnabled
|
setTemplate()
|
||||||
|
|
||||||
assertThat(enabled).isTrue()
|
composeTestRule.onNodeWithText(context.getString(R.string.billing_cycle))
|
||||||
|
.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun isEnabled_afterSetTemplate_updated() {
|
fun setTemplate_modifiable_enabled() {
|
||||||
|
mockBillingCycleRepository.stub {
|
||||||
|
on { isModifiable(SUB_ID) } doReturn true
|
||||||
|
}
|
||||||
|
|
||||||
|
setTemplate()
|
||||||
|
|
||||||
|
composeTestRule.onNodeWithText(context.getString(R.string.billing_cycle)).assertIsEnabled()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun setTemplate_notModifiable_notEnabled() {
|
||||||
|
mockBillingCycleRepository.stub {
|
||||||
|
on { isModifiable(SUB_ID) } doReturn false
|
||||||
|
}
|
||||||
|
|
||||||
|
setTemplate()
|
||||||
|
|
||||||
|
composeTestRule.onNodeWithText(context.getString(R.string.billing_cycle))
|
||||||
|
.assertIsNotEnabled()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setTemplate() {
|
||||||
preference.setTemplate(mock<NetworkTemplate>(), SUB_ID)
|
preference.setTemplate(mock<NetworkTemplate>(), SUB_ID)
|
||||||
|
composeTestRule.setContent {
|
||||||
val enabled = preference.isEnabled
|
preference.Content()
|
||||||
|
}
|
||||||
assertThat(enabled).isFalse()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
@@ -61,7 +61,7 @@ class ComposePreferenceControllerTest {
|
|||||||
controller.displayPreference(preferenceScreen)
|
controller.displayPreference(preferenceScreen)
|
||||||
|
|
||||||
composeTestRule.setContent {
|
composeTestRule.setContent {
|
||||||
preference.content()
|
preference.Content()
|
||||||
}
|
}
|
||||||
composeTestRule.onNodeWithText(TEXT).assertIsDisplayed()
|
composeTestRule.onNodeWithText(TEXT).assertIsDisplayed()
|
||||||
}
|
}
|
||||||
|
@@ -43,7 +43,7 @@ class ComposePreferenceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun onBindViewHolder() {
|
fun onBindViewHolder() {
|
||||||
preference.content = {
|
preference.setContent {
|
||||||
Text(TEXT)
|
Text(TEXT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user