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.datausage.DataUsageUtils
33 import com.android.settings.datausage.lib.DataUsageFormatter.FormattedDataUsage
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.settingslib.spaprivileged.framework.compose.getPlaceholder
38 import kotlinx.coroutines.Dispatchers
39 import kotlinx.coroutines.launch
40 import kotlinx.coroutines.withContext
41 
42 /**
43  * Preference controller for "Data usage"
44  */
45 class DataUsagePreferenceController(context: Context, key: String) :
46     TelephonyBasePreferenceController(context, key) {
47 
48     private lateinit var preference: Preference
49     private var networkTemplate: NetworkTemplate? = null
50 
51     fun init(subId: Int) {
52         mSubId = subId
53     }
54 
55     override fun getAvailabilityStatus(subId: Int): Int = when {
56         SubscriptionManager.isValidSubscriptionId(subId) &&
57             DataUsageUtils.hasMobileData(mContext) -> AVAILABLE
58 
59         else -> AVAILABLE_UNSEARCHABLE
60     }
61 
62     override fun displayPreference(screen: PreferenceScreen) {
63         super.displayPreference(screen)
64         preference = screen.findPreference(preferenceKey)!!
65     }
66 
67     override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
68         preference.summary = mContext.getPlaceholder()
69         viewLifecycleOwner.lifecycleScope.launch {
70             viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
71                 update()
72             }
73         }
74     }
75 
76     override fun handlePreferenceTreeClick(preference: Preference): Boolean {
77         if (preference.key != preferenceKey || networkTemplate == null) return false
78         val intent = Intent(Settings.ACTION_MOBILE_DATA_USAGE).apply {
79             setPackage(mContext.packageName)
80             putExtra(Settings.EXTRA_NETWORK_TEMPLATE, networkTemplate)
81             putExtra(Settings.EXTRA_SUB_ID, mSubId)
82         }
83         mContext.startActivity(intent)
84         return true
85     }
86 
87     private suspend fun update() {
88         val (summary, enabled) = withContext(Dispatchers.Default) {
89             networkTemplate = getNetworkTemplate()
90             getDataUsageSummaryAndEnabled()
91         }
92         preference.isEnabled = enabled
93         preference.summary = summary?.displayText
94     }
95 
96     private fun getNetworkTemplate(): NetworkTemplate? = when {
97         SubscriptionManager.isValidSubscriptionId(mSubId) -> {
98             DataUsageLib.getMobileTemplate(mContext, mSubId)
99         }
100 
101         else -> null
102     }
103 
104     @VisibleForTesting
105     fun createNetworkCycleDataRepository(): NetworkCycleDataRepository? =
106         networkTemplate?.let { NetworkCycleDataRepository(mContext, it) }
107 
108     private fun getDataUsageSummaryAndEnabled(): Pair<FormattedDataUsage?, Boolean> {
109         val repository = createNetworkCycleDataRepository() ?: return null to false
110 
111         repository.loadFirstCycle()?.let { usageData ->
112             val formattedDataUsage = usageData.formatUsage(mContext)
113                 .format(mContext, R.string.data_usage_template, usageData.formatDateRange(mContext))
114             val hasUsage = usageData.usage > 0 || repository.queryUsage(AllTimeRange).usage > 0
115             return formattedDataUsage to hasUsage
116         }
117 
118         val allTimeUsage = repository.queryUsage(AllTimeRange)
119         return allTimeUsage.getDataUsedString(mContext) to (allTimeUsage.usage > 0)
120     }
121 }
122