Unify the default template and title

On AppDataUsage page, using single source of truth to calculate the
default template, and set title base on the current template.

Fix: 213266028
Fix: 234104784
Test: visual - on AppDataUsage
Test: unit test
Change-Id: I80facca0b000964e901905af51a344a4bc9f498b
This commit is contained in:
Chaohui Wang
2023-10-09 17:43:32 +08:00
parent b7f8c15ff0
commit 6395cf8d30
8 changed files with 119 additions and 94 deletions

View File

@@ -18,13 +18,13 @@ package com.android.settings.spa.app.appinfo
import android.content.Context
import android.content.pm.ApplicationInfo
import android.net.NetworkStats
import android.net.NetworkTemplate
import android.os.Process
import android.text.format.DateUtils
import android.text.format.Formatter
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -32,25 +32,41 @@ import com.android.settings.R
import com.android.settings.Utils
import com.android.settings.applications.appinfo.AppInfoDashboardFragment
import com.android.settings.datausage.AppDataUsage
import com.android.settings.datausage.DataUsageUtils
import com.android.settings.datausage.lib.INetworkTemplates
import com.android.settings.datausage.lib.NetworkTemplates
import com.android.settings.datausage.lib.NetworkTemplates.getTitleResId
import com.android.settingslib.net.NetworkCycleDataForUid
import com.android.settingslib.net.NetworkCycleDataForUidLoader
import com.android.settingslib.spa.framework.compose.toState
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spaprivileged.model.app.hasFlag
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.withContext
@Composable
fun AppDataUsagePreference(app: ApplicationInfo) {
fun AppDataUsagePreference(
app: ApplicationInfo,
networkTemplates: INetworkTemplates = NetworkTemplates,
) {
val context = LocalContext.current
val presenter = remember { AppDataUsagePresenter(context, app) }
val coroutineScope = rememberCoroutineScope()
val presenter = remember {
AppDataUsagePresenter(context, app, coroutineScope, networkTemplates)
}
if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
Preference(object : PreferenceModel {
override val title = stringResource(R.string.data_usage_app_summary_title)
override val title = stringResource(
presenter.titleResIdFlow.collectAsStateWithLifecycle(
initialValue = R.string.summary_placeholder,
).value
)
override val summary = presenter.summaryFlow.collectAsStateWithLifecycle(
initialValue = stringResource(R.string.computing_size),
)
@@ -62,6 +78,8 @@ fun AppDataUsagePreference(app: ApplicationInfo) {
private class AppDataUsagePresenter(
private val context: Context,
private val app: ApplicationInfo,
coroutineScope: CoroutineScope,
networkTemplates: INetworkTemplates,
) {
val isAvailableFlow = flow { emit(isAvailable()) }
@@ -71,10 +89,17 @@ private class AppDataUsagePresenter(
fun isEnabled() = app.hasFlag(ApplicationInfo.FLAG_INSTALLED)
val summaryFlow = flow { emit(getSummary()) }
private val templateFlow = flow {
emit(withContext(Dispatchers.IO) {
networkTemplates.getDefaultTemplate(context)
})
}.shareIn(coroutineScope, SharingStarted.WhileSubscribed(), 1)
private suspend fun getSummary() = withContext(Dispatchers.IO) {
val appUsageData = getAppUsageData()
val titleResIdFlow = templateFlow.map { it.getTitleResId() }
val summaryFlow = templateFlow.map { getSummary(it) }
private suspend fun getSummary(template: NetworkTemplate) = withContext(Dispatchers.IO) {
val appUsageData = getAppUsageData(template)
val totalBytes = appUsageData.sumOf { it.totalUsage }
if (totalBytes == 0L) {
context.getString(R.string.no_data_usage)
@@ -88,15 +113,15 @@ private class AppDataUsagePresenter(
}
}
private suspend fun getAppUsageData(): List<NetworkCycleDataForUid> =
private suspend fun getAppUsageData(template: NetworkTemplate): List<NetworkCycleDataForUid> =
withContext(Dispatchers.IO) {
createLoader().loadInBackground() ?: emptyList()
createLoader(template).loadInBackground() ?: emptyList()
}
private fun createLoader(): NetworkCycleDataForUidLoader =
private fun createLoader(template: NetworkTemplate): NetworkCycleDataForUidLoader =
NetworkCycleDataForUidLoader.builder(context).apply {
setRetrieveDetail(false)
setNetworkTemplate(getTemplate())
setNetworkTemplate(template)
addUid(app.uid)
if (Process.isApplicationUid(app.uid)) {
// Also add in network usage for the app's SDK sandbox
@@ -104,18 +129,6 @@ private class AppDataUsagePresenter(
}
}.build()
private fun getTemplate(): NetworkTemplate = when {
DataUsageUtils.hasReadyMobileRadio(context) -> {
NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE)
.setMeteredness(NetworkStats.METERED_YES)
.build()
}
DataUsageUtils.hasWifiRadio(context) -> {
NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build()
}
else -> NetworkTemplate.Builder(NetworkTemplate.MATCH_ETHERNET).build()
}
fun startActivity() {
AppInfoDashboardFragment.startAppInfoFragment(
AppDataUsage::class.java,