• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.datausage
18 
19 import android.content.Context
20 import android.net.NetworkPolicy
21 import android.net.NetworkTemplate
22 import android.text.TextUtils
23 import android.util.Log
24 import androidx.lifecycle.LifecycleOwner
25 import androidx.preference.PreferenceScreen
26 import com.android.settings.R
27 import com.android.settings.datausage.lib.DataUsageFormatter
28 import com.android.settings.datausage.lib.DataUsageLib.getMobileTemplate
29 import com.android.settings.datausage.lib.INetworkCycleDataRepository
30 import com.android.settings.datausage.lib.NetworkCycleDataRepository
31 import com.android.settings.network.ProxySubscriptionManager
32 import com.android.settings.network.policy.NetworkPolicyRepository
33 import com.android.settings.network.telephony.TelephonyBasePreferenceController
34 import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
35 import kotlin.math.max
36 import kotlinx.coroutines.Dispatchers
37 import kotlinx.coroutines.withContext
38 
39 /**
40  * This is the controller for a data usage header that retrieves carrier data from the new
41  * subscriptions framework API if available. The controller reads subscription information from the
42  * framework and falls back to legacy usage data if none are available.
43  */
44 open class DataUsageSummaryPreferenceController @JvmOverloads constructor(
45     context: Context,
46     subId: Int,
47     private val proxySubscriptionManager: ProxySubscriptionManager =
48         ProxySubscriptionManager.getInstance(context),
49     private val networkPolicyRepository: NetworkPolicyRepository = NetworkPolicyRepository(context),
50     private val networkCycleDataRepositoryFactory: (
51         template: NetworkTemplate,
52     ) -> INetworkCycleDataRepository = { NetworkCycleDataRepository(context, it) },
53     private val dataPlanRepositoryFactory: (
54         networkCycleDataRepository: INetworkCycleDataRepository,
<lambda>null55     ) -> DataPlanRepository = { DataPlanRepositoryImpl(it) }
56 ) : TelephonyBasePreferenceController(context, KEY) {
57 
58     init {
59         mSubId = subId
60     }
61 
<lambda>null62     private val subInfo by lazy {
63         if (DataUsageUtils.hasMobileData(mContext)) {
64             proxySubscriptionManager.getAccessibleSubscriptionInfo(mSubId)
65         } else null
66     }
67 
<lambda>null68     private val networkTemplate by lazy { getMobileTemplate(mContext, mSubId) }
69 
<lambda>null70     private val networkCycleDataRepository by lazy {
71         networkCycleDataRepositoryFactory(networkTemplate)
72     }
73 
74     private lateinit var preference: DataUsageSummaryPreference
75 
76     private val dataUsageFormatter = DataUsageFormatter(mContext)
77 
getAvailabilityStatusnull78     override fun getAvailabilityStatus(subId: Int) =
79         if (subInfo != null) AVAILABLE else CONDITIONALLY_UNAVAILABLE
80 
81     override fun displayPreference(screen: PreferenceScreen) {
82         super.displayPreference(screen)
83         preference = screen.findPreference(preferenceKey)!!
84     }
85 
onViewCreatednull86     override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
87         networkPolicyRepository.networkPolicyFlow(networkTemplate)
88             .collectLatestWithLifecycle(viewLifecycleOwner) { policy ->
89                 preference.isVisible = subInfo != null && policy != null
90                 if (policy != null) update(policy)
91             }
92     }
93 
updatenull94     private suspend fun update(policy: NetworkPolicy) {
95         preference.setLimitInfo(policy.getLimitInfo())
96         val dataBarSize = max(policy.limitBytes, policy.warningBytes)
97         if (dataBarSize > NetworkPolicy.WARNING_DISABLED) {
98             setDataBarSize(dataBarSize)
99         }
100         val dataPlanInfo = withContext(Dispatchers.Default) {
101             dataPlanRepositoryFactory(networkCycleDataRepository).getDataPlanInfo(
102                 policy = policy,
103                 plans = proxySubscriptionManager.get().getSubscriptionPlans(mSubId),
104             )
105         }
106         Log.d(TAG, "dataPlanInfo: $dataPlanInfo")
107         preference.setUsageNumbers(dataPlanInfo.dataPlanUse, dataPlanInfo.dataPlanSize)
108         if (dataPlanInfo.dataBarSize > 0) {
109             preference.setChartEnabled(true)
110             setDataBarSize(dataPlanInfo.dataBarSize)
111             preference.setProgress(dataPlanInfo.dataPlanUse / dataPlanInfo.dataBarSize.toFloat())
112         } else {
113             preference.setChartEnabled(false)
114         }
115 
116         preference.setUsageInfo(
117             dataPlanInfo.cycleEnd,
118             dataPlanInfo.snapshotTime,
119             subInfo?.carrierName,
120             dataPlanInfo.dataPlanCount,
121         )
122     }
123 
setDataBarSizenull124     private fun setDataBarSize(dataBarSize: Long) {
125         preference.setLabels(
126             dataUsageFormatter.formatDataUsage(/* byteValue = */ 0),
127             dataUsageFormatter.formatDataUsage(dataBarSize)
128         )
129     }
130 
getLimitInfonull131     private fun NetworkPolicy.getLimitInfo(): CharSequence? = when {
132         warningBytes > 0 && limitBytes > 0 -> {
133             TextUtils.expandTemplate(
134                 mContext.getText(R.string.cell_data_warning_and_limit),
135                 dataUsageFormatter.formatDataUsage(warningBytes),
136                 dataUsageFormatter.formatDataUsage(limitBytes),
137             )
138         }
139 
140         warningBytes > 0 -> {
141             TextUtils.expandTemplate(
142                 mContext.getText(R.string.cell_data_warning),
143                 dataUsageFormatter.formatDataUsage(warningBytes),
144             )
145         }
146 
147         limitBytes > 0 -> {
148             TextUtils.expandTemplate(
149                 mContext.getText(R.string.cell_data_limit),
150                 dataUsageFormatter.formatDataUsage(limitBytes),
151             )
152         }
153 
154         else -> null
155     }
156 
157     companion object {
158         private const val TAG = "DataUsageSummaryPC"
159         private const val KEY = "status_header"
160     }
161 }
162