Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4e2fa570 authored by Chaohui Wang's avatar Chaohui Wang Committed by Android (Google) Code Review
Browse files

Merge "Use MobileDataEnabledFlow in BillingCyclePreference" into main

parents 097739ec 0739b5ed
Loading
Loading
Loading
Loading
+23 −31
Original line number Diff line number Diff line
@@ -16,15 +16,21 @@ package com.android.settings.datausage

import android.app.settings.SettingsEnums
import android.content.Context
import android.content.Intent
import android.net.NetworkTemplate
import android.os.Bundle
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.core.SubSettingLauncher
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
@@ -36,45 +42,31 @@ class BillingCyclePreference @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet?,
    private val repository: BillingCycleRepository = BillingCycleRepository(context),
) : Preference(context, attrs), TemplatePreference {
    private lateinit var template: NetworkTemplate
    private var subId = 0

    private val listener = MobileDataEnabledListener(context) {
        updateEnabled()
    }
) : ComposePreference(context, attrs), TemplatePreference {

    override fun setTemplate(template: NetworkTemplate, subId: Int) {
        this.template = template
        this.subId = subId
        summary = null
        updateEnabled()
        intent = intent
    }
        setContent {
            val isModifiable by remember {
                context.mobileDataEnabledFlow(subId).map { repository.isModifiable(subId) }
            }.collectAsStateWithLifecycle(initialValue = false)

    override fun onAttached() {
        super.onAttached()
        listener.start(subId)
            Preference(object : PreferenceModel {
                override val title = stringResource(R.string.billing_cycle)
                override val enabled = { isModifiable }
                override val onClick = { launchBillingCycleSettings(template) }
            })
        }

    override fun onDetached() {
        listener.stop()
        super.onDetached()
    }

    private fun updateEnabled() {
        isEnabled = repository.isModifiable(subId)
    }

    override fun getIntent(): Intent {
    private fun launchBillingCycleSettings(template: NetworkTemplate) {
        val args = Bundle().apply {
            putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, template)
        }
        return SubSettingLauncher(context).apply {
        SubSettingLauncher(context).apply {
            setDestination(BillingCycleSettings::class.java.name)
            setArguments(args)
            setTitleRes(R.string.billing_cycle)
            setSourceMetricsCategory(SettingsEnums.PAGE_UNKNOWN)
        }.toIntent()
        }.launch()
    }
}
+13 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settings.spa.preference

import android.content.Context
import android.util.AttributeSet
import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
@@ -26,13 +27,23 @@ import androidx.preference.PreferenceViewHolder
import com.android.settings.R
import com.android.settingslib.spa.framework.theme.SettingsTheme

class ComposePreference @JvmOverloads constructor(
open class ComposePreference @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
    defStyleRes: Int = 0,
) : 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 {
        layoutResource = R.layout.preference_compose
+1 −1
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ abstract class ComposePreferenceController(context: Context, preferenceKey: Stri
    override fun displayPreference(screen: PreferenceScreen) {
        super.displayPreference(screen)
        preference = screen.findPreference(preferenceKey)!!
        preference.content = { Content() }
        preference.setContent { Content() }
    }

    @Composable
+40 −11
Original line number Diff line number Diff line
@@ -18,40 +18,69 @@ package com.android.settings.datausage

import android.content.Context
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.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
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.runner.RunWith
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.stub

@RunWith(AndroidJUnit4::class)
class BillingCyclePreferenceTest {
    @get:Rule
    val composeTestRule = createComposeRule()

    private val mockBillingCycleRepository = mock<BillingCycleRepository> {
        on { isModifiable(SUB_ID) } doReturn false
    }
    private val mockBillingCycleRepository = mock<BillingCycleRepository>()

    private val context: Context = ApplicationProvider.getApplicationContext()

    private val preference = BillingCyclePreference(context, null, mockBillingCycleRepository)

    @Test
    fun isEnabled_initialState() {
        val enabled = preference.isEnabled
    fun setTemplate_titleDisplayed() {
        setTemplate()

        assertThat(enabled).isTrue()
        composeTestRule.onNodeWithText(context.getString(R.string.billing_cycle))
            .assertIsDisplayed()
    }

    @Test
    fun isEnabled_afterSetTemplate_updated() {
        preference.setTemplate(mock<NetworkTemplate>(), SUB_ID)
    fun setTemplate_modifiable_enabled() {
        mockBillingCycleRepository.stub {
            on { isModifiable(SUB_ID) } doReturn true
        }

        val enabled = preference.isEnabled
        setTemplate()

        assertThat(enabled).isFalse()
        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)
        composeTestRule.setContent {
            preference.Content()
        }
    }

    private companion object {
+1 −1
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ class ComposePreferenceControllerTest {
        controller.displayPreference(preferenceScreen)

        composeTestRule.setContent {
            preference.content()
            preference.Content()
        }
        composeTestRule.onNodeWithText(TEXT).assertIsDisplayed()
    }
Loading