Use DataUsageFormatter to format app data usage

Use the new unitsContentDescription from Formatter.formatBytes()

Fix: 318780411
Test: manual - on AppDataUsage
Test: unit test
Change-Id: I55079c83db2e46a48f49f746f2371825ec0bb029
This commit is contained in:
Chaohui Wang
2024-04-09 14:03:04 +08:00
parent ee501485b8
commit 7ca1ceb722
11 changed files with 161 additions and 65 deletions

View File

@@ -23,11 +23,12 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settings.R
import com.android.settings.datausage.lib.DataUsageFormatter
import com.android.settings.datausage.lib.NetworkUsageDetailsData
import com.android.settings.spa.preference.ComposePreferenceController
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spaprivileged.framework.compose.placeholder
import com.android.settingslib.spaprivileged.framework.compose.getPlaceholder
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map
@@ -35,17 +36,20 @@ class AppDataUsageSummaryController(context: Context, preferenceKey: String) :
ComposePreferenceController(context, preferenceKey) {
private val dataFlow = MutableStateFlow(NetworkUsageDetailsData.AllZero)
private val dataUsageFormatter = DataUsageFormatter(context)
private val emptyDataUsage =
DataUsageFormatter.FormattedDataUsage(context.getPlaceholder(), context.getPlaceholder())
private val totalUsageFlow = dataFlow.map {
DataUsageUtils.formatDataUsage(mContext, it.totalUsage).toString()
dataUsageFormatter.formatDataUsage(it.totalUsage)
}
private val foregroundUsageFlow = dataFlow.map {
DataUsageUtils.formatDataUsage(mContext, it.foregroundUsage).toString()
dataUsageFormatter.formatDataUsage(it.foregroundUsage)
}
private val backgroundUsageFlow = dataFlow.map {
DataUsageUtils.formatDataUsage(mContext, it.backgroundUsage).toString()
dataUsageFormatter.formatDataUsage(it.backgroundUsage)
}
override fun getAvailabilityStatus() = AVAILABLE
@@ -57,20 +61,23 @@ class AppDataUsageSummaryController(context: Context, preferenceKey: String) :
@Composable
override fun Content() {
Column {
val totalUsage by totalUsageFlow.collectAsStateWithLifecycle(placeholder())
val foregroundUsage by foregroundUsageFlow.collectAsStateWithLifecycle(placeholder())
val backgroundUsage by backgroundUsageFlow.collectAsStateWithLifecycle(placeholder())
val totalUsage by totalUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
val foregroundUsage by foregroundUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
val backgroundUsage by backgroundUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
Preference(object : PreferenceModel {
override val title = stringResource(R.string.total_size_label)
override val summary = { totalUsage }
override val summary = { totalUsage.displayText }
override val summaryContentDescription = { totalUsage.contentDescription }
})
Preference(object : PreferenceModel {
override val title = stringResource(R.string.data_usage_label_foreground)
override val summary = { foregroundUsage }
override val summary = { foregroundUsage.displayText }
override val summaryContentDescription = { foregroundUsage.contentDescription }
})
Preference(object : PreferenceModel {
override val title = stringResource(R.string.data_usage_label_background)
override val summary = { backgroundUsage }
override val summary = { backgroundUsage.displayText }
override val summaryContentDescription = { backgroundUsage.contentDescription }
})
}
}

View File

@@ -44,6 +44,7 @@ import androidx.preference.TwoStatePreference;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.datausage.lib.DataUsageFormatter;
import com.android.settings.datausage.lib.NetworkTemplates;
import com.android.settings.network.SubscriptionUtil;
import com.android.settings.network.telephony.MobileNetworkUtils;
@@ -322,8 +323,8 @@ public class BillingCycleSettings extends DataUsageBaseFragment implements
: editor.getPolicyWarningBytes(template);
final String[] unitNames = new String[] {
DataUsageFormatter.INSTANCE.getBytesDisplayUnit(getResources(), MIB_IN_BYTES),
DataUsageFormatter.INSTANCE.getBytesDisplayUnit(getResources(), GIB_IN_BYTES),
DataUsageFormatter.Companion.getBytesDisplayUnit(getResources(), MIB_IN_BYTES),
DataUsageFormatter.Companion.getBytesDisplayUnit(getResources(), GIB_IN_BYTES),
};
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
getContext(), android.R.layout.simple_spinner_item, unitNames);

View File

@@ -1,32 +0,0 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.datausage
import android.content.res.Resources
import android.text.format.Formatter
object DataUsageFormatter {
/**
* Gets the display unit of the given bytes.
*
* Similar to MeasureFormat.getUnitDisplayName(), but with the expected result for the bytes in
* Settings, and align with other places in Settings.
*/
fun Resources.getBytesDisplayUnit(bytes: Long): String =
Formatter.formatBytes(this, bytes, Formatter.FLAG_IEC_UNITS).units
}

View File

@@ -178,7 +178,7 @@ open class DataUsageList : DashboardFragment() {
private fun updateSelectedCycle(usageData: NetworkUsageData) {
Log.d(TAG, "showing cycle $usageData")
usageAmount?.title = usageData.getDataUsedString(requireContext())
usageAmount?.title = usageData.getDataUsedString(requireContext()).displayText
viewModel.selectedCycleFlow.value = usageData
updateApps(usageData)

View File

@@ -56,7 +56,10 @@ public final class DataUsageUtils {
/**
* Format byte value to readable string using IEC units.
*
* @deprecated Use {@link com.android.settings.datausage.lib.DataUsageFormatter} instead.
*/
@Deprecated
public static CharSequence formatDataUsage(Context context, long byteValue) {
final BytesResult res = Formatter.formatBytes(context.getResources(), byteValue,
Formatter.FLAG_IEC_UNITS);

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.datausage.lib
import android.annotation.StringRes
import android.content.Context
import android.content.res.Resources
import android.icu.text.UnicodeSet
import android.icu.text.UnicodeSetSpanner
import android.text.BidiFormatter
import android.text.format.Formatter
import com.android.internal.R
class DataUsageFormatter(private val context: Context) {
data class FormattedDataUsage(
val displayText: String,
val contentDescription: String,
) {
fun format(context: Context, @StringRes resId: Int, vararg formatArgs: Any?) =
FormattedDataUsage(
displayText = context.getString(resId, displayText, *formatArgs),
contentDescription = context.getString(resId, contentDescription, *formatArgs),
)
}
/** Formats the data usage. */
fun formatDataUsage(sizeBytes: Long): FormattedDataUsage {
val result = Formatter.formatBytes(context.resources, sizeBytes, Formatter.FLAG_IEC_UNITS)
return FormattedDataUsage(
displayText = BidiFormatter.getInstance().unicodeWrap(
context.getString(R.string.fileSizeSuffix, result.value, result.units)
),
contentDescription = context.getString(
R.string.fileSizeSuffix, result.value, result.unitsContentDescription
),
)
}
companion object {
/**
* Gets the display unit of the given bytes.
*
* Similar to MeasureFormat.getUnitDisplayName(), but with the expected result for the bytes
* in Settings, and align with other places in Settings.
*/
fun Resources.getBytesDisplayUnit(bytes: Long): String =
Formatter.formatBytes(this, bytes, Formatter.FLAG_IEC_UNITS).units
}
}

View File

@@ -20,7 +20,7 @@ import android.content.Context
import android.text.format.DateUtils
import android.util.Range
import com.android.settings.R
import com.android.settings.datausage.DataUsageUtils
import com.android.settings.datausage.lib.DataUsageFormatter.FormattedDataUsage
/**
* Base data structure representing usage data in a period.
@@ -38,10 +38,11 @@ data class NetworkUsageData(
fun formatDateRange(context: Context): String =
DateUtils.formatDateRange(context, startTime, endTime, DATE_FORMAT)
fun formatUsage(context: Context): CharSequence = DataUsageUtils.formatDataUsage(context, usage)
fun formatUsage(context: Context): FormattedDataUsage =
DataUsageFormatter(context).formatDataUsage(usage)
fun getDataUsedString(context: Context): String =
context.getString(R.string.data_used_template, formatUsage(context))
fun getDataUsedString(context: Context): FormattedDataUsage =
formatUsage(context).format(context, R.string.data_used_template)
companion object {
val AllZero = NetworkUsageData(