• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2023 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.network.telephony
18 
19 import android.content.Context
20 import android.content.Intent
21 import android.net.NetworkTemplate
22 import android.provider.Settings
23 import android.telephony.SubscriptionManager
24 import androidx.annotation.VisibleForTesting
25 import androidx.lifecycle.Lifecycle
26 import androidx.lifecycle.LifecycleOwner
27 import androidx.lifecycle.lifecycleScope
28 import androidx.lifecycle.repeatOnLifecycle
29 import androidx.preference.Preference
30 import androidx.preference.PreferenceScreen
31 import com.android.settings.R
32 import com.android.settings.core.BasePreferenceController
33 import com.android.settings.datausage.DataUsageUtils
34 import com.android.settings.datausage.lib.DataUsageLib
35 import com.android.settings.datausage.lib.NetworkCycleDataRepository
36 import com.android.settings.datausage.lib.NetworkStatsRepository.Companion.AllTimeRange
37 import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem
38 import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult
39 import com.android.settingslib.spaprivileged.framework.compose.getPlaceholder
40 import kotlinx.coroutines.Dispatchers
41 import kotlinx.coroutines.launch
42 import kotlinx.coroutines.withContext
43 
44 /** Preference controller for "Data usage" */
45 class DataUsagePreferenceController(context: Context, key: String) :
46     BasePreferenceController(context, key) {
47 
48     private var subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID
49     private lateinit var preference: Preference
50     private var networkTemplate: NetworkTemplate? = null
51 
52     fun init(subId: Int) {
53         this.subId = subId
54     }
55 
56     override fun getAvailabilityStatus() = AVAILABLE
57 
58     override fun displayPreference(screen: PreferenceScreen) {
59         super.displayPreference(screen)
60         preference = screen.findPreference(preferenceKey)!!
61     }
62 
63     override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
64         preference.summary = mContext.getPlaceholder()
65         viewLifecycleOwner.lifecycleScope.launch {
66             viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
67                 update()
68             }
69         }
70     }
71 
72     override fun handlePreferenceTreeClick(preference: Preference): Boolean {
73         if (preference.key != preferenceKey || networkTemplate == null) return false
74         val intent =
75             Intent(Settings.ACTION_MOBILE_DATA_USAGE).apply {
76                 setPackage(mContext.packageName)
77                 putExtra(Settings.EXTRA_NETWORK_TEMPLATE, networkTemplate)
78                 putExtra(Settings.EXTRA_SUB_ID, subId)
79             }
80         mContext.startActivity(intent)
81         return true
82     }
83 
84     private suspend fun update() {
85         val (summary, enabled) = withContext(Dispatchers.Default) {
86             networkTemplate = getNetworkTemplate()
87             getDataUsageSummaryAndEnabled()
88         }
89         preference.isEnabled = enabled
90         preference.summary = summary
91     }
92 
93     private fun getNetworkTemplate(): NetworkTemplate? =
94         if (SubscriptionManager.isValidSubscriptionId(subId)) {
95             DataUsageLib.getMobileTemplate(mContext, subId)
96         } else null
97 
98     @VisibleForTesting
99     fun createNetworkCycleDataRepository(): NetworkCycleDataRepository? =
100         networkTemplate?.let { NetworkCycleDataRepository(mContext, it) }
101 
102     private fun getDataUsageSummaryAndEnabled(): Pair<String?, Boolean> {
103         val repository = createNetworkCycleDataRepository() ?: return null to false
104 
105         repository.loadFirstCycle()?.let { usageData ->
106             val formattedDataUsage =
107                 mContext.getString(
108                     R.string.data_usage_template,
109                     usageData.formatUsage(mContext),
110                     usageData.formatDateRange(mContext),
111                 )
112             val hasUsage = usageData.usage > 0 || repository.queryUsage(AllTimeRange).usage > 0
113             return formattedDataUsage to hasUsage
114         }
115 
116         val allTimeUsage = repository.queryUsage(AllTimeRange)
117         return allTimeUsage.getDataUsedString(mContext) to (allTimeUsage.usage > 0)
118     }
119 
120     companion object {
121         class DataUsageSearchItem(private val context: Context) : MobileNetworkSettingsSearchItem {
122             override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? {
123                 if (!DataUsageUtils.hasMobileData(context)) return null
124                 return MobileNetworkSettingsSearchResult(
125                     key = "data_usage_summary",
126                     title = context.getString(R.string.app_cellular_data_usage),
127                 )
128             }
129         }
130     }
131 }
132