Refresh DataUsageSummaryPreferenceController
When re-enter the page contains it. Fix: 341234382 Test: manual - on Data usage Test: unit test Change-Id: Ib6a4624e11b60d703c35cea07232cc24f1516389
This commit is contained in:
@@ -21,20 +21,18 @@ import android.net.NetworkPolicy
|
||||
import android.net.NetworkTemplate
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.preference.PreferenceScreen
|
||||
import com.android.settings.R
|
||||
import com.android.settings.datausage.lib.DataUsageLib.getMobileTemplate
|
||||
import com.android.settings.datausage.lib.INetworkCycleDataRepository
|
||||
import com.android.settings.datausage.lib.NetworkCycleDataRepository
|
||||
import com.android.settings.network.ProxySubscriptionManager
|
||||
import com.android.settings.network.policy.NetworkPolicyRepository
|
||||
import com.android.settings.network.telephony.TelephonyBasePreferenceController
|
||||
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
|
||||
import kotlin.math.max
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
@@ -47,6 +45,7 @@ open class DataUsageSummaryPreferenceController @JvmOverloads constructor(
|
||||
subId: Int,
|
||||
private val proxySubscriptionManager: ProxySubscriptionManager =
|
||||
ProxySubscriptionManager.getInstance(context),
|
||||
private val networkPolicyRepository: NetworkPolicyRepository = NetworkPolicyRepository(context),
|
||||
private val networkCycleDataRepositoryFactory: (
|
||||
template: NetworkTemplate,
|
||||
) -> INetworkCycleDataRepository = { NetworkCycleDataRepository(context, it) },
|
||||
@@ -64,37 +63,37 @@ open class DataUsageSummaryPreferenceController @JvmOverloads constructor(
|
||||
proxySubscriptionManager.getAccessibleSubscriptionInfo(mSubId)
|
||||
} else null
|
||||
}
|
||||
|
||||
private val networkTemplate by lazy { getMobileTemplate(mContext, mSubId) }
|
||||
|
||||
private val networkCycleDataRepository by lazy {
|
||||
networkCycleDataRepositoryFactory(getMobileTemplate(mContext, mSubId))
|
||||
networkCycleDataRepositoryFactory(networkTemplate)
|
||||
}
|
||||
private val policy by lazy { networkCycleDataRepository.getPolicy() }
|
||||
|
||||
private lateinit var preference: DataUsageSummaryPreference
|
||||
|
||||
override fun getAvailabilityStatus(subId: Int) =
|
||||
if (subInfo != null && policy != null) AVAILABLE else CONDITIONALLY_UNAVAILABLE
|
||||
if (subInfo != null) AVAILABLE else CONDITIONALLY_UNAVAILABLE
|
||||
|
||||
override fun displayPreference(screen: PreferenceScreen) {
|
||||
super.displayPreference(screen)
|
||||
preference = screen.findPreference(preferenceKey)!!
|
||||
policy?.let {
|
||||
preference.setLimitInfo(it.getLimitInfo())
|
||||
val dataBarSize = max(it.limitBytes, it.warningBytes)
|
||||
if (dataBarSize > NetworkPolicy.WARNING_DISABLED) {
|
||||
setDataBarSize(dataBarSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
update()
|
||||
networkPolicyRepository.networkPolicyFlow(networkTemplate)
|
||||
.collectLatestWithLifecycle(viewLifecycleOwner) { policy ->
|
||||
preference.isVisible = subInfo != null && policy != null
|
||||
if (policy != null) update(policy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun update() {
|
||||
val policy = policy ?: return
|
||||
private suspend fun update(policy: NetworkPolicy) {
|
||||
preference.setLimitInfo(policy.getLimitInfo())
|
||||
val dataBarSize = max(policy.limitBytes, policy.warningBytes)
|
||||
if (dataBarSize > NetworkPolicy.WARNING_DISABLED) {
|
||||
setDataBarSize(dataBarSize)
|
||||
}
|
||||
val dataPlanInfo = withContext(Dispatchers.Default) {
|
||||
dataPlanRepositoryFactory(networkCycleDataRepository).getDataPlanInfo(
|
||||
policy = policy,
|
||||
|
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.network.policy
|
||||
|
||||
import android.content.Context
|
||||
import android.net.NetworkPolicy
|
||||
import android.net.NetworkPolicyManager
|
||||
import android.net.NetworkTemplate
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
|
||||
class NetworkPolicyRepository(context: Context) {
|
||||
private val networkPolicyManager = context.getSystemService(NetworkPolicyManager::class.java)!!
|
||||
|
||||
fun getNetworkPolicy(networkTemplate: NetworkTemplate): NetworkPolicy? =
|
||||
networkPolicyManager.networkPolicies.find { policy -> policy.template == networkTemplate }
|
||||
|
||||
fun networkPolicyFlow(networkTemplate: NetworkTemplate): Flow<NetworkPolicy?> = flow {
|
||||
emit(getNetworkPolicy(networkTemplate))
|
||||
}.flowOn(Dispatchers.Default)
|
||||
}
|
@@ -32,8 +32,10 @@ import com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILA
|
||||
import com.android.settings.datausage.lib.INetworkCycleDataRepository
|
||||
import com.android.settings.datausage.lib.NetworkUsageData
|
||||
import com.android.settings.network.ProxySubscriptionManager
|
||||
import com.android.settings.network.policy.NetworkPolicyRepository
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@@ -41,6 +43,7 @@ import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.argumentCaptor
|
||||
import org.mockito.kotlin.clearInvocations
|
||||
import org.mockito.kotlin.doAnswer
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.never
|
||||
@@ -69,6 +72,10 @@ class DataUsageSummaryPreferenceControllerTest {
|
||||
on { get() } doReturn mockSubscriptionManager
|
||||
}
|
||||
|
||||
private val mockNetworkPolicyRepository = mock<NetworkPolicyRepository> {
|
||||
on { networkPolicyFlow(any()) } doAnswer { flowOf(policy) }
|
||||
}
|
||||
|
||||
private val fakeNetworkCycleDataRepository = object : INetworkCycleDataRepository {
|
||||
override fun getCycles(): List<Range<Long>> = emptyList()
|
||||
override fun getPolicy() = policy
|
||||
@@ -86,6 +93,7 @@ class DataUsageSummaryPreferenceControllerTest {
|
||||
context = context,
|
||||
subId = SUB_ID,
|
||||
proxySubscriptionManager = mockProxySubscriptionManager,
|
||||
networkPolicyRepository = mockNetworkPolicyRepository,
|
||||
networkCycleDataRepositoryFactory = { fakeNetworkCycleDataRepository },
|
||||
dataPlanRepositoryFactory = { fakeDataPlanRepository },
|
||||
)
|
||||
@@ -112,7 +120,7 @@ class DataUsageSummaryPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAvailabilityStatus_hasSubInfoAndPolicy_available() {
|
||||
fun getAvailabilityStatus_hasSubInfo_available() {
|
||||
mockProxySubscriptionManager.stub {
|
||||
on { getAccessibleSubscriptionInfo(SUB_ID) } doReturn SubscriptionInfo.Builder().build()
|
||||
}
|
||||
@@ -134,36 +142,43 @@ class DataUsageSummaryPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAvailabilityStatus_noPolicy_conditionallyUnavailable() {
|
||||
fun onViewCreated_noPolicy_setInvisible() = runBlocking {
|
||||
policy = null
|
||||
controller.displayPreference(preferenceScreen)
|
||||
clearInvocations(preference)
|
||||
|
||||
val availabilityStatus = controller.getAvailabilityStatus(SUB_ID)
|
||||
controller.onViewCreated(TestLifecycleOwner())
|
||||
delay(100)
|
||||
|
||||
assertThat(availabilityStatus).isEqualTo(CONDITIONALLY_UNAVAILABLE)
|
||||
verify(preference).isVisible = false
|
||||
}
|
||||
|
||||
@Test
|
||||
fun displayPreference_policyHasNoLimitInfo() {
|
||||
fun onViewCreated_policyHasNoLimitInfo() = runBlocking {
|
||||
policy = mock<NetworkPolicy>().apply {
|
||||
warningBytes = NetworkPolicy.WARNING_DISABLED
|
||||
limitBytes = NetworkPolicy.LIMIT_DISABLED
|
||||
}
|
||||
|
||||
controller.displayPreference(preferenceScreen)
|
||||
|
||||
controller.onViewCreated(TestLifecycleOwner())
|
||||
delay(100)
|
||||
|
||||
verify(preference).setLimitInfo(null)
|
||||
verify(preference, never()).setLabels(any(), any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun displayPreference_policyWarningOnly() {
|
||||
fun onViewCreated_policyWarningOnly() = runBlocking {
|
||||
policy = mock<NetworkPolicy>().apply {
|
||||
warningBytes = 1L
|
||||
limitBytes = NetworkPolicy.LIMIT_DISABLED
|
||||
}
|
||||
|
||||
controller.displayPreference(preferenceScreen)
|
||||
|
||||
controller.onViewCreated(TestLifecycleOwner())
|
||||
delay(100)
|
||||
|
||||
val limitInfo = argumentCaptor {
|
||||
verify(preference).setLimitInfo(capture())
|
||||
}.firstValue.toString()
|
||||
@@ -172,14 +187,16 @@ class DataUsageSummaryPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun displayPreference_policyLimitOnly() {
|
||||
fun onViewCreated_policyLimitOnly() = runBlocking {
|
||||
policy = mock<NetworkPolicy>().apply {
|
||||
warningBytes = NetworkPolicy.WARNING_DISABLED
|
||||
limitBytes = 1L
|
||||
}
|
||||
|
||||
controller.displayPreference(preferenceScreen)
|
||||
|
||||
controller.onViewCreated(TestLifecycleOwner())
|
||||
delay(100)
|
||||
|
||||
val limitInfo = argumentCaptor {
|
||||
verify(preference).setLimitInfo(capture())
|
||||
}.firstValue.toString()
|
||||
@@ -188,14 +205,16 @@ class DataUsageSummaryPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun displayPreference_policyHasWarningAndLimit() {
|
||||
fun onViewCreated_policyHasWarningAndLimit() = runBlocking {
|
||||
policy = mock<NetworkPolicy>().apply {
|
||||
warningBytes = BillingCycleSettings.GIB_IN_BYTES / 2
|
||||
limitBytes = BillingCycleSettings.GIB_IN_BYTES
|
||||
}
|
||||
|
||||
controller.displayPreference(preferenceScreen)
|
||||
|
||||
controller.onViewCreated(TestLifecycleOwner())
|
||||
delay(100)
|
||||
|
||||
val limitInfo = argumentCaptor {
|
||||
verify(preference).setLimitInfo(capture())
|
||||
}.firstValue.toString()
|
||||
@@ -207,7 +226,6 @@ class DataUsageSummaryPreferenceControllerTest {
|
||||
fun onViewCreated_emptyDataPlanInfo() = runBlocking {
|
||||
dataPlanInfo = EMPTY_DATA_PLAN_INFO
|
||||
controller.displayPreference(preferenceScreen)
|
||||
clearInvocations(preference)
|
||||
|
||||
controller.onViewCreated(TestLifecycleOwner())
|
||||
delay(100)
|
||||
@@ -229,7 +247,6 @@ class DataUsageSummaryPreferenceControllerTest {
|
||||
fun onViewCreated_positiveDataPlanInfo() = runBlocking {
|
||||
dataPlanInfo = POSITIVE_DATA_PLAN_INFO
|
||||
controller.displayPreference(preferenceScreen)
|
||||
clearInvocations(preference)
|
||||
|
||||
controller.onViewCreated(TestLifecycleOwner())
|
||||
delay(100)
|
||||
|
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.network.policy
|
||||
|
||||
import android.content.Context
|
||||
import android.net.NetworkPolicy
|
||||
import android.net.NetworkPolicyManager
|
||||
import android.net.NetworkTemplate
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.spy
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class NetworkPolicyRepositoryTest {
|
||||
|
||||
private val mockNetworkPolicyManager = mock<NetworkPolicyManager> {
|
||||
on { networkPolicies } doReturn arrayOf(Policy1, Policy2)
|
||||
}
|
||||
|
||||
private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
|
||||
on { getSystemService(NetworkPolicyManager::class.java) } doReturn mockNetworkPolicyManager
|
||||
}
|
||||
|
||||
private val repository = NetworkPolicyRepository(context)
|
||||
|
||||
@Test
|
||||
fun getNetworkPolicy() {
|
||||
val networkPolicy = repository.getNetworkPolicy(Template1)
|
||||
|
||||
assertThat(networkPolicy).isSameInstanceAs(Policy1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun networkPolicyFlow() = runBlocking {
|
||||
val networkPolicy = repository.networkPolicyFlow(Template2).firstWithTimeoutOrNull()
|
||||
|
||||
assertThat(networkPolicy).isSameInstanceAs(Policy2)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val Template1: NetworkTemplate =
|
||||
NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE).build()
|
||||
val Template2: NetworkTemplate = NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build()
|
||||
val Policy1 = mock<NetworkPolicy>().apply {
|
||||
template = Template1
|
||||
}
|
||||
val Policy2 = mock<NetworkPolicy>().apply {
|
||||
template = Template2
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user