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