Snap for 11834877 from 2dbb27de91 to 24Q3-release
Change-Id: Ieed92f531be066e0b3d009c7314868390ce682ff
This commit is contained in:
@@ -1,3 +1,6 @@
|
|||||||
|
# The Android Biometric team should approve all changes to biometrics subdirectories.
|
||||||
|
set noparent
|
||||||
|
|
||||||
graciecheng@google.com
|
graciecheng@google.com
|
||||||
ilyamaty@google.com
|
ilyamaty@google.com
|
||||||
jaggies@google.com
|
jaggies@google.com
|
||||||
|
|||||||
@@ -1 +1,4 @@
|
|||||||
|
# The Android Biometric team should approve all changes to biometrics2 subdirectories.
|
||||||
|
set noparent
|
||||||
|
|
||||||
include /src/com/android/settings/biometrics/OWNERS
|
include /src/com/android/settings/biometrics/OWNERS
|
||||||
|
|||||||
@@ -23,11 +23,12 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
|
import com.android.settings.datausage.lib.DataUsageFormatter
|
||||||
import com.android.settings.datausage.lib.NetworkUsageDetailsData
|
import com.android.settings.datausage.lib.NetworkUsageDetailsData
|
||||||
import com.android.settings.spa.preference.ComposePreferenceController
|
import com.android.settings.spa.preference.ComposePreferenceController
|
||||||
import com.android.settingslib.spa.widget.preference.Preference
|
import com.android.settingslib.spa.widget.preference.Preference
|
||||||
import com.android.settingslib.spa.widget.preference.PreferenceModel
|
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.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
@@ -35,17 +36,20 @@ class AppDataUsageSummaryController(context: Context, preferenceKey: String) :
|
|||||||
ComposePreferenceController(context, preferenceKey) {
|
ComposePreferenceController(context, preferenceKey) {
|
||||||
|
|
||||||
private val dataFlow = MutableStateFlow(NetworkUsageDetailsData.AllZero)
|
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 {
|
private val totalUsageFlow = dataFlow.map {
|
||||||
DataUsageUtils.formatDataUsage(mContext, it.totalUsage).toString()
|
dataUsageFormatter.formatDataUsage(it.totalUsage)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val foregroundUsageFlow = dataFlow.map {
|
private val foregroundUsageFlow = dataFlow.map {
|
||||||
DataUsageUtils.formatDataUsage(mContext, it.foregroundUsage).toString()
|
dataUsageFormatter.formatDataUsage(it.foregroundUsage)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val backgroundUsageFlow = dataFlow.map {
|
private val backgroundUsageFlow = dataFlow.map {
|
||||||
DataUsageUtils.formatDataUsage(mContext, it.backgroundUsage).toString()
|
dataUsageFormatter.formatDataUsage(it.backgroundUsage)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAvailabilityStatus() = AVAILABLE
|
override fun getAvailabilityStatus() = AVAILABLE
|
||||||
@@ -57,20 +61,23 @@ class AppDataUsageSummaryController(context: Context, preferenceKey: String) :
|
|||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
Column {
|
Column {
|
||||||
val totalUsage by totalUsageFlow.collectAsStateWithLifecycle(placeholder())
|
val totalUsage by totalUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
|
||||||
val foregroundUsage by foregroundUsageFlow.collectAsStateWithLifecycle(placeholder())
|
val foregroundUsage by foregroundUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
|
||||||
val backgroundUsage by backgroundUsageFlow.collectAsStateWithLifecycle(placeholder())
|
val backgroundUsage by backgroundUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
|
||||||
Preference(object : PreferenceModel {
|
Preference(object : PreferenceModel {
|
||||||
override val title = stringResource(R.string.total_size_label)
|
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 {
|
Preference(object : PreferenceModel {
|
||||||
override val title = stringResource(R.string.data_usage_label_foreground)
|
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 {
|
Preference(object : PreferenceModel {
|
||||||
override val title = stringResource(R.string.data_usage_label_background)
|
override val title = stringResource(R.string.data_usage_label_background)
|
||||||
override val summary = { backgroundUsage }
|
override val summary = { backgroundUsage.displayText }
|
||||||
|
override val summaryContentDescription = { backgroundUsage.contentDescription }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import androidx.preference.TwoStatePreference;
|
|||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
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.datausage.lib.NetworkTemplates;
|
||||||
import com.android.settings.network.SubscriptionUtil;
|
import com.android.settings.network.SubscriptionUtil;
|
||||||
import com.android.settings.network.telephony.MobileNetworkUtils;
|
import com.android.settings.network.telephony.MobileNetworkUtils;
|
||||||
@@ -322,8 +323,8 @@ public class BillingCycleSettings extends DataUsageBaseFragment implements
|
|||||||
: editor.getPolicyWarningBytes(template);
|
: editor.getPolicyWarningBytes(template);
|
||||||
|
|
||||||
final String[] unitNames = new String[] {
|
final String[] unitNames = new String[] {
|
||||||
DataUsageFormatter.INSTANCE.getBytesDisplayUnit(getResources(), MIB_IN_BYTES),
|
DataUsageFormatter.Companion.getBytesDisplayUnit(getResources(), MIB_IN_BYTES),
|
||||||
DataUsageFormatter.INSTANCE.getBytesDisplayUnit(getResources(), GIB_IN_BYTES),
|
DataUsageFormatter.Companion.getBytesDisplayUnit(getResources(), GIB_IN_BYTES),
|
||||||
};
|
};
|
||||||
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
|
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
|
||||||
getContext(), android.R.layout.simple_spinner_item, unitNames);
|
getContext(), android.R.layout.simple_spinner_item, unitNames);
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -178,7 +178,7 @@ open class DataUsageList : DashboardFragment() {
|
|||||||
private fun updateSelectedCycle(usageData: NetworkUsageData) {
|
private fun updateSelectedCycle(usageData: NetworkUsageData) {
|
||||||
Log.d(TAG, "showing cycle $usageData")
|
Log.d(TAG, "showing cycle $usageData")
|
||||||
|
|
||||||
usageAmount?.title = usageData.getDataUsedString(requireContext())
|
usageAmount?.title = usageData.getDataUsedString(requireContext()).displayText
|
||||||
viewModel.selectedCycleFlow.value = usageData
|
viewModel.selectedCycleFlow.value = usageData
|
||||||
|
|
||||||
updateApps(usageData)
|
updateApps(usageData)
|
||||||
|
|||||||
@@ -56,7 +56,10 @@ public final class DataUsageUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Format byte value to readable string using IEC units.
|
* 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) {
|
public static CharSequence formatDataUsage(Context context, long byteValue) {
|
||||||
final BytesResult res = Formatter.formatBytes(context.getResources(), byteValue,
|
final BytesResult res = Formatter.formatBytes(context.getResources(), byteValue,
|
||||||
Formatter.FLAG_IEC_UNITS);
|
Formatter.FLAG_IEC_UNITS);
|
||||||
|
|||||||
64
src/com/android/settings/datausage/lib/DataUsageFormatter.kt
Normal file
64
src/com/android/settings/datausage/lib/DataUsageFormatter.kt
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ import android.content.Context
|
|||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import android.util.Range
|
import android.util.Range
|
||||||
import com.android.settings.R
|
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.
|
* Base data structure representing usage data in a period.
|
||||||
@@ -38,10 +38,11 @@ data class NetworkUsageData(
|
|||||||
fun formatDateRange(context: Context): String =
|
fun formatDateRange(context: Context): String =
|
||||||
DateUtils.formatDateRange(context, startTime, endTime, DATE_FORMAT)
|
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 =
|
fun getDataUsedString(context: Context): FormattedDataUsage =
|
||||||
context.getString(R.string.data_used_template, formatUsage(context))
|
formatUsage(context).format(context, R.string.data_used_template)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val AllZero = NetworkUsageData(
|
val AllZero = NetworkUsageData(
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import androidx.preference.Preference
|
|||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.datausage.DataUsageUtils
|
import com.android.settings.datausage.DataUsageUtils
|
||||||
|
import com.android.settings.datausage.lib.DataUsageFormatter.FormattedDataUsage
|
||||||
import com.android.settings.datausage.lib.DataUsageLib
|
import com.android.settings.datausage.lib.DataUsageLib
|
||||||
import com.android.settings.datausage.lib.NetworkCycleDataRepository
|
import com.android.settings.datausage.lib.NetworkCycleDataRepository
|
||||||
import com.android.settings.datausage.lib.NetworkStatsRepository.Companion.AllTimeRange
|
import com.android.settings.datausage.lib.NetworkStatsRepository.Companion.AllTimeRange
|
||||||
@@ -89,7 +90,7 @@ class DataUsagePreferenceController(context: Context, key: String) :
|
|||||||
getDataUsageSummaryAndEnabled()
|
getDataUsageSummaryAndEnabled()
|
||||||
}
|
}
|
||||||
preference.isEnabled = enabled
|
preference.isEnabled = enabled
|
||||||
preference.summary = summary
|
preference.summary = summary?.displayText
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNetworkTemplate(): NetworkTemplate? = when {
|
private fun getNetworkTemplate(): NetworkTemplate? = when {
|
||||||
@@ -104,15 +105,14 @@ class DataUsagePreferenceController(context: Context, key: String) :
|
|||||||
fun createNetworkCycleDataRepository(): NetworkCycleDataRepository? =
|
fun createNetworkCycleDataRepository(): NetworkCycleDataRepository? =
|
||||||
networkTemplate?.let { NetworkCycleDataRepository(mContext, it) }
|
networkTemplate?.let { NetworkCycleDataRepository(mContext, it) }
|
||||||
|
|
||||||
private fun getDataUsageSummaryAndEnabled(): Pair<String?, Boolean> {
|
private fun getDataUsageSummaryAndEnabled(): Pair<FormattedDataUsage?, Boolean> {
|
||||||
val repository = createNetworkCycleDataRepository() ?: return null to false
|
val repository = createNetworkCycleDataRepository() ?: return null to false
|
||||||
|
|
||||||
repository.loadFirstCycle()?.let { usageData ->
|
repository.loadFirstCycle()?.let { usageData ->
|
||||||
return mContext.getString(
|
val formattedDataUsage = usageData.formatUsage(mContext)
|
||||||
R.string.data_usage_template,
|
.format(mContext, R.string.data_usage_template, usageData.formatDateRange(mContext))
|
||||||
usageData.formatUsage(mContext),
|
val hasUsage = usageData.usage > 0 || repository.queryUsage(AllTimeRange).usage > 0
|
||||||
usageData.formatDateRange(mContext),
|
return formattedDataUsage to hasUsage
|
||||||
) to (usageData.usage > 0 || repository.queryUsage(AllTimeRange).usage > 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val allTimeUsage = repository.queryUsage(AllTimeRange)
|
val allTimeUsage = repository.queryUsage(AllTimeRange)
|
||||||
|
|||||||
@@ -26,9 +26,11 @@ import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.asExecutor
|
import kotlinx.coroutines.asExecutor
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.flow.conflate
|
import kotlinx.coroutines.flow.conflate
|
||||||
import kotlinx.coroutines.flow.filterNot
|
import kotlinx.coroutines.flow.filterNot
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@@ -46,7 +48,15 @@ class SubscriptionRepository(private val context: Context) {
|
|||||||
fun getSelectableSubscriptionInfoList(): List<SubscriptionInfo> =
|
fun getSelectableSubscriptionInfoList(): List<SubscriptionInfo> =
|
||||||
context.getSelectableSubscriptionInfoList()
|
context.getSelectableSubscriptionInfoList()
|
||||||
|
|
||||||
fun isSubscriptionEnabledFlow(subId: Int) = context.isSubscriptionEnabledFlow(subId)
|
/** Flow of whether the subscription enabled for the given [subId]. */
|
||||||
|
fun isSubscriptionEnabledFlow(subId: Int): Flow<Boolean> {
|
||||||
|
if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
|
||||||
|
return context.subscriptionsChangedFlow()
|
||||||
|
.map { subscriptionManager.isSubscriptionEnabled(subId) }
|
||||||
|
.conflate()
|
||||||
|
.onEach { Log.d(TAG, "[$subId] isSubscriptionEnabledFlow: $it") }
|
||||||
|
.flowOn(Dispatchers.Default)
|
||||||
|
}
|
||||||
|
|
||||||
/** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */
|
/** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */
|
||||||
fun collectSubscriptionEnabled(
|
fun collectSubscriptionEnabled(
|
||||||
@@ -65,11 +75,6 @@ val Context.subscriptionManager: SubscriptionManager?
|
|||||||
|
|
||||||
fun Context.requireSubscriptionManager(): SubscriptionManager = subscriptionManager!!
|
fun Context.requireSubscriptionManager(): SubscriptionManager = subscriptionManager!!
|
||||||
|
|
||||||
fun Context.isSubscriptionEnabledFlow(subId: Int) = subscriptionsChangedFlow().map {
|
|
||||||
subscriptionManager?.isSubscriptionEnabled(subId) ?: false
|
|
||||||
}.conflate().onEach { Log.d(TAG, "[$subId] isSubscriptionEnabledFlow: $it") }
|
|
||||||
.flowOn(Dispatchers.Default)
|
|
||||||
|
|
||||||
fun Context.phoneNumberFlow(subscriptionInfo: SubscriptionInfo) = subscriptionsChangedFlow().map {
|
fun Context.phoneNumberFlow(subscriptionInfo: SubscriptionInfo) = subscriptionsChangedFlow().map {
|
||||||
SubscriptionUtil.getBidiFormattedPhoneNumber(this, subscriptionInfo)
|
SubscriptionUtil.getBidiFormattedPhoneNumber(this, subscriptionInfo)
|
||||||
}.filterNot { it.isNullOrEmpty() }.flowOn(Dispatchers.Default)
|
}.filterNot { it.isNullOrEmpty() }.flowOn(Dispatchers.Default)
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
# The Android Biometric team should approve all changes to password subdirectories.
|
||||||
|
set noparent
|
||||||
|
|
||||||
# Default reviewers for this and subdirectories.
|
# Default reviewers for this and subdirectories.
|
||||||
curtislb@google.com
|
curtislb@google.com
|
||||||
graciecheng@google.com
|
graciecheng@google.com
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ private class AppDataUsagePresenter(
|
|||||||
} else {
|
} else {
|
||||||
context.getString(
|
context.getString(
|
||||||
R.string.data_summary_format,
|
R.string.data_summary_format,
|
||||||
appUsageData.formatUsage(context),
|
appUsageData.formatUsage(context).displayText,
|
||||||
appUsageData.formatStartDate(context),
|
appUsageData.formatStartDate(context),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ import com.android.settings.Utils
|
|||||||
import com.android.settings.network.SubscriptionUtil
|
import com.android.settings.network.SubscriptionUtil
|
||||||
import com.android.settings.network.telephony.MobileNetworkUtils
|
import com.android.settings.network.telephony.MobileNetworkUtils
|
||||||
import com.android.settings.network.telephony.SubscriptionActivationRepository
|
import com.android.settings.network.telephony.SubscriptionActivationRepository
|
||||||
import com.android.settings.network.telephony.isSubscriptionEnabledFlow
|
import com.android.settings.network.telephony.SubscriptionRepository
|
||||||
import com.android.settings.network.telephony.phoneNumberFlow
|
import com.android.settings.network.telephony.phoneNumberFlow
|
||||||
import com.android.settingslib.spa.widget.preference.PreferenceModel
|
import com.android.settingslib.spa.widget.preference.PreferenceModel
|
||||||
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
|
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
|
||||||
@@ -63,7 +63,7 @@ fun SimsSection(subscriptionInfoList: List<SubscriptionInfo>) {
|
|||||||
private fun SimPreference(subInfo: SubscriptionInfo) {
|
private fun SimPreference(subInfo: SubscriptionInfo) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val checked = remember(subInfo.subscriptionId) {
|
val checked = remember(subInfo.subscriptionId) {
|
||||||
context.isSubscriptionEnabledFlow(subInfo.subscriptionId)
|
SubscriptionRepository(context).isSubscriptionEnabledFlow(subInfo.subscriptionId)
|
||||||
}.collectAsStateWithLifecycle(initialValue = false)
|
}.collectAsStateWithLifecycle(initialValue = false)
|
||||||
val phoneNumber = phoneNumber(subInfo)
|
val phoneNumber = phoneNumber(subInfo)
|
||||||
val isConvertedPsim by remember(subInfo) {
|
val isConvertedPsim by remember(subInfo) {
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import com.android.settings.overlay.FeatureFactory;
|
|||||||
import com.android.settings.search.BaseSearchIndexProvider;
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
import com.android.settings.widget.SettingsMainSwitchBar;
|
import com.android.settings.widget.SettingsMainSwitchBar;
|
||||||
import com.android.settings.wifi.WifiUtils;
|
import com.android.settings.wifi.WifiUtils;
|
||||||
|
import com.android.settings.wifi.repository.SharedConnectivityRepository;
|
||||||
import com.android.settingslib.TetherUtil;
|
import com.android.settingslib.TetherUtil;
|
||||||
import com.android.settingslib.core.AbstractPreferenceController;
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
import com.android.settingslib.search.SearchIndexable;
|
import com.android.settingslib.search.SearchIndexable;
|
||||||
@@ -346,16 +347,20 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
|
|||||||
static class SearchIndexProvider extends BaseSearchIndexProvider {
|
static class SearchIndexProvider extends BaseSearchIndexProvider {
|
||||||
|
|
||||||
private final WifiRestriction mWifiRestriction;
|
private final WifiRestriction mWifiRestriction;
|
||||||
|
private final boolean mIsInstantHotspotEnabled;
|
||||||
|
|
||||||
SearchIndexProvider(int xmlRes) {
|
SearchIndexProvider(int xmlRes) {
|
||||||
super(xmlRes);
|
super(xmlRes);
|
||||||
mWifiRestriction = new WifiRestriction();
|
mWifiRestriction = new WifiRestriction();
|
||||||
|
mIsInstantHotspotEnabled = SharedConnectivityRepository.isDeviceConfigEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
SearchIndexProvider(int xmlRes, WifiRestriction wifiRestriction) {
|
SearchIndexProvider(int xmlRes, WifiRestriction wifiRestriction,
|
||||||
|
boolean isInstantHotspotEnabled) {
|
||||||
super(xmlRes);
|
super(xmlRes);
|
||||||
mWifiRestriction = wifiRestriction;
|
mWifiRestriction = wifiRestriction;
|
||||||
|
mIsInstantHotspotEnabled = isInstantHotspotEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -369,6 +374,9 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
|
|||||||
keys.add(KEY_WIFI_TETHER_NETWORK_PASSWORD);
|
keys.add(KEY_WIFI_TETHER_NETWORK_PASSWORD);
|
||||||
keys.add(KEY_WIFI_TETHER_AUTO_OFF);
|
keys.add(KEY_WIFI_TETHER_AUTO_OFF);
|
||||||
keys.add(KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
|
keys.add(KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
|
||||||
|
keys.add(KEY_INSTANT_HOTSPOT);
|
||||||
|
} else if (!mIsInstantHotspotEnabled) {
|
||||||
|
keys.add(KEY_INSTANT_HOTSPOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove duplicate
|
// Remove duplicate
|
||||||
|
|||||||
@@ -4,21 +4,20 @@
|
|||||||
## The full suite
|
## The full suite
|
||||||
```
|
```
|
||||||
$ croot
|
$ croot
|
||||||
$ make RunSettingsRoboTests
|
$ atest SettingsRoboTests
|
||||||
```
|
```
|
||||||
|
|
||||||
## Running a single test class
|
## Running a single test class
|
||||||
|
|
||||||
|
With a filter
|
||||||
|
|
||||||
```
|
```
|
||||||
$ croot
|
$ croot
|
||||||
$ make RunSettingsRoboTests ROBOTEST_FILTER=<ClassName>
|
$ atest SettingsRoboTests:com.android.settings.display.AdaptiveSleepPreferenceControllerTest
|
||||||
```
|
```
|
||||||
|
|
||||||
For example:
|
You can also run any single test class with atest (it will try to find the correct path)
|
||||||
|
|
||||||
```
|
```
|
||||||
make RunSettingsRoboTests ROBOTEST_FILTER=CodeInspectionTest
|
$ atest AdaptiveSleepPreferenceControllerTest
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also use partial class name in ROBOTEST_FILTER. If the partial class name matches
|
|
||||||
multiple file names, all of them will be executed.
|
|
||||||
|
|||||||
@@ -266,7 +266,8 @@ public class WifiTetherSettingsTest {
|
|||||||
when(mWifiRestriction.isTetherAvailable(mContext)).thenReturn(true);
|
when(mWifiRestriction.isTetherAvailable(mContext)).thenReturn(true);
|
||||||
when(mWifiRestriction.isHotspotAvailable(mContext)).thenReturn(true);
|
when(mWifiRestriction.isHotspotAvailable(mContext)).thenReturn(true);
|
||||||
WifiTetherSettings.SearchIndexProvider searchIndexProvider =
|
WifiTetherSettings.SearchIndexProvider searchIndexProvider =
|
||||||
new WifiTetherSettings.SearchIndexProvider(XML_RES, mWifiRestriction);
|
new WifiTetherSettings.SearchIndexProvider(XML_RES, mWifiRestriction,
|
||||||
|
true /* isInstantHotspotEnabled */);
|
||||||
|
|
||||||
final List<String> keys = searchIndexProvider.getNonIndexableKeys(mContext);
|
final List<String> keys = searchIndexProvider.getNonIndexableKeys(mContext);
|
||||||
|
|
||||||
@@ -275,6 +276,7 @@ public class WifiTetherSettingsTest {
|
|||||||
assertThat(keys).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
|
assertThat(keys).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
|
||||||
assertThat(keys).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
|
assertThat(keys).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
|
||||||
assertThat(keys).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
|
assertThat(keys).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
|
||||||
|
assertThat(keys).doesNotContain(WifiTetherSettings.KEY_INSTANT_HOTSPOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -282,7 +284,8 @@ public class WifiTetherSettingsTest {
|
|||||||
when(mWifiRestriction.isTetherAvailable(mContext)).thenReturn(false);
|
when(mWifiRestriction.isTetherAvailable(mContext)).thenReturn(false);
|
||||||
when(mWifiRestriction.isHotspotAvailable(mContext)).thenReturn(true);
|
when(mWifiRestriction.isHotspotAvailable(mContext)).thenReturn(true);
|
||||||
WifiTetherSettings.SearchIndexProvider searchIndexProvider =
|
WifiTetherSettings.SearchIndexProvider searchIndexProvider =
|
||||||
new WifiTetherSettings.SearchIndexProvider(XML_RES, mWifiRestriction);
|
new WifiTetherSettings.SearchIndexProvider(XML_RES, mWifiRestriction,
|
||||||
|
true /* isInstantHotspotEnabled */);
|
||||||
|
|
||||||
final List<String> keys = searchIndexProvider.getNonIndexableKeys(mContext);
|
final List<String> keys = searchIndexProvider.getNonIndexableKeys(mContext);
|
||||||
|
|
||||||
@@ -291,6 +294,7 @@ public class WifiTetherSettingsTest {
|
|||||||
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
|
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
|
||||||
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
|
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
|
||||||
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
|
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
|
||||||
|
assertThat(keys).contains(WifiTetherSettings.KEY_INSTANT_HOTSPOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -298,7 +302,26 @@ public class WifiTetherSettingsTest {
|
|||||||
when(mWifiRestriction.isTetherAvailable(mContext)).thenReturn(true);
|
when(mWifiRestriction.isTetherAvailable(mContext)).thenReturn(true);
|
||||||
when(mWifiRestriction.isHotspotAvailable(mContext)).thenReturn(false);
|
when(mWifiRestriction.isHotspotAvailable(mContext)).thenReturn(false);
|
||||||
WifiTetherSettings.SearchIndexProvider searchIndexProvider =
|
WifiTetherSettings.SearchIndexProvider searchIndexProvider =
|
||||||
new WifiTetherSettings.SearchIndexProvider(XML_RES, mWifiRestriction);
|
new WifiTetherSettings.SearchIndexProvider(XML_RES, mWifiRestriction,
|
||||||
|
true /* isInstantHotspotEnabled */);
|
||||||
|
|
||||||
|
final List<String> keys = searchIndexProvider.getNonIndexableKeys(mContext);
|
||||||
|
|
||||||
|
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME);
|
||||||
|
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_SECURITY);
|
||||||
|
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
|
||||||
|
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
|
||||||
|
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
|
||||||
|
assertThat(keys).contains(WifiTetherSettings.KEY_INSTANT_HOTSPOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNonIndexableKeys_tetherAndHotspotNotAvailable_keysReturned() {
|
||||||
|
when(mWifiRestriction.isTetherAvailable(mContext)).thenReturn(false);
|
||||||
|
when(mWifiRestriction.isHotspotAvailable(mContext)).thenReturn(false);
|
||||||
|
WifiTetherSettings.SearchIndexProvider searchIndexProvider =
|
||||||
|
new WifiTetherSettings.SearchIndexProvider(XML_RES, mWifiRestriction,
|
||||||
|
true /* isInstantHotspotEnabled */);
|
||||||
|
|
||||||
final List<String> keys = searchIndexProvider.getNonIndexableKeys(mContext);
|
final List<String> keys = searchIndexProvider.getNonIndexableKeys(mContext);
|
||||||
|
|
||||||
@@ -310,19 +333,21 @@ public class WifiTetherSettingsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getNonIndexableKeys_tetherAndHotspotNotAvailable_keysReturned() {
|
public void getNonIndexableKeys_instantHotspotNotAvailableOnly_keysContainInstantHotspotOnly() {
|
||||||
when(mWifiRestriction.isTetherAvailable(mContext)).thenReturn(false);
|
when(mWifiRestriction.isTetherAvailable(mContext)).thenReturn(true);
|
||||||
when(mWifiRestriction.isHotspotAvailable(mContext)).thenReturn(false);
|
when(mWifiRestriction.isHotspotAvailable(mContext)).thenReturn(true);
|
||||||
WifiTetherSettings.SearchIndexProvider searchIndexProvider =
|
WifiTetherSettings.SearchIndexProvider searchIndexProvider =
|
||||||
new WifiTetherSettings.SearchIndexProvider(XML_RES, mWifiRestriction);
|
new WifiTetherSettings.SearchIndexProvider(XML_RES, mWifiRestriction,
|
||||||
|
false /* isInstantHotspotEnabled */);
|
||||||
|
|
||||||
final List<String> keys = searchIndexProvider.getNonIndexableKeys(mContext);
|
final List<String> keys = searchIndexProvider.getNonIndexableKeys(mContext);
|
||||||
|
|
||||||
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME);
|
assertThat(keys).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME);
|
||||||
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_SECURITY);
|
assertThat(keys).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_SECURITY);
|
||||||
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
|
assertThat(keys).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
|
||||||
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
|
assertThat(keys).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
|
||||||
assertThat(keys).contains(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
|
assertThat(keys).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
|
||||||
|
assertThat(keys).contains(WifiTetherSettings.KEY_INSTANT_HOTSPOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -19,8 +19,9 @@ package com.android.settings.datausage
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Range
|
import android.util.Range
|
||||||
import androidx.compose.ui.test.assertIsDisplayed
|
import androidx.compose.ui.test.assertIsDisplayed
|
||||||
|
import androidx.compose.ui.test.hasTextExactly
|
||||||
import androidx.compose.ui.test.junit4.createComposeRule
|
import androidx.compose.ui.test.junit4.createComposeRule
|
||||||
import androidx.compose.ui.test.onNodeWithText
|
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import com.android.settings.datausage.lib.NetworkUsageDetailsData
|
import com.android.settings.datausage.lib.NetworkUsageDetailsData
|
||||||
@@ -52,9 +53,34 @@ class AppDataUsageSummaryControllerTest {
|
|||||||
controller.Content()
|
controller.Content()
|
||||||
}
|
}
|
||||||
|
|
||||||
composeTestRule.onNodeWithText("6.75 kB").assertIsDisplayed()
|
composeTestRule.onNode(hasTextExactly("Total", "6.75 kB")).assertIsDisplayed()
|
||||||
composeTestRule.onNodeWithText("5.54 kB").assertIsDisplayed()
|
composeTestRule.onNode(hasTextExactly("Foreground", "5.54 kB")).assertIsDisplayed()
|
||||||
composeTestRule.onNodeWithText("1.21 kB").assertIsDisplayed()
|
composeTestRule.onNode(hasTextExactly("Background", "1.21 kB")).assertIsDisplayed()
|
||||||
|
composeTestRule.onNodeWithContentDescription("6.75 kB").assertIsDisplayed()
|
||||||
|
composeTestRule.onNodeWithContentDescription("5.54 kB").assertIsDisplayed()
|
||||||
|
composeTestRule.onNodeWithContentDescription("1.21 kB").assertIsDisplayed()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun summary_zero() {
|
||||||
|
val appUsage = NetworkUsageDetailsData(
|
||||||
|
range = Range(1L, 2L),
|
||||||
|
totalUsage = 3,
|
||||||
|
foregroundUsage = 1,
|
||||||
|
backgroundUsage = 2,
|
||||||
|
)
|
||||||
|
|
||||||
|
controller.update(appUsage)
|
||||||
|
composeTestRule.setContent {
|
||||||
|
controller.Content()
|
||||||
|
}
|
||||||
|
|
||||||
|
composeTestRule.onNode(hasTextExactly("Total", "3 B")).assertIsDisplayed()
|
||||||
|
composeTestRule.onNode(hasTextExactly("Foreground", "1 B")).assertIsDisplayed()
|
||||||
|
composeTestRule.onNode(hasTextExactly("Background", "2 B")).assertIsDisplayed()
|
||||||
|
composeTestRule.onNodeWithContentDescription("3 byte").assertIsDisplayed()
|
||||||
|
composeTestRule.onNodeWithContentDescription("1 byte").assertIsDisplayed()
|
||||||
|
composeTestRule.onNodeWithContentDescription("2 byte").assertIsDisplayed()
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2023 The Android Open Source Project
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -14,12 +14,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.settings.datausage
|
package com.android.settings.datausage.lib
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import com.android.settings.datausage.DataUsageFormatter.getBytesDisplayUnit
|
import com.android.settings.datausage.lib.DataUsageFormatter.Companion.getBytesDisplayUnit
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -29,6 +29,32 @@ import org.junit.runner.RunWith
|
|||||||
class DataUsageFormatterTest {
|
class DataUsageFormatterTest {
|
||||||
private val context: Context = ApplicationProvider.getApplicationContext()
|
private val context: Context = ApplicationProvider.getApplicationContext()
|
||||||
|
|
||||||
|
private val dataUsageFormatter = DataUsageFormatter(context)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun formatDataUsage_0() {
|
||||||
|
val (displayText, contentDescription) = dataUsageFormatter.formatDataUsage(0)
|
||||||
|
|
||||||
|
assertThat(displayText).isEqualTo("0 B")
|
||||||
|
assertThat(contentDescription).isEqualTo("0 byte")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun formatDataUsage_1000() {
|
||||||
|
val (displayText, contentDescription) = dataUsageFormatter.formatDataUsage(1000)
|
||||||
|
|
||||||
|
assertThat(displayText).isEqualTo("0.98 kB")
|
||||||
|
assertThat(contentDescription).isEqualTo("0.98 kB")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun formatDataUsage_2000000() {
|
||||||
|
val (displayText, contentDescription) = dataUsageFormatter.formatDataUsage(2000000)
|
||||||
|
|
||||||
|
assertThat(displayText).isEqualTo("1.91 MB")
|
||||||
|
assertThat(contentDescription).isEqualTo("1.91 MB")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun getUnitDisplayName_megaByte() {
|
fun getUnitDisplayName_megaByte() {
|
||||||
val displayName = context.resources.getBytesDisplayUnit(ONE_MEGA_BYTE_IN_BYTES)
|
val displayName = context.resources.getBytesDisplayUnit(ONE_MEGA_BYTE_IN_BYTES)
|
||||||
@@ -52,13 +52,24 @@ class SubscriptionRepositoryTest {
|
|||||||
on { subscriptionManager } doReturn mockSubscriptionManager
|
on { subscriptionManager } doReturn mockSubscriptionManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val repository = SubscriptionRepository(context)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun isSubscriptionEnabledFlow() = runBlocking {
|
fun isSubscriptionEnabledFlow_invalidSubId() = runBlocking {
|
||||||
|
val isEnabled = repository
|
||||||
|
.isSubscriptionEnabledFlow(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
|
||||||
|
.firstWithTimeoutOrNull()
|
||||||
|
|
||||||
|
assertThat(isEnabled).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isSubscriptionEnabledFlow_enabled() = runBlocking {
|
||||||
mockSubscriptionManager.stub {
|
mockSubscriptionManager.stub {
|
||||||
on { isSubscriptionEnabled(SUB_ID_1) } doReturn true
|
on { isSubscriptionEnabled(SUB_ID_1) } doReturn true
|
||||||
}
|
}
|
||||||
|
|
||||||
val isEnabled = context.isSubscriptionEnabledFlow(SUB_ID_1).firstWithTimeoutOrNull()
|
val isEnabled = repository.isSubscriptionEnabledFlow(SUB_ID_1).firstWithTimeoutOrNull()
|
||||||
|
|
||||||
assertThat(isEnabled).isTrue()
|
assertThat(isEnabled).isTrue()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package com.android.settings.connecteddevice.threadnetwork
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.platform.test.flag.junit.SetFlagsRule
|
import android.platform.test.flag.junit.SetFlagsRule
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
@@ -27,6 +26,7 @@ import com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILA
|
|||||||
import com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE
|
import com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE
|
||||||
import com.android.settings.flags.Flags
|
import com.android.settings.flags.Flags
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -50,7 +50,7 @@ class ThreadNetworkFragmentControllerTest {
|
|||||||
fun setUp() {
|
fun setUp() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_THREAD_SETTINGS_ENABLED)
|
mSetFlagsRule.enableFlags(Flags.FLAG_THREAD_SETTINGS_ENABLED)
|
||||||
context = spy(ApplicationProvider.getApplicationContext<Context>())
|
context = spy(ApplicationProvider.getApplicationContext<Context>())
|
||||||
executor = ContextCompat.getMainExecutor(context)
|
executor = MoreExecutors.directExecutor()
|
||||||
fakeThreadNetworkController = FakeThreadNetworkController()
|
fakeThreadNetworkController = FakeThreadNetworkController()
|
||||||
controller = newControllerWithThreadFeatureSupported(true)
|
controller = newControllerWithThreadFeatureSupported(true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILA
|
|||||||
import com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE
|
import com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE
|
||||||
import com.android.settings.flags.Flags
|
import com.android.settings.flags.Flags
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -51,7 +52,7 @@ class ThreadNetworkToggleControllerTest {
|
|||||||
fun setUp() {
|
fun setUp() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_THREAD_SETTINGS_ENABLED)
|
mSetFlagsRule.enableFlags(Flags.FLAG_THREAD_SETTINGS_ENABLED)
|
||||||
context = spy(ApplicationProvider.getApplicationContext<Context>())
|
context = spy(ApplicationProvider.getApplicationContext<Context>())
|
||||||
executor = Executor { runnable: Runnable -> runnable.run() }
|
executor = MoreExecutors.directExecutor()
|
||||||
fakeThreadNetworkController = FakeThreadNetworkController()
|
fakeThreadNetworkController = FakeThreadNetworkController()
|
||||||
controller = newControllerWithThreadFeatureSupported(true)
|
controller = newControllerWithThreadFeatureSupported(true)
|
||||||
val preferenceManager = PreferenceManager(context)
|
val preferenceManager = PreferenceManager(context)
|
||||||
|
|||||||
Reference in New Issue
Block a user