Merge changes I5986ba47,I8ddeafe4,I385e2050,I1f8b2b4e,Iab75c65a, ... into tm-qpr-dev am: d756cb556d
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21302234 Change-Id: I78c5fa223410a1c996184dc87c3b04859cdb3aa5 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -79,10 +79,10 @@ fun <T : Diffable<T>> Flow<T>.logDiffsForTable(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Here and below: Various Flow<SomeType> extension functions that are effectively equivalent to the
|
||||||
* Each time the boolean flow is updated with a new value that's different from the previous value,
|
// above [logDiffsForTable] method.
|
||||||
* logs the new value to the given [tableLogBuffer].
|
|
||||||
*/
|
/** See [logDiffsForTable(TableLogBuffer, String, T)]. */
|
||||||
fun Flow<Boolean>.logDiffsForTable(
|
fun Flow<Boolean>.logDiffsForTable(
|
||||||
tableLogBuffer: TableLogBuffer,
|
tableLogBuffer: TableLogBuffer,
|
||||||
columnPrefix: String,
|
columnPrefix: String,
|
||||||
@@ -100,10 +100,8 @@ fun Flow<Boolean>.logDiffsForTable(
|
|||||||
newVal
|
newVal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Each time the Int flow is updated with a new value that's different from the previous value, logs
|
/** See [logDiffsForTable(TableLogBuffer, String, T)]. */
|
||||||
* the new value to the given [tableLogBuffer].
|
|
||||||
*/
|
|
||||||
fun Flow<Int>.logDiffsForTable(
|
fun Flow<Int>.logDiffsForTable(
|
||||||
tableLogBuffer: TableLogBuffer,
|
tableLogBuffer: TableLogBuffer,
|
||||||
columnPrefix: String,
|
columnPrefix: String,
|
||||||
@@ -122,10 +120,26 @@ fun Flow<Int>.logDiffsForTable(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** See [logDiffsForTable(TableLogBuffer, String, T)]. */
|
||||||
* Each time the String? flow is updated with a new value that's different from the previous value,
|
fun Flow<Int?>.logDiffsForTable(
|
||||||
* logs the new value to the given [tableLogBuffer].
|
tableLogBuffer: TableLogBuffer,
|
||||||
*/
|
columnPrefix: String,
|
||||||
|
columnName: String,
|
||||||
|
initialValue: Int?,
|
||||||
|
): Flow<Int?> {
|
||||||
|
val initialValueFun = {
|
||||||
|
tableLogBuffer.logChange(columnPrefix, columnName, initialValue)
|
||||||
|
initialValue
|
||||||
|
}
|
||||||
|
return this.pairwiseBy(initialValueFun) { prevVal, newVal: Int? ->
|
||||||
|
if (prevVal != newVal) {
|
||||||
|
tableLogBuffer.logChange(columnPrefix, columnName, newVal)
|
||||||
|
}
|
||||||
|
newVal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** See [logDiffsForTable(TableLogBuffer, String, T)]. */
|
||||||
fun Flow<String?>.logDiffsForTable(
|
fun Flow<String?>.logDiffsForTable(
|
||||||
tableLogBuffer: TableLogBuffer,
|
tableLogBuffer: TableLogBuffer,
|
||||||
columnPrefix: String,
|
columnPrefix: String,
|
||||||
@@ -143,3 +157,23 @@ fun Flow<String?>.logDiffsForTable(
|
|||||||
newVal
|
newVal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** See [logDiffsForTable(TableLogBuffer, String, T)]. */
|
||||||
|
fun <T> Flow<List<T>>.logDiffsForTable(
|
||||||
|
tableLogBuffer: TableLogBuffer,
|
||||||
|
columnPrefix: String,
|
||||||
|
columnName: String,
|
||||||
|
initialValue: List<T>,
|
||||||
|
): Flow<List<T>> {
|
||||||
|
val initialValueFun = {
|
||||||
|
tableLogBuffer.logChange(columnPrefix, columnName, initialValue.toString())
|
||||||
|
initialValue
|
||||||
|
}
|
||||||
|
return this.pairwiseBy(initialValueFun) { prevVal, newVal: List<T> ->
|
||||||
|
if (prevVal != newVal) {
|
||||||
|
// TODO(b/267761156): Can we log list changes without using toString?
|
||||||
|
tableLogBuffer.logChange(columnPrefix, columnName, newVal.toString())
|
||||||
|
}
|
||||||
|
newVal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ data class TableChange(
|
|||||||
var columnName: String = "",
|
var columnName: String = "",
|
||||||
var type: DataType = DataType.EMPTY,
|
var type: DataType = DataType.EMPTY,
|
||||||
var bool: Boolean = false,
|
var bool: Boolean = false,
|
||||||
var int: Int = 0,
|
var int: Int? = null,
|
||||||
var str: String? = null,
|
var str: String? = null,
|
||||||
) {
|
) {
|
||||||
/** Resets to default values so that the object can be recycled. */
|
/** Resets to default values so that the object can be recycled. */
|
||||||
@@ -54,7 +54,7 @@ data class TableChange(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Sets this to store an int change. */
|
/** Sets this to store an int change. */
|
||||||
fun set(value: Int) {
|
fun set(value: Int?) {
|
||||||
type = DataType.INT
|
type = DataType.INT
|
||||||
int = value
|
int = value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class TableLogBuffer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Logs a Int change. */
|
/** Logs a Int change. */
|
||||||
fun logChange(prefix: String, columnName: String, value: Int) {
|
fun logChange(prefix: String, columnName: String, value: Int?) {
|
||||||
logChange(systemClock.currentTimeMillis(), prefix, columnName, value)
|
logChange(systemClock.currentTimeMillis(), prefix, columnName, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ class TableLogBuffer(
|
|||||||
change.set(value)
|
change.set(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun logChange(timestamp: Long, prefix: String, columnName: String, value: Int) {
|
private fun logChange(timestamp: Long, prefix: String, columnName: String, value: Int?) {
|
||||||
val change = obtain(timestamp, prefix, columnName)
|
val change = obtain(timestamp, prefix, columnName)
|
||||||
change.set(value)
|
change.set(value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.statusbar.pipeline.dagger
|
||||||
|
|
||||||
|
import javax.inject.Qualifier
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs for mobile data that's **the same across all connections**.
|
||||||
|
*
|
||||||
|
* This buffer should only be used for the mobile parent classes like [MobileConnectionsRepository]
|
||||||
|
* and [MobileIconsInteractor]. It should *not* be used for classes that represent an individual
|
||||||
|
* connection, like [MobileConnectionRepository] or [MobileIconInteractor].
|
||||||
|
*/
|
||||||
|
@Qualifier
|
||||||
|
@MustBeDocumented
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class MobileSummaryLog
|
||||||
@@ -118,5 +118,12 @@ abstract class StatusBarPipelineModule {
|
|||||||
fun provideAirplaneTableLogBuffer(factory: TableLogBufferFactory): TableLogBuffer {
|
fun provideAirplaneTableLogBuffer(factory: TableLogBufferFactory): TableLogBuffer {
|
||||||
return factory.create("AirplaneTableLog", 30)
|
return factory.create("AirplaneTableLog", 30)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@SysUISingleton
|
||||||
|
@MobileSummaryLog
|
||||||
|
fun provideMobileSummaryLogBuffer(factory: TableLogBufferFactory): TableLogBuffer {
|
||||||
|
return factory.create("MobileSummaryLog", 100)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
package com.android.systemui.statusbar.pipeline.mobile.data.model
|
package com.android.systemui.statusbar.pipeline.mobile.data.model
|
||||||
|
|
||||||
import android.net.NetworkCapabilities
|
import android.net.NetworkCapabilities
|
||||||
|
import com.android.systemui.log.table.Diffable
|
||||||
|
import com.android.systemui.log.table.TableRowLogger
|
||||||
|
|
||||||
/** Provides information about a mobile network connection */
|
/** Provides information about a mobile network connection */
|
||||||
data class MobileConnectivityModel(
|
data class MobileConnectivityModel(
|
||||||
@@ -24,4 +26,24 @@ data class MobileConnectivityModel(
|
|||||||
val isConnected: Boolean = false,
|
val isConnected: Boolean = false,
|
||||||
/** Whether the mobile transport is validated [NetworkCapabilities.NET_CAPABILITY_VALIDATED] */
|
/** Whether the mobile transport is validated [NetworkCapabilities.NET_CAPABILITY_VALIDATED] */
|
||||||
val isValidated: Boolean = false,
|
val isValidated: Boolean = false,
|
||||||
)
|
) : Diffable<MobileConnectivityModel> {
|
||||||
|
// TODO(b/267767715): Can we implement [logDiffs] and [logFull] generically for data classes?
|
||||||
|
override fun logDiffs(prevVal: MobileConnectivityModel, row: TableRowLogger) {
|
||||||
|
if (prevVal.isConnected != isConnected) {
|
||||||
|
row.logChange(COL_IS_CONNECTED, isConnected)
|
||||||
|
}
|
||||||
|
if (prevVal.isValidated != isValidated) {
|
||||||
|
row.logChange(COL_IS_VALIDATED, isValidated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun logFull(row: TableRowLogger) {
|
||||||
|
row.logChange(COL_IS_CONNECTED, isConnected)
|
||||||
|
row.logChange(COL_IS_VALIDATED, isValidated)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val COL_IS_CONNECTED = "isConnected"
|
||||||
|
private const val COL_IS_VALIDATED = "isValidated"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -91,9 +91,6 @@ class CarrierMergedConnectionRepository(
|
|||||||
.map { it.toMobileConnectionModel() }
|
.map { it.toMobileConnectionModel() }
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectionModel())
|
.stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectionModel())
|
||||||
|
|
||||||
// TODO(b/238425913): Add logging to this class.
|
|
||||||
// TODO(b/238425913): Make sure SignalStrength.getEmptyState is used when appropriate.
|
|
||||||
|
|
||||||
// Carrier merged is never roaming.
|
// Carrier merged is never roaming.
|
||||||
override val cdmaRoaming: StateFlow<Boolean> = MutableStateFlow(false).asStateFlow()
|
override val cdmaRoaming: StateFlow<Boolean> = MutableStateFlow(false).asStateFlow()
|
||||||
|
|
||||||
|
|||||||
@@ -117,11 +117,22 @@ class FullMobileConnectionRepository(
|
|||||||
override val connectionInfo =
|
override val connectionInfo =
|
||||||
activeRepo
|
activeRepo
|
||||||
.flatMapLatest { it.connectionInfo }
|
.flatMapLatest { it.connectionInfo }
|
||||||
|
.logDiffsForTable(
|
||||||
|
tableLogBuffer,
|
||||||
|
columnPrefix = "",
|
||||||
|
initialValue = activeRepo.value.connectionInfo.value,
|
||||||
|
)
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.connectionInfo.value)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.connectionInfo.value)
|
||||||
|
|
||||||
override val dataEnabled =
|
override val dataEnabled =
|
||||||
activeRepo
|
activeRepo
|
||||||
.flatMapLatest { it.dataEnabled }
|
.flatMapLatest { it.dataEnabled }
|
||||||
|
.logDiffsForTable(
|
||||||
|
tableLogBuffer,
|
||||||
|
columnPrefix = "",
|
||||||
|
columnName = "dataEnabled",
|
||||||
|
initialValue = activeRepo.value.dataEnabled.value,
|
||||||
|
)
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.dataEnabled.value)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.dataEnabled.value)
|
||||||
|
|
||||||
override val numberOfLevels =
|
override val numberOfLevels =
|
||||||
@@ -132,6 +143,11 @@ class FullMobileConnectionRepository(
|
|||||||
override val networkName =
|
override val networkName =
|
||||||
activeRepo
|
activeRepo
|
||||||
.flatMapLatest { it.networkName }
|
.flatMapLatest { it.networkName }
|
||||||
|
.logDiffsForTable(
|
||||||
|
tableLogBuffer,
|
||||||
|
columnPrefix = "",
|
||||||
|
initialValue = activeRepo.value.networkName.value,
|
||||||
|
)
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.networkName.value)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.networkName.value)
|
||||||
|
|
||||||
class Factory
|
class Factory
|
||||||
@@ -168,7 +184,7 @@ class FullMobileConnectionRepository(
|
|||||||
const val MOBILE_CONNECTION_BUFFER_SIZE = 100
|
const val MOBILE_CONNECTION_BUFFER_SIZE = 100
|
||||||
|
|
||||||
/** Returns a log buffer name for a mobile connection with the given [subId]. */
|
/** Returns a log buffer name for a mobile connection with the given [subId]. */
|
||||||
fun tableBufferLogName(subId: Int): String = "MobileConnectionLog [$subId]"
|
fun tableBufferLogName(subId: Int): String = "MobileConnectionLog[$subId]"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
|
|||||||
import com.android.systemui.dagger.qualifiers.Application
|
import com.android.systemui.dagger.qualifiers.Application
|
||||||
import com.android.systemui.dagger.qualifiers.Background
|
import com.android.systemui.dagger.qualifiers.Background
|
||||||
import com.android.systemui.log.table.TableLogBuffer
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
import com.android.systemui.log.table.logDiffsForTable
|
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
|
||||||
@@ -62,7 +61,6 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
|||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
import kotlinx.coroutines.flow.mapNotNull
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
@@ -87,7 +85,7 @@ class MobileConnectionRepositoryImpl(
|
|||||||
private val mobileMappingsProxy: MobileMappingsProxy,
|
private val mobileMappingsProxy: MobileMappingsProxy,
|
||||||
bgDispatcher: CoroutineDispatcher,
|
bgDispatcher: CoroutineDispatcher,
|
||||||
logger: ConnectivityPipelineLogger,
|
logger: ConnectivityPipelineLogger,
|
||||||
mobileLogger: TableLogBuffer,
|
override val tableLogBuffer: TableLogBuffer,
|
||||||
scope: CoroutineScope,
|
scope: CoroutineScope,
|
||||||
) : MobileConnectionRepository {
|
) : MobileConnectionRepository {
|
||||||
init {
|
init {
|
||||||
@@ -101,8 +99,6 @@ class MobileConnectionRepositoryImpl(
|
|||||||
|
|
||||||
private val telephonyCallbackEvent = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
|
private val telephonyCallbackEvent = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
|
||||||
|
|
||||||
override val tableLogBuffer: TableLogBuffer = mobileLogger
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This flow defines the single shared connection to system_server via TelephonyCallback. Any
|
* This flow defines the single shared connection to system_server via TelephonyCallback. Any
|
||||||
* new callback should be added to this listener and funneled through callbackEvents via a data
|
* new callback should be added to this listener and funneled through callbackEvents via a data
|
||||||
@@ -243,11 +239,6 @@ class MobileConnectionRepositoryImpl(
|
|||||||
val initial = MobileConnectionModel()
|
val initial = MobileConnectionModel()
|
||||||
callbackEvents
|
callbackEvents
|
||||||
.scan(initial, ::updateConnectionState)
|
.scan(initial, ::updateConnectionState)
|
||||||
.logDiffsForTable(
|
|
||||||
mobileLogger,
|
|
||||||
columnPrefix = "MobileConnection ($subId)",
|
|
||||||
initialValue = initial,
|
|
||||||
)
|
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,24 +276,12 @@ class MobileConnectionRepositoryImpl(
|
|||||||
intent.toNetworkNameModel(networkNameSeparator) ?: defaultNetworkName
|
intent.toNetworkNameModel(networkNameSeparator) ?: defaultNetworkName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.distinctUntilChanged()
|
|
||||||
.logDiffsForTable(
|
|
||||||
mobileLogger,
|
|
||||||
columnPrefix = "",
|
|
||||||
initialValue = defaultNetworkName,
|
|
||||||
)
|
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
|
||||||
|
|
||||||
override val dataEnabled = run {
|
override val dataEnabled = run {
|
||||||
val initial = telephonyManager.isDataConnectionAllowed
|
val initial = telephonyManager.isDataConnectionAllowed
|
||||||
callbackEvents
|
callbackEvents
|
||||||
.mapNotNull { (it as? CallbackEvent.OnDataEnabledChanged)?.enabled }
|
.mapNotNull { (it as? CallbackEvent.OnDataEnabledChanged)?.enabled }
|
||||||
.logDiffsForTable(
|
|
||||||
mobileLogger,
|
|
||||||
columnPrefix = "",
|
|
||||||
columnName = "dataEnabled",
|
|
||||||
initialValue = initial
|
|
||||||
)
|
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
|
|||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.dagger.qualifiers.Application
|
import com.android.systemui.dagger.qualifiers.Application
|
||||||
import com.android.systemui.dagger.qualifiers.Background
|
import com.android.systemui.dagger.qualifiers.Background
|
||||||
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
|
import com.android.systemui.log.table.logDiffsForTable
|
||||||
|
import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
||||||
@@ -82,6 +85,7 @@ constructor(
|
|||||||
private val subscriptionManager: SubscriptionManager,
|
private val subscriptionManager: SubscriptionManager,
|
||||||
private val telephonyManager: TelephonyManager,
|
private val telephonyManager: TelephonyManager,
|
||||||
private val logger: ConnectivityPipelineLogger,
|
private val logger: ConnectivityPipelineLogger,
|
||||||
|
@MobileSummaryLog private val tableLogger: TableLogBuffer,
|
||||||
mobileMappingsProxy: MobileMappingsProxy,
|
mobileMappingsProxy: MobileMappingsProxy,
|
||||||
broadcastDispatcher: BroadcastDispatcher,
|
broadcastDispatcher: BroadcastDispatcher,
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
@@ -114,6 +118,12 @@ constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
|
.logDiffsForTable(
|
||||||
|
tableLogger,
|
||||||
|
LOGGING_PREFIX,
|
||||||
|
columnName = "carrierMergedSubId",
|
||||||
|
initialValue = null,
|
||||||
|
)
|
||||||
.stateIn(scope, started = SharingStarted.WhileSubscribed(), null)
|
.stateIn(scope, started = SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
private val mobileSubscriptionsChangeEvent: Flow<Unit> = conflatedCallbackFlow {
|
private val mobileSubscriptionsChangeEvent: Flow<Unit> = conflatedCallbackFlow {
|
||||||
@@ -139,8 +149,14 @@ constructor(
|
|||||||
override val subscriptions: StateFlow<List<SubscriptionModel>> =
|
override val subscriptions: StateFlow<List<SubscriptionModel>> =
|
||||||
merge(mobileSubscriptionsChangeEvent, carrierMergedSubId)
|
merge(mobileSubscriptionsChangeEvent, carrierMergedSubId)
|
||||||
.mapLatest { fetchSubscriptionsList().map { it.toSubscriptionModel() } }
|
.mapLatest { fetchSubscriptionsList().map { it.toSubscriptionModel() } }
|
||||||
.logInputChange(logger, "onSubscriptionsChanged")
|
|
||||||
.onEach { infos -> updateRepos(infos) }
|
.onEach { infos -> updateRepos(infos) }
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.logDiffsForTable(
|
||||||
|
tableLogger,
|
||||||
|
LOGGING_PREFIX,
|
||||||
|
columnName = "subscriptions",
|
||||||
|
initialValue = listOf(),
|
||||||
|
)
|
||||||
.stateIn(scope, started = SharingStarted.WhileSubscribed(), listOf())
|
.stateIn(scope, started = SharingStarted.WhileSubscribed(), listOf())
|
||||||
|
|
||||||
/** StateFlow that keeps track of the current active mobile data subscription */
|
/** StateFlow that keeps track of the current active mobile data subscription */
|
||||||
@@ -157,7 +173,12 @@ constructor(
|
|||||||
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
|
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
|
||||||
}
|
}
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.logInputChange(logger, "onActiveDataSubscriptionIdChanged")
|
.logDiffsForTable(
|
||||||
|
tableLogger,
|
||||||
|
LOGGING_PREFIX,
|
||||||
|
columnName = "activeSubId",
|
||||||
|
initialValue = INVALID_SUBSCRIPTION_ID,
|
||||||
|
)
|
||||||
.stateIn(scope, started = SharingStarted.WhileSubscribed(), INVALID_SUBSCRIPTION_ID)
|
.stateIn(scope, started = SharingStarted.WhileSubscribed(), INVALID_SUBSCRIPTION_ID)
|
||||||
|
|
||||||
private val defaultDataSubIdChangeEvent: MutableSharedFlow<Unit> =
|
private val defaultDataSubIdChangeEvent: MutableSharedFlow<Unit> =
|
||||||
@@ -171,7 +192,12 @@ constructor(
|
|||||||
intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
|
intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
|
||||||
}
|
}
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.logInputChange(logger, "ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED")
|
.logDiffsForTable(
|
||||||
|
tableLogger,
|
||||||
|
LOGGING_PREFIX,
|
||||||
|
columnName = "defaultSubId",
|
||||||
|
initialValue = SubscriptionManager.getDefaultDataSubscriptionId(),
|
||||||
|
)
|
||||||
.onEach { defaultDataSubIdChangeEvent.tryEmit(Unit) }
|
.onEach { defaultDataSubIdChangeEvent.tryEmit(Unit) }
|
||||||
.stateIn(
|
.stateIn(
|
||||||
scope,
|
scope,
|
||||||
@@ -247,7 +273,11 @@ constructor(
|
|||||||
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
|
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
|
||||||
}
|
}
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.logInputChange(logger, "defaultMobileNetworkConnectivity")
|
.logDiffsForTable(
|
||||||
|
tableLogger,
|
||||||
|
columnPrefix = "$LOGGING_PREFIX.defaultConnection",
|
||||||
|
initialValue = MobileConnectivityModel(),
|
||||||
|
)
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectivityModel())
|
.stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectivityModel())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -321,4 +351,8 @@ constructor(
|
|||||||
subscriptionId = subscriptionId,
|
subscriptionId = subscriptionId,
|
||||||
isOpportunistic = isOpportunistic,
|
isOpportunistic = isOpportunistic,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val LOGGING_PREFIX = "Repo"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
|
||||||
interface MobileIconInteractor {
|
interface MobileIconInteractor {
|
||||||
@@ -109,6 +111,9 @@ interface MobileIconInteractor {
|
|||||||
|
|
||||||
/** Based on [CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL], either 4 or 5 */
|
/** Based on [CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL], either 4 or 5 */
|
||||||
val numberOfLevels: StateFlow<Int>
|
val numberOfLevels: StateFlow<Int>
|
||||||
|
|
||||||
|
/** See [MobileIconsInteractor.isForceHidden]. */
|
||||||
|
val isForceHidden: Flow<Boolean>
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Interactor for a single mobile connection. This connection _should_ have one subscription ID */
|
/** Interactor for a single mobile connection. This connection _should_ have one subscription ID */
|
||||||
@@ -124,6 +129,7 @@ class MobileIconInteractorImpl(
|
|||||||
defaultMobileIconGroup: StateFlow<MobileIconGroup>,
|
defaultMobileIconGroup: StateFlow<MobileIconGroup>,
|
||||||
defaultDataSubId: StateFlow<Int>,
|
defaultDataSubId: StateFlow<Int>,
|
||||||
override val isDefaultConnectionFailed: StateFlow<Boolean>,
|
override val isDefaultConnectionFailed: StateFlow<Boolean>,
|
||||||
|
override val isForceHidden: Flow<Boolean>,
|
||||||
connectionRepository: MobileConnectionRepository,
|
connectionRepository: MobileConnectionRepository,
|
||||||
) : MobileIconInteractor {
|
) : MobileIconInteractor {
|
||||||
private val connectionInfo = connectionRepository.connectionInfo
|
private val connectionInfo = connectionRepository.connectionInfo
|
||||||
@@ -181,6 +187,16 @@ class MobileIconInteractorImpl(
|
|||||||
else -> mapping[info.resolvedNetworkType.lookupKey] ?: defaultGroup
|
else -> mapping[info.resolvedNetworkType.lookupKey] ?: defaultGroup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.onEach {
|
||||||
|
// Doesn't use [logDiffsForTable] because [MobileIconGroup] can't implement the
|
||||||
|
// [Diffable] interface.
|
||||||
|
tableLogBuffer.logChange(
|
||||||
|
prefix = "",
|
||||||
|
columnName = "networkTypeIcon",
|
||||||
|
value = it.name
|
||||||
|
)
|
||||||
|
}
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value)
|
||||||
|
|
||||||
override val isEmergencyOnly: StateFlow<Boolean> =
|
override val isEmergencyOnly: StateFlow<Boolean> =
|
||||||
|
|||||||
@@ -23,12 +23,17 @@ import com.android.settingslib.SignalIcon.MobileIconGroup
|
|||||||
import com.android.settingslib.mobile.TelephonyIcons
|
import com.android.settingslib.mobile.TelephonyIcons
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.dagger.qualifiers.Application
|
import com.android.systemui.dagger.qualifiers.Application
|
||||||
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
|
import com.android.systemui.log.table.logDiffsForTable
|
||||||
|
import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||||
|
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
|
||||||
|
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
|
||||||
import com.android.systemui.util.CarrierConfigTracker
|
import com.android.systemui.util.CarrierConfigTracker
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -42,8 +47,8 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
|||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.flow.transformLatest
|
import kotlinx.coroutines.flow.transformLatest
|
||||||
|
|
||||||
@@ -88,6 +93,10 @@ interface MobileIconsInteractor {
|
|||||||
val isDefaultConnectionFailed: StateFlow<Boolean>
|
val isDefaultConnectionFailed: StateFlow<Boolean>
|
||||||
/** True once the user has been set up */
|
/** True once the user has been set up */
|
||||||
val isUserSetup: StateFlow<Boolean>
|
val isUserSetup: StateFlow<Boolean>
|
||||||
|
|
||||||
|
/** True if we're configured to force-hide the mobile icons and false otherwise. */
|
||||||
|
val isForceHidden: Flow<Boolean>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vends out a [MobileIconInteractor] tracking the [MobileConnectionRepository] for the given
|
* Vends out a [MobileIconInteractor] tracking the [MobileConnectionRepository] for the given
|
||||||
* subId. Will throw if the ID is invalid
|
* subId. Will throw if the ID is invalid
|
||||||
@@ -104,6 +113,8 @@ constructor(
|
|||||||
private val mobileConnectionsRepo: MobileConnectionsRepository,
|
private val mobileConnectionsRepo: MobileConnectionsRepository,
|
||||||
private val carrierConfigTracker: CarrierConfigTracker,
|
private val carrierConfigTracker: CarrierConfigTracker,
|
||||||
private val logger: ConnectivityPipelineLogger,
|
private val logger: ConnectivityPipelineLogger,
|
||||||
|
@MobileSummaryLog private val tableLogger: TableLogBuffer,
|
||||||
|
connectivityRepository: ConnectivityRepository,
|
||||||
userSetupRepo: UserSetupRepository,
|
userSetupRepo: UserSetupRepository,
|
||||||
@Application private val scope: CoroutineScope,
|
@Application private val scope: CoroutineScope,
|
||||||
) : MobileIconsInteractor {
|
) : MobileIconsInteractor {
|
||||||
@@ -173,7 +184,13 @@ constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.onEach { logger.logFilteredSubscriptionsChanged(it) }
|
.logDiffsForTable(
|
||||||
|
tableLogger,
|
||||||
|
LOGGING_PREFIX,
|
||||||
|
columnName = "filteredSubscriptions",
|
||||||
|
initialValue = listOf(),
|
||||||
|
)
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), listOf())
|
||||||
|
|
||||||
override val defaultDataSubId = mobileConnectionsRepo.defaultDataSubId
|
override val defaultDataSubId = mobileConnectionsRepo.defaultDataSubId
|
||||||
|
|
||||||
@@ -195,6 +212,12 @@ constructor(
|
|||||||
delay(2000)
|
delay(2000)
|
||||||
emit(false)
|
emit(false)
|
||||||
}
|
}
|
||||||
|
.logDiffsForTable(
|
||||||
|
tableLogger,
|
||||||
|
LOGGING_PREFIX,
|
||||||
|
columnName = "forcingValidation",
|
||||||
|
initialValue = false,
|
||||||
|
)
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
override val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel> =
|
override val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel> =
|
||||||
@@ -211,6 +234,12 @@ constructor(
|
|||||||
networkConnectivity
|
networkConnectivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.logDiffsForTable(
|
||||||
|
tableLogger,
|
||||||
|
columnPrefix = "$LOGGING_PREFIX.defaultConnection",
|
||||||
|
initialValue = mobileConnectionsRepo.defaultMobileNetworkConnectivity.value,
|
||||||
|
)
|
||||||
.stateIn(
|
.stateIn(
|
||||||
scope,
|
scope,
|
||||||
SharingStarted.WhileSubscribed(),
|
SharingStarted.WhileSubscribed(),
|
||||||
@@ -259,10 +288,21 @@ constructor(
|
|||||||
!connectivityModel.isValidated
|
!connectivityModel.isValidated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.logDiffsForTable(
|
||||||
|
tableLogger,
|
||||||
|
LOGGING_PREFIX,
|
||||||
|
columnName = "isDefaultConnectionFailed",
|
||||||
|
initialValue = false,
|
||||||
|
)
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
override val isUserSetup: StateFlow<Boolean> = userSetupRepo.isUserSetupFlow
|
override val isUserSetup: StateFlow<Boolean> = userSetupRepo.isUserSetupFlow
|
||||||
|
|
||||||
|
override val isForceHidden: Flow<Boolean> =
|
||||||
|
connectivityRepository.forceHiddenSlots
|
||||||
|
.map { it.contains(ConnectivitySlot.MOBILE) }
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
/** Vends out new [MobileIconInteractor] for a particular subId */
|
/** Vends out new [MobileIconInteractor] for a particular subId */
|
||||||
override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
|
override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
|
||||||
MobileIconInteractorImpl(
|
MobileIconInteractorImpl(
|
||||||
@@ -275,6 +315,11 @@ constructor(
|
|||||||
defaultMobileIconGroup,
|
defaultMobileIconGroup,
|
||||||
defaultDataSubId,
|
defaultDataSubId,
|
||||||
isDefaultConnectionFailed,
|
isDefaultConnectionFailed,
|
||||||
|
isForceHidden,
|
||||||
mobileConnectionsRepo.getRepoForSubId(subId),
|
mobileConnectionsRepo.getRepoForSubId(subId),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val LOGGING_PREFIX = "Intr"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,10 +91,17 @@ object MobileIconBinder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
launch { viewModel.isVisible.collect { isVisible -> view.isVisible = isVisible } }
|
||||||
|
|
||||||
// Set the icon for the triangle
|
// Set the icon for the triangle
|
||||||
launch {
|
launch {
|
||||||
viewModel.iconId.distinctUntilChanged().collect { iconId ->
|
viewModel.icon.distinctUntilChanged().collect { icon ->
|
||||||
mobileDrawable.level = iconId
|
mobileDrawable.level =
|
||||||
|
SignalDrawable.getState(
|
||||||
|
icon.level,
|
||||||
|
icon.numberOfLevels,
|
||||||
|
icon.showExclamationMark,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,8 +155,7 @@ object MobileIconBinder {
|
|||||||
|
|
||||||
return object : ModernStatusBarViewBinding {
|
return object : ModernStatusBarViewBinding {
|
||||||
override fun getShouldIconBeVisible(): Boolean {
|
override fun getShouldIconBeVisible(): Boolean {
|
||||||
// If this view model exists, then the icon should be visible.
|
return viewModel.isVisible.value
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onVisibilityStateChanged(@StatusBarIconView.VisibleState state: Int) {
|
override fun onVisibilityStateChanged(@StatusBarIconView.VisibleState state: Int) {
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.statusbar.pipeline.mobile.ui.model
|
||||||
|
|
||||||
|
import com.android.systemui.log.table.Diffable
|
||||||
|
import com.android.systemui.log.table.TableRowLogger
|
||||||
|
|
||||||
|
/** A model that will be consumed by [SignalDrawable] to show the mobile triangle icon. */
|
||||||
|
data class SignalIconModel(
|
||||||
|
val level: Int,
|
||||||
|
val numberOfLevels: Int,
|
||||||
|
val showExclamationMark: Boolean,
|
||||||
|
) : Diffable<SignalIconModel> {
|
||||||
|
// TODO(b/267767715): Can we implement [logDiffs] and [logFull] generically for data classes?
|
||||||
|
override fun logDiffs(prevVal: SignalIconModel, row: TableRowLogger) {
|
||||||
|
if (prevVal.level != level) {
|
||||||
|
row.logChange(COL_LEVEL, level)
|
||||||
|
}
|
||||||
|
if (prevVal.numberOfLevels != numberOfLevels) {
|
||||||
|
row.logChange(COL_NUM_LEVELS, numberOfLevels)
|
||||||
|
}
|
||||||
|
if (prevVal.showExclamationMark != showExclamationMark) {
|
||||||
|
row.logChange(COL_SHOW_EXCLAMATION, showExclamationMark)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun logFull(row: TableRowLogger) {
|
||||||
|
row.logChange(COL_LEVEL, level)
|
||||||
|
row.logChange(COL_NUM_LEVELS, numberOfLevels)
|
||||||
|
row.logChange(COL_SHOW_EXCLAMATION, showExclamationMark)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/** Creates a [SignalIconModel] representing an empty and invalidated state. */
|
||||||
|
fun createEmptyState(numberOfLevels: Int) =
|
||||||
|
SignalIconModel(level = 0, numberOfLevels, showExclamationMark = true)
|
||||||
|
|
||||||
|
private const val COL_LEVEL = "level"
|
||||||
|
private const val COL_NUM_LEVELS = "numLevels"
|
||||||
|
private const val COL_SHOW_EXCLAMATION = "showExclamation"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,10 +22,11 @@ import com.android.settingslib.graph.SignalDrawable
|
|||||||
import com.android.systemui.common.shared.model.ContentDescription
|
import com.android.systemui.common.shared.model.ContentDescription
|
||||||
import com.android.systemui.common.shared.model.Icon
|
import com.android.systemui.common.shared.model.Icon
|
||||||
import com.android.systemui.log.table.logDiffsForTable
|
import com.android.systemui.log.table.logDiffsForTable
|
||||||
|
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
|
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
|
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
|
||||||
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
@@ -37,14 +38,14 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
|||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
|
||||||
/** Common interface for all of the location-based mobile icon view models. */
|
/** Common interface for all of the location-based mobile icon view models. */
|
||||||
interface MobileIconViewModelCommon {
|
interface MobileIconViewModelCommon {
|
||||||
val subscriptionId: Int
|
val subscriptionId: Int
|
||||||
/** An int consumable by [SignalDrawable] for display */
|
/** True if this view should be visible at all. */
|
||||||
val iconId: Flow<Int>
|
val isVisible: StateFlow<Boolean>
|
||||||
|
val icon: Flow<SignalIconModel>
|
||||||
val contentDescription: Flow<ContentDescription>
|
val contentDescription: Flow<ContentDescription>
|
||||||
val roaming: Flow<Boolean>
|
val roaming: Flow<Boolean>
|
||||||
/** The RAT icon (LTE, 3G, 5G, etc) to be displayed. Null if we shouldn't show anything */
|
/** The RAT icon (LTE, 3G, 5G, etc) to be displayed. Null if we shouldn't show anything */
|
||||||
@@ -73,7 +74,7 @@ class MobileIconViewModel
|
|||||||
constructor(
|
constructor(
|
||||||
override val subscriptionId: Int,
|
override val subscriptionId: Int,
|
||||||
iconInteractor: MobileIconInteractor,
|
iconInteractor: MobileIconInteractor,
|
||||||
logger: ConnectivityPipelineLogger,
|
airplaneModeInteractor: AirplaneModeInteractor,
|
||||||
constants: ConnectivityConstants,
|
constants: ConnectivityConstants,
|
||||||
scope: CoroutineScope,
|
scope: CoroutineScope,
|
||||||
) : MobileIconViewModelCommon {
|
) : MobileIconViewModelCommon {
|
||||||
@@ -81,8 +82,28 @@ constructor(
|
|||||||
private val showExclamationMark: Flow<Boolean> =
|
private val showExclamationMark: Flow<Boolean> =
|
||||||
iconInteractor.isDefaultDataEnabled.mapLatest { !it }
|
iconInteractor.isDefaultDataEnabled.mapLatest { !it }
|
||||||
|
|
||||||
override val iconId: Flow<Int> = run {
|
override val isVisible: StateFlow<Boolean> =
|
||||||
val initial = SignalDrawable.getEmptyState(iconInteractor.numberOfLevels.value)
|
if (!constants.hasDataCapabilities) {
|
||||||
|
flowOf(false)
|
||||||
|
} else {
|
||||||
|
combine(
|
||||||
|
airplaneModeInteractor.isAirplaneMode,
|
||||||
|
iconInteractor.isForceHidden,
|
||||||
|
) { isAirplaneMode, isForceHidden ->
|
||||||
|
!isAirplaneMode && !isForceHidden
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.logDiffsForTable(
|
||||||
|
iconInteractor.tableLogBuffer,
|
||||||
|
columnPrefix = "",
|
||||||
|
columnName = "visible",
|
||||||
|
initialValue = false,
|
||||||
|
)
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
|
override val icon: Flow<SignalIconModel> = run {
|
||||||
|
val initial = SignalIconModel.createEmptyState(iconInteractor.numberOfLevels.value)
|
||||||
combine(
|
combine(
|
||||||
iconInteractor.level,
|
iconInteractor.level,
|
||||||
iconInteractor.numberOfLevels,
|
iconInteractor.numberOfLevels,
|
||||||
@@ -90,16 +111,15 @@ constructor(
|
|||||||
iconInteractor.isInService,
|
iconInteractor.isInService,
|
||||||
) { level, numberOfLevels, showExclamationMark, isInService ->
|
) { level, numberOfLevels, showExclamationMark, isInService ->
|
||||||
if (!isInService) {
|
if (!isInService) {
|
||||||
SignalDrawable.getEmptyState(numberOfLevels)
|
SignalIconModel.createEmptyState(numberOfLevels)
|
||||||
} else {
|
} else {
|
||||||
SignalDrawable.getState(level, numberOfLevels, showExclamationMark)
|
SignalIconModel(level, numberOfLevels, showExclamationMark)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.logDiffsForTable(
|
.logDiffsForTable(
|
||||||
iconInteractor.tableLogBuffer,
|
iconInteractor.tableLogBuffer,
|
||||||
columnPrefix = "",
|
columnPrefix = "icon",
|
||||||
columnName = "iconId",
|
|
||||||
initialValue = initial,
|
initialValue = initial,
|
||||||
)
|
)
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
|
||||||
@@ -132,6 +152,14 @@ constructor(
|
|||||||
) { dataConnected, dataEnabled, failedConnection, alwaysShow, connected ->
|
) { dataConnected, dataEnabled, failedConnection, alwaysShow, connected ->
|
||||||
alwaysShow || (dataConnected && dataEnabled && !failedConnection && connected)
|
alwaysShow || (dataConnected && dataEnabled && !failedConnection && connected)
|
||||||
}
|
}
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.logDiffsForTable(
|
||||||
|
iconInteractor.tableLogBuffer,
|
||||||
|
columnPrefix = "",
|
||||||
|
columnName = "showNetworkTypeIcon",
|
||||||
|
initialValue = false,
|
||||||
|
)
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
override val networkTypeIcon: Flow<Icon?> =
|
override val networkTypeIcon: Flow<Icon?> =
|
||||||
combine(
|
combine(
|
||||||
@@ -149,14 +177,6 @@ constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.onEach {
|
|
||||||
// This is done as an onEach side effect since Icon is not Diffable (yet)
|
|
||||||
iconInteractor.tableLogBuffer.logChange(
|
|
||||||
prefix = "",
|
|
||||||
columnName = "networkTypeIcon",
|
|
||||||
value = it.toString(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
override val roaming: StateFlow<Boolean> =
|
override val roaming: StateFlow<Boolean> =
|
||||||
|
|||||||
@@ -17,9 +17,11 @@
|
|||||||
package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
|
package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.dagger.qualifiers.Application
|
import com.android.systemui.dagger.qualifiers.Application
|
||||||
import com.android.systemui.statusbar.phone.StatusBarLocation
|
import com.android.systemui.statusbar.phone.StatusBarLocation
|
||||||
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
||||||
|
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
|
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
|
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
||||||
@@ -39,6 +41,7 @@ class MobileIconsViewModel
|
|||||||
constructor(
|
constructor(
|
||||||
val subscriptionIdsFlow: StateFlow<List<Int>>,
|
val subscriptionIdsFlow: StateFlow<List<Int>>,
|
||||||
private val interactor: MobileIconsInteractor,
|
private val interactor: MobileIconsInteractor,
|
||||||
|
private val airplaneModeInteractor: AirplaneModeInteractor,
|
||||||
private val logger: ConnectivityPipelineLogger,
|
private val logger: ConnectivityPipelineLogger,
|
||||||
private val constants: ConnectivityConstants,
|
private val constants: ConnectivityConstants,
|
||||||
@Application private val scope: CoroutineScope,
|
@Application private val scope: CoroutineScope,
|
||||||
@@ -56,7 +59,7 @@ constructor(
|
|||||||
?: MobileIconViewModel(
|
?: MobileIconViewModel(
|
||||||
subId,
|
subId,
|
||||||
interactor.createMobileConnectionInteractorForSubId(subId),
|
interactor.createMobileConnectionInteractorForSubId(subId),
|
||||||
logger,
|
airplaneModeInteractor,
|
||||||
constants,
|
constants,
|
||||||
scope,
|
scope,
|
||||||
)
|
)
|
||||||
@@ -74,10 +77,12 @@ constructor(
|
|||||||
subIdsToRemove.forEach { mobileIconSubIdCache.remove(it) }
|
subIdsToRemove.forEach { mobileIconSubIdCache.remove(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SysUISingleton
|
||||||
class Factory
|
class Factory
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val interactor: MobileIconsInteractor,
|
private val interactor: MobileIconsInteractor,
|
||||||
|
private val airplaneModeInteractor: AirplaneModeInteractor,
|
||||||
private val logger: ConnectivityPipelineLogger,
|
private val logger: ConnectivityPipelineLogger,
|
||||||
private val constants: ConnectivityConstants,
|
private val constants: ConnectivityConstants,
|
||||||
@Application private val scope: CoroutineScope,
|
@Application private val scope: CoroutineScope,
|
||||||
@@ -87,6 +92,7 @@ constructor(
|
|||||||
return MobileIconsViewModel(
|
return MobileIconsViewModel(
|
||||||
subscriptionIdsFlow,
|
subscriptionIdsFlow,
|
||||||
interactor,
|
interactor,
|
||||||
|
airplaneModeInteractor,
|
||||||
logger,
|
logger,
|
||||||
constants,
|
constants,
|
||||||
scope,
|
scope,
|
||||||
|
|||||||
@@ -204,15 +204,6 @@ constructor(
|
|||||||
|
|
||||||
// TODO(b/238425913): We should split this class into mobile-specific and wifi-specific loggers.
|
// TODO(b/238425913): We should split this class into mobile-specific and wifi-specific loggers.
|
||||||
|
|
||||||
fun logFilteredSubscriptionsChanged(subs: List<SubscriptionModel>) {
|
|
||||||
buffer.log(
|
|
||||||
SB_LOGGING_TAG,
|
|
||||||
LogLevel.INFO,
|
|
||||||
{ str1 = subs.toString() },
|
|
||||||
{ "Filtered subscriptions updated: $str1" },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun logUiAdapterSubIdsUpdated(subs: List<Int>) {
|
fun logUiAdapterSubIdsUpdated(subs: List<Int>) {
|
||||||
buffer.log(
|
buffer.log(
|
||||||
SB_LOGGING_TAG,
|
SB_LOGGING_TAG,
|
||||||
|
|||||||
@@ -275,6 +275,52 @@ class LogDiffsForTableTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun intNullable_logsNull() =
|
||||||
|
testScope.runTest {
|
||||||
|
systemClock.setCurrentTimeMillis(100L)
|
||||||
|
val flow = flow {
|
||||||
|
for (int in listOf(null, 6, null, 8)) {
|
||||||
|
systemClock.advanceTime(100L)
|
||||||
|
emit(int)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val flowWithLogging =
|
||||||
|
flow.logDiffsForTable(
|
||||||
|
tableLogBuffer,
|
||||||
|
COLUMN_PREFIX,
|
||||||
|
COLUMN_NAME,
|
||||||
|
initialValue = 1234,
|
||||||
|
)
|
||||||
|
|
||||||
|
val job = launch { flowWithLogging.collect() }
|
||||||
|
|
||||||
|
val logs = dumpLog()
|
||||||
|
assertThat(logs)
|
||||||
|
.contains(
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(100L) + SEPARATOR + FULL_NAME + SEPARATOR + "1234"
|
||||||
|
)
|
||||||
|
assertThat(logs)
|
||||||
|
.contains(
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(200L) + SEPARATOR + FULL_NAME + SEPARATOR + "null"
|
||||||
|
)
|
||||||
|
assertThat(logs)
|
||||||
|
.contains(
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(300L) + SEPARATOR + FULL_NAME + SEPARATOR + "6"
|
||||||
|
)
|
||||||
|
assertThat(logs)
|
||||||
|
.contains(
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(400L) + SEPARATOR + FULL_NAME + SEPARATOR + "null"
|
||||||
|
)
|
||||||
|
assertThat(logs)
|
||||||
|
.contains(
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(500L) + SEPARATOR + FULL_NAME + SEPARATOR + "8"
|
||||||
|
)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun int_logsUpdates() =
|
fun int_logsUpdates() =
|
||||||
testScope.runTest {
|
testScope.runTest {
|
||||||
@@ -1030,6 +1076,246 @@ class LogDiffsForTableTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- Flow<List<T>> tests ----
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun list_doesNotLogWhenNotCollected() {
|
||||||
|
val flow = flowOf(listOf(5), listOf(6), listOf(7))
|
||||||
|
|
||||||
|
flow.logDiffsForTable(
|
||||||
|
tableLogBuffer,
|
||||||
|
COLUMN_PREFIX,
|
||||||
|
COLUMN_NAME,
|
||||||
|
initialValue = listOf(1234),
|
||||||
|
)
|
||||||
|
|
||||||
|
val logs = dumpLog()
|
||||||
|
assertThat(logs).doesNotContain(COLUMN_PREFIX)
|
||||||
|
assertThat(logs).doesNotContain(COLUMN_NAME)
|
||||||
|
assertThat(logs).doesNotContain("1234")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun list_logsInitialWhenCollected() =
|
||||||
|
testScope.runTest {
|
||||||
|
val flow = flowOf(listOf(5), listOf(6), listOf(7))
|
||||||
|
|
||||||
|
val flowWithLogging =
|
||||||
|
flow.logDiffsForTable(
|
||||||
|
tableLogBuffer,
|
||||||
|
COLUMN_PREFIX,
|
||||||
|
COLUMN_NAME,
|
||||||
|
initialValue = listOf(1234),
|
||||||
|
)
|
||||||
|
|
||||||
|
systemClock.setCurrentTimeMillis(3000L)
|
||||||
|
val job = launch { flowWithLogging.collect() }
|
||||||
|
|
||||||
|
val logs = dumpLog()
|
||||||
|
assertThat(logs)
|
||||||
|
.contains(
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(3000L) +
|
||||||
|
SEPARATOR +
|
||||||
|
FULL_NAME +
|
||||||
|
SEPARATOR +
|
||||||
|
listOf(1234).toString()
|
||||||
|
)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun list_logsUpdates() =
|
||||||
|
testScope.runTest {
|
||||||
|
systemClock.setCurrentTimeMillis(100L)
|
||||||
|
|
||||||
|
val listItems =
|
||||||
|
listOf(listOf("val1", "val2"), listOf("val3"), listOf("val4", "val5", "val6"))
|
||||||
|
val flow = flow {
|
||||||
|
for (list in listItems) {
|
||||||
|
systemClock.advanceTime(100L)
|
||||||
|
emit(list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val flowWithLogging =
|
||||||
|
flow.logDiffsForTable(
|
||||||
|
tableLogBuffer,
|
||||||
|
COLUMN_PREFIX,
|
||||||
|
COLUMN_NAME,
|
||||||
|
initialValue = listOf("val0", "val00"),
|
||||||
|
)
|
||||||
|
|
||||||
|
val job = launch { flowWithLogging.collect() }
|
||||||
|
|
||||||
|
val logs = dumpLog()
|
||||||
|
assertThat(logs)
|
||||||
|
.contains(
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(100L) +
|
||||||
|
SEPARATOR +
|
||||||
|
FULL_NAME +
|
||||||
|
SEPARATOR +
|
||||||
|
listOf("val0", "val00").toString()
|
||||||
|
)
|
||||||
|
assertThat(logs)
|
||||||
|
.contains(
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(200L) +
|
||||||
|
SEPARATOR +
|
||||||
|
FULL_NAME +
|
||||||
|
SEPARATOR +
|
||||||
|
listOf("val1", "val2").toString()
|
||||||
|
)
|
||||||
|
assertThat(logs)
|
||||||
|
.contains(
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(300L) +
|
||||||
|
SEPARATOR +
|
||||||
|
FULL_NAME +
|
||||||
|
SEPARATOR +
|
||||||
|
listOf("val3").toString()
|
||||||
|
)
|
||||||
|
assertThat(logs)
|
||||||
|
.contains(
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(400L) +
|
||||||
|
SEPARATOR +
|
||||||
|
FULL_NAME +
|
||||||
|
SEPARATOR +
|
||||||
|
listOf("val4", "val5", "val6").toString()
|
||||||
|
)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun list_doesNotLogIfSameValue() =
|
||||||
|
testScope.runTest {
|
||||||
|
systemClock.setCurrentTimeMillis(100L)
|
||||||
|
|
||||||
|
val listItems =
|
||||||
|
listOf(
|
||||||
|
listOf("val0", "val00"),
|
||||||
|
listOf("val1"),
|
||||||
|
listOf("val1"),
|
||||||
|
listOf("val1", "val2"),
|
||||||
|
)
|
||||||
|
val flow = flow {
|
||||||
|
for (bool in listItems) {
|
||||||
|
systemClock.advanceTime(100L)
|
||||||
|
emit(bool)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val flowWithLogging =
|
||||||
|
flow.logDiffsForTable(
|
||||||
|
tableLogBuffer,
|
||||||
|
COLUMN_PREFIX,
|
||||||
|
COLUMN_NAME,
|
||||||
|
initialValue = listOf("val0", "val00"),
|
||||||
|
)
|
||||||
|
|
||||||
|
val job = launch { flowWithLogging.collect() }
|
||||||
|
|
||||||
|
val logs = dumpLog()
|
||||||
|
|
||||||
|
val expected1 =
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(100L) +
|
||||||
|
SEPARATOR +
|
||||||
|
FULL_NAME +
|
||||||
|
SEPARATOR +
|
||||||
|
listOf("val0", "val00").toString()
|
||||||
|
val expected3 =
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(300L) +
|
||||||
|
SEPARATOR +
|
||||||
|
FULL_NAME +
|
||||||
|
SEPARATOR +
|
||||||
|
listOf("val1").toString()
|
||||||
|
val expected5 =
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(500L) +
|
||||||
|
SEPARATOR +
|
||||||
|
FULL_NAME +
|
||||||
|
SEPARATOR +
|
||||||
|
listOf("val1", "val2").toString()
|
||||||
|
assertThat(logs).contains(expected1)
|
||||||
|
assertThat(logs).contains(expected3)
|
||||||
|
assertThat(logs).contains(expected5)
|
||||||
|
|
||||||
|
val unexpected2 =
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(200L) +
|
||||||
|
SEPARATOR +
|
||||||
|
FULL_NAME +
|
||||||
|
SEPARATOR +
|
||||||
|
listOf("val0", "val00")
|
||||||
|
val unexpected4 =
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(400L) +
|
||||||
|
SEPARATOR +
|
||||||
|
FULL_NAME +
|
||||||
|
SEPARATOR +
|
||||||
|
listOf("val1")
|
||||||
|
assertThat(logs).doesNotContain(unexpected2)
|
||||||
|
assertThat(logs).doesNotContain(unexpected4)
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun list_worksForStateFlows() =
|
||||||
|
testScope.runTest {
|
||||||
|
val flow = MutableStateFlow(listOf(1111))
|
||||||
|
|
||||||
|
val flowWithLogging =
|
||||||
|
flow.logDiffsForTable(
|
||||||
|
tableLogBuffer,
|
||||||
|
COLUMN_PREFIX,
|
||||||
|
COLUMN_NAME,
|
||||||
|
initialValue = listOf(1111),
|
||||||
|
)
|
||||||
|
|
||||||
|
systemClock.setCurrentTimeMillis(50L)
|
||||||
|
val job = launch { flowWithLogging.collect() }
|
||||||
|
assertThat(dumpLog())
|
||||||
|
.contains(
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(50L) +
|
||||||
|
SEPARATOR +
|
||||||
|
FULL_NAME +
|
||||||
|
SEPARATOR +
|
||||||
|
listOf(1111).toString()
|
||||||
|
)
|
||||||
|
|
||||||
|
systemClock.setCurrentTimeMillis(100L)
|
||||||
|
flow.emit(listOf(2222, 3333))
|
||||||
|
assertThat(dumpLog())
|
||||||
|
.contains(
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(100L) +
|
||||||
|
SEPARATOR +
|
||||||
|
FULL_NAME +
|
||||||
|
SEPARATOR +
|
||||||
|
listOf(2222, 3333).toString()
|
||||||
|
)
|
||||||
|
|
||||||
|
systemClock.setCurrentTimeMillis(200L)
|
||||||
|
flow.emit(listOf(3333, 4444))
|
||||||
|
assertThat(dumpLog())
|
||||||
|
.contains(
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(200L) +
|
||||||
|
SEPARATOR +
|
||||||
|
FULL_NAME +
|
||||||
|
SEPARATOR +
|
||||||
|
listOf(3333, 4444).toString()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Doesn't log duplicates
|
||||||
|
systemClock.setCurrentTimeMillis(300L)
|
||||||
|
flow.emit(listOf(3333, 4444))
|
||||||
|
assertThat(dumpLog())
|
||||||
|
.doesNotContain(
|
||||||
|
TABLE_LOG_DATE_FORMAT.format(300L) +
|
||||||
|
SEPARATOR +
|
||||||
|
FULL_NAME +
|
||||||
|
SEPARATOR +
|
||||||
|
listOf(3333, 4444).toString()
|
||||||
|
)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
private fun dumpLog(): String {
|
private fun dumpLog(): String {
|
||||||
val outputWriter = StringWriter()
|
val outputWriter = StringWriter()
|
||||||
tableLogBuffer.dump(PrintWriter(outputWriter), arrayOf())
|
tableLogBuffer.dump(PrintWriter(outputWriter), arrayOf())
|
||||||
|
|||||||
@@ -35,6 +35,17 @@ class TableChangeTest : SysuiTestCase() {
|
|||||||
assertThat(underTest.getVal()).isEqualTo("fakeValue")
|
assertThat(underTest.getVal()).isEqualTo("fakeValue")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun setString_null() {
|
||||||
|
val underTest = TableChange()
|
||||||
|
|
||||||
|
underTest.reset(timestamp = 100, columnPrefix = "", columnName = "fakeName")
|
||||||
|
underTest.set(null as String?)
|
||||||
|
|
||||||
|
assertThat(underTest.hasData()).isTrue()
|
||||||
|
assertThat(underTest.getVal()).isEqualTo("null")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun setBoolean_isBoolean() {
|
fun setBoolean_isBoolean() {
|
||||||
val underTest = TableChange()
|
val underTest = TableChange()
|
||||||
@@ -57,6 +68,17 @@ class TableChangeTest : SysuiTestCase() {
|
|||||||
assertThat(underTest.getVal()).isEqualTo("8900")
|
assertThat(underTest.getVal()).isEqualTo("8900")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun setInt_null() {
|
||||||
|
val underTest = TableChange()
|
||||||
|
|
||||||
|
underTest.reset(timestamp = 100, columnPrefix = "", columnName = "fakeName")
|
||||||
|
underTest.set(null as Int?)
|
||||||
|
|
||||||
|
assertThat(underTest.hasData()).isTrue()
|
||||||
|
assertThat(underTest.getVal()).isEqualTo("null")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun setThenReset_isEmpty() {
|
fun setThenReset_isEmpty() {
|
||||||
val underTest = TableChange()
|
val underTest = TableChange()
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.android.systemui.SysuiTestCase
|
|||||||
import com.android.systemui.demomode.DemoMode
|
import com.android.systemui.demomode.DemoMode
|
||||||
import com.android.systemui.demomode.DemoModeController
|
import com.android.systemui.demomode.DemoModeController
|
||||||
import com.android.systemui.dump.DumpManager
|
import com.android.systemui.dump.DumpManager
|
||||||
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
import com.android.systemui.log.table.TableLogBufferFactory
|
import com.android.systemui.log.table.TableLogBufferFactory
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepository
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepository
|
||||||
@@ -81,6 +82,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
|
|||||||
@Mock private lateinit var subscriptionManager: SubscriptionManager
|
@Mock private lateinit var subscriptionManager: SubscriptionManager
|
||||||
@Mock private lateinit var telephonyManager: TelephonyManager
|
@Mock private lateinit var telephonyManager: TelephonyManager
|
||||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||||
|
@Mock private lateinit var summaryLogger: TableLogBuffer
|
||||||
@Mock private lateinit var demoModeController: DemoModeController
|
@Mock private lateinit var demoModeController: DemoModeController
|
||||||
@Mock private lateinit var dumpManager: DumpManager
|
@Mock private lateinit var dumpManager: DumpManager
|
||||||
|
|
||||||
@@ -114,6 +116,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
|
|||||||
subscriptionManager,
|
subscriptionManager,
|
||||||
telephonyManager,
|
telephonyManager,
|
||||||
logger,
|
logger,
|
||||||
|
summaryLogger,
|
||||||
mobileMappings,
|
mobileMappings,
|
||||||
fakeBroadcastDispatcher,
|
fakeBroadcastDispatcher,
|
||||||
context,
|
context,
|
||||||
|
|||||||
@@ -16,20 +16,32 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
|
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
|
||||||
|
|
||||||
|
import android.telephony.ServiceState
|
||||||
|
import android.telephony.SignalStrength
|
||||||
|
import android.telephony.TelephonyCallback
|
||||||
|
import android.telephony.TelephonyManager
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.log.table.TableLogBuffer
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
import com.android.systemui.log.table.TableLogBufferFactory
|
import com.android.systemui.log.table.TableLogBufferFactory
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_EMERGENCY
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_OPERATOR
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_PRIMARY_LEVEL
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.getTelephonyCallbackForType
|
||||||
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
|
||||||
import com.android.systemui.util.mockito.any
|
import com.android.systemui.util.mockito.any
|
||||||
import com.android.systemui.util.mockito.eq
|
import com.android.systemui.util.mockito.eq
|
||||||
import com.android.systemui.util.mockito.mock
|
import com.android.systemui.util.mockito.mock
|
||||||
import com.android.systemui.util.mockito.whenever
|
import com.android.systemui.util.mockito.whenever
|
||||||
import com.android.systemui.util.time.FakeSystemClock
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import java.io.PrintWriter
|
||||||
|
import java.io.StringWriter
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@@ -52,9 +64,10 @@ import org.mockito.Mockito.verify
|
|||||||
class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
||||||
private lateinit var underTest: FullMobileConnectionRepository
|
private lateinit var underTest: FullMobileConnectionRepository
|
||||||
|
|
||||||
|
private val systemClock = FakeSystemClock()
|
||||||
private val testDispatcher = UnconfinedTestDispatcher()
|
private val testDispatcher = UnconfinedTestDispatcher()
|
||||||
private val testScope = TestScope(testDispatcher)
|
private val testScope = TestScope(testDispatcher)
|
||||||
private val tableLogBuffer = mock<TableLogBuffer>()
|
private val tableLogBuffer = TableLogBuffer(maxSize = 100, name = "TestName", systemClock)
|
||||||
private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>()
|
private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>()
|
||||||
private val carrierMergedFactory = mock<CarrierMergedConnectionRepository.Factory>()
|
private val carrierMergedFactory = mock<CarrierMergedConnectionRepository.Factory>()
|
||||||
|
|
||||||
@@ -347,8 +360,214 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
.isSameInstanceAs(connection1Repeat.tableLogBuffer)
|
.isSameInstanceAs(connection1Repeat.tableLogBuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(b/238425913): Verify that the logging switches correctly (once the carrier merged repo
|
@Test
|
||||||
// implements logging).
|
fun connectionInfo_logging_notCarrierMerged_getsUpdates() =
|
||||||
|
testScope.runTest {
|
||||||
|
// SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
|
||||||
|
val telephonyManager = mock<TelephonyManager>()
|
||||||
|
createRealMobileRepo(telephonyManager)
|
||||||
|
createRealCarrierMergedRepo(FakeWifiRepository())
|
||||||
|
|
||||||
|
initializeRepo(startingIsCarrierMerged = false)
|
||||||
|
|
||||||
|
val job = underTest.connectionInfo.launchIn(this)
|
||||||
|
|
||||||
|
// WHEN we set up some mobile connection info
|
||||||
|
val serviceState = ServiceState()
|
||||||
|
serviceState.setOperatorName("longName", "OpTypical", "1")
|
||||||
|
serviceState.isEmergencyOnly = false
|
||||||
|
getTelephonyCallbackForType<TelephonyCallback.ServiceStateListener>(telephonyManager)
|
||||||
|
.onServiceStateChanged(serviceState)
|
||||||
|
|
||||||
|
// THEN it's logged to the buffer
|
||||||
|
assertThat(dumpBuffer()).contains("$COL_OPERATOR${BUFFER_SEPARATOR}OpTypical")
|
||||||
|
assertThat(dumpBuffer()).contains("$COL_EMERGENCY${BUFFER_SEPARATOR}false")
|
||||||
|
|
||||||
|
// WHEN we update mobile connection info
|
||||||
|
val serviceState2 = ServiceState()
|
||||||
|
serviceState2.setOperatorName("longName", "OpDiff", "1")
|
||||||
|
serviceState2.isEmergencyOnly = true
|
||||||
|
getTelephonyCallbackForType<TelephonyCallback.ServiceStateListener>(telephonyManager)
|
||||||
|
.onServiceStateChanged(serviceState2)
|
||||||
|
|
||||||
|
// THEN the updates are logged
|
||||||
|
assertThat(dumpBuffer()).contains("$COL_OPERATOR${BUFFER_SEPARATOR}OpDiff")
|
||||||
|
assertThat(dumpBuffer()).contains("$COL_EMERGENCY${BUFFER_SEPARATOR}true")
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectionInfo_logging_carrierMerged_getsUpdates() =
|
||||||
|
testScope.runTest {
|
||||||
|
// SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
|
||||||
|
createRealMobileRepo(mock())
|
||||||
|
val wifiRepository = FakeWifiRepository()
|
||||||
|
createRealCarrierMergedRepo(wifiRepository)
|
||||||
|
|
||||||
|
initializeRepo(startingIsCarrierMerged = true)
|
||||||
|
|
||||||
|
val job = underTest.connectionInfo.launchIn(this)
|
||||||
|
|
||||||
|
// WHEN we set up carrier merged info
|
||||||
|
val networkId = 2
|
||||||
|
wifiRepository.setWifiNetwork(
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId,
|
||||||
|
SUB_ID,
|
||||||
|
level = 3,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// THEN the carrier merged info is logged
|
||||||
|
assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}3")
|
||||||
|
|
||||||
|
// WHEN we update the info
|
||||||
|
wifiRepository.setWifiNetwork(
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId,
|
||||||
|
SUB_ID,
|
||||||
|
level = 1,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// THEN the updates are logged
|
||||||
|
assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectionInfo_logging_updatesWhenCarrierMergedUpdates() =
|
||||||
|
testScope.runTest {
|
||||||
|
// SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
|
||||||
|
val telephonyManager = mock<TelephonyManager>()
|
||||||
|
createRealMobileRepo(telephonyManager)
|
||||||
|
|
||||||
|
val wifiRepository = FakeWifiRepository()
|
||||||
|
createRealCarrierMergedRepo(wifiRepository)
|
||||||
|
|
||||||
|
initializeRepo(startingIsCarrierMerged = false)
|
||||||
|
|
||||||
|
val job = underTest.connectionInfo.launchIn(this)
|
||||||
|
|
||||||
|
// WHEN we set up some mobile connection info
|
||||||
|
val signalStrength = mock<SignalStrength>()
|
||||||
|
whenever(signalStrength.level).thenReturn(1)
|
||||||
|
|
||||||
|
getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>(telephonyManager)
|
||||||
|
.onSignalStrengthsChanged(signalStrength)
|
||||||
|
|
||||||
|
// THEN it's logged to the buffer
|
||||||
|
assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
|
||||||
|
|
||||||
|
// WHEN isCarrierMerged is set to true
|
||||||
|
val networkId = 2
|
||||||
|
wifiRepository.setWifiNetwork(
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId,
|
||||||
|
SUB_ID,
|
||||||
|
level = 3,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
underTest.setIsCarrierMerged(true)
|
||||||
|
|
||||||
|
// THEN the carrier merged info is logged
|
||||||
|
assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}3")
|
||||||
|
|
||||||
|
// WHEN the carrier merge network is updated
|
||||||
|
wifiRepository.setWifiNetwork(
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId,
|
||||||
|
SUB_ID,
|
||||||
|
level = 4,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// THEN the new level is logged
|
||||||
|
assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}4")
|
||||||
|
|
||||||
|
// WHEN isCarrierMerged is set to false
|
||||||
|
underTest.setIsCarrierMerged(false)
|
||||||
|
|
||||||
|
// THEN the typical info is logged
|
||||||
|
// Note: Since our first logs also had the typical info, we need to search the log
|
||||||
|
// contents for after our carrier merged level log.
|
||||||
|
val fullBuffer = dumpBuffer()
|
||||||
|
val carrierMergedContentIndex = fullBuffer.indexOf("${BUFFER_SEPARATOR}4")
|
||||||
|
val bufferAfterCarrierMerged = fullBuffer.substring(carrierMergedContentIndex)
|
||||||
|
assertThat(bufferAfterCarrierMerged).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
|
||||||
|
|
||||||
|
// WHEN the normal network is updated
|
||||||
|
val newMobileInfo =
|
||||||
|
MobileConnectionModel(
|
||||||
|
operatorAlphaShort = "Mobile Operator 2",
|
||||||
|
primaryLevel = 0,
|
||||||
|
)
|
||||||
|
mobileRepo.setConnectionInfo(newMobileInfo)
|
||||||
|
|
||||||
|
// THEN the new level is logged
|
||||||
|
assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}0")
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectionInfo_logging_doesNotLogUpdatesForNotActiveRepo() =
|
||||||
|
testScope.runTest {
|
||||||
|
// SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
|
||||||
|
val telephonyManager = mock<TelephonyManager>()
|
||||||
|
createRealMobileRepo(telephonyManager)
|
||||||
|
|
||||||
|
val wifiRepository = FakeWifiRepository()
|
||||||
|
createRealCarrierMergedRepo(wifiRepository)
|
||||||
|
|
||||||
|
// WHEN isCarrierMerged = false
|
||||||
|
initializeRepo(startingIsCarrierMerged = false)
|
||||||
|
|
||||||
|
val job = underTest.connectionInfo.launchIn(this)
|
||||||
|
|
||||||
|
val signalStrength = mock<SignalStrength>()
|
||||||
|
whenever(signalStrength.level).thenReturn(1)
|
||||||
|
getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>(telephonyManager)
|
||||||
|
.onSignalStrengthsChanged(signalStrength)
|
||||||
|
|
||||||
|
// THEN updates to the carrier merged level aren't logged
|
||||||
|
val networkId = 2
|
||||||
|
wifiRepository.setWifiNetwork(
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId,
|
||||||
|
SUB_ID,
|
||||||
|
level = 4,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}4")
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId,
|
||||||
|
SUB_ID,
|
||||||
|
level = 3,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}3")
|
||||||
|
|
||||||
|
// WHEN isCarrierMerged is set to true
|
||||||
|
underTest.setIsCarrierMerged(true)
|
||||||
|
|
||||||
|
// THEN updates to the normal level aren't logged
|
||||||
|
whenever(signalStrength.level).thenReturn(5)
|
||||||
|
getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>(telephonyManager)
|
||||||
|
.onSignalStrengthsChanged(signalStrength)
|
||||||
|
assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}5")
|
||||||
|
|
||||||
|
whenever(signalStrength.level).thenReturn(6)
|
||||||
|
getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>(telephonyManager)
|
||||||
|
.onSignalStrengthsChanged(signalStrength)
|
||||||
|
assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}6")
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
private fun initializeRepo(startingIsCarrierMerged: Boolean) {
|
private fun initializeRepo(startingIsCarrierMerged: Boolean) {
|
||||||
underTest =
|
underTest =
|
||||||
@@ -364,9 +583,68 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createRealMobileRepo(
|
||||||
|
telephonyManager: TelephonyManager,
|
||||||
|
): MobileConnectionRepositoryImpl {
|
||||||
|
whenever(telephonyManager.subscriptionId).thenReturn(SUB_ID)
|
||||||
|
|
||||||
|
val realRepo =
|
||||||
|
MobileConnectionRepositoryImpl(
|
||||||
|
context,
|
||||||
|
SUB_ID,
|
||||||
|
defaultNetworkName = NetworkNameModel.Default("default"),
|
||||||
|
networkNameSeparator = SEP,
|
||||||
|
telephonyManager,
|
||||||
|
systemUiCarrierConfig = mock(),
|
||||||
|
fakeBroadcastDispatcher,
|
||||||
|
mobileMappingsProxy = mock(),
|
||||||
|
testDispatcher,
|
||||||
|
logger = mock(),
|
||||||
|
tableLogBuffer,
|
||||||
|
testScope.backgroundScope,
|
||||||
|
)
|
||||||
|
whenever(
|
||||||
|
mobileFactory.build(
|
||||||
|
eq(SUB_ID),
|
||||||
|
any(),
|
||||||
|
eq(DEFAULT_NAME),
|
||||||
|
eq(SEP),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.thenReturn(realRepo)
|
||||||
|
|
||||||
|
return realRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createRealCarrierMergedRepo(
|
||||||
|
wifiRepository: FakeWifiRepository,
|
||||||
|
): CarrierMergedConnectionRepository {
|
||||||
|
wifiRepository.setIsWifiEnabled(true)
|
||||||
|
wifiRepository.setIsWifiDefault(true)
|
||||||
|
val realRepo =
|
||||||
|
CarrierMergedConnectionRepository(
|
||||||
|
SUB_ID,
|
||||||
|
tableLogBuffer,
|
||||||
|
defaultNetworkName = NetworkNameModel.Default("default"),
|
||||||
|
testScope.backgroundScope,
|
||||||
|
wifiRepository,
|
||||||
|
)
|
||||||
|
whenever(carrierMergedFactory.build(eq(SUB_ID), any(), eq(DEFAULT_NAME)))
|
||||||
|
.thenReturn(realRepo)
|
||||||
|
|
||||||
|
return realRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dumpBuffer(): String {
|
||||||
|
val outputWriter = StringWriter()
|
||||||
|
tableLogBuffer.dump(PrintWriter(outputWriter), arrayOf())
|
||||||
|
return outputWriter.toString()
|
||||||
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val SUB_ID = 42
|
const val SUB_ID = 42
|
||||||
private val DEFAULT_NAME = NetworkNameModel.Default("default name")
|
private val DEFAULT_NAME = NetworkNameModel.Default("default name")
|
||||||
private const val SEP = "-"
|
private const val SEP = "-"
|
||||||
|
private const val BUFFER_SEPARATOR = "|"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
|||||||
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||||
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
||||||
import com.android.systemui.util.mockito.any
|
import com.android.systemui.util.mockito.any
|
||||||
import com.android.systemui.util.mockito.argumentCaptor
|
|
||||||
import com.android.systemui.util.mockito.mock
|
import com.android.systemui.util.mockito.mock
|
||||||
import com.android.systemui.util.mockito.whenever
|
import com.android.systemui.util.mockito.whenever
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
@@ -86,7 +85,6 @@ import org.junit.After
|
|||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito
|
|
||||||
import org.mockito.MockitoAnnotations
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||||
@@ -670,16 +668,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTelephonyCallbacks(): List<TelephonyCallback> {
|
|
||||||
val callbackCaptor = argumentCaptor<TelephonyCallback>()
|
|
||||||
Mockito.verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
|
|
||||||
return callbackCaptor.allValues
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun <reified T> getTelephonyCallbackForType(): T {
|
private inline fun <reified T> getTelephonyCallbackForType(): T {
|
||||||
val cbs = getTelephonyCallbacks().filterIsInstance<T>()
|
return MobileTelephonyHelpers.getTelephonyCallbackForType(telephonyManager)
|
||||||
assertThat(cbs.size).isEqualTo(1)
|
|
||||||
return cbs[0]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convenience constructor for SignalStrength */
|
/** Convenience constructor for SignalStrength */
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
@Mock private lateinit var subscriptionManager: SubscriptionManager
|
@Mock private lateinit var subscriptionManager: SubscriptionManager
|
||||||
@Mock private lateinit var telephonyManager: TelephonyManager
|
@Mock private lateinit var telephonyManager: TelephonyManager
|
||||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||||
|
@Mock private lateinit var summaryLogger: TableLogBuffer
|
||||||
@Mock private lateinit var logBufferFactory: TableLogBufferFactory
|
@Mock private lateinit var logBufferFactory: TableLogBufferFactory
|
||||||
|
|
||||||
private val mobileMappings = FakeMobileMappingsProxy()
|
private val mobileMappings = FakeMobileMappingsProxy()
|
||||||
@@ -157,6 +158,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
subscriptionManager,
|
subscriptionManager,
|
||||||
telephonyManager,
|
telephonyManager,
|
||||||
logger,
|
logger,
|
||||||
|
summaryLogger,
|
||||||
mobileMappings,
|
mobileMappings,
|
||||||
fakeBroadcastDispatcher,
|
fakeBroadcastDispatcher,
|
||||||
context,
|
context,
|
||||||
@@ -616,6 +618,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
subscriptionManager,
|
subscriptionManager,
|
||||||
telephonyManager,
|
telephonyManager,
|
||||||
logger,
|
logger,
|
||||||
|
summaryLogger,
|
||||||
mobileMappings,
|
mobileMappings,
|
||||||
fakeBroadcastDispatcher,
|
fakeBroadcastDispatcher,
|
||||||
context,
|
context,
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.statusbar.pipeline.mobile.data.repository.prod
|
||||||
|
|
||||||
|
import android.telephony.TelephonyCallback
|
||||||
|
import android.telephony.TelephonyManager
|
||||||
|
import com.android.systemui.util.mockito.any
|
||||||
|
import com.android.systemui.util.mockito.argumentCaptor
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
|
||||||
|
/** Helper methods for telephony-related callbacks for mobile tests. */
|
||||||
|
object MobileTelephonyHelpers {
|
||||||
|
fun getTelephonyCallbacks(mockTelephonyManager: TelephonyManager): List<TelephonyCallback> {
|
||||||
|
val callbackCaptor = argumentCaptor<TelephonyCallback>()
|
||||||
|
verify(mockTelephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
|
||||||
|
return callbackCaptor.allValues
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> getTelephonyCallbackForType(mockTelephonyManager: TelephonyManager): T {
|
||||||
|
val cbs = getTelephonyCallbacks(mockTelephonyManager).filterIsInstance<T>()
|
||||||
|
assertThat(cbs.size).isEqualTo(1)
|
||||||
|
return cbs[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,6 +71,8 @@ class FakeMobileIconInteractor(
|
|||||||
private val _numberOfLevels = MutableStateFlow(DEFAULT_NUM_LEVELS)
|
private val _numberOfLevels = MutableStateFlow(DEFAULT_NUM_LEVELS)
|
||||||
override val numberOfLevels = _numberOfLevels
|
override val numberOfLevels = _numberOfLevels
|
||||||
|
|
||||||
|
override val isForceHidden = MutableStateFlow(false)
|
||||||
|
|
||||||
fun setIconGroup(group: SignalIcon.MobileIconGroup) {
|
fun setIconGroup(group: SignalIcon.MobileIconGroup) {
|
||||||
_iconGroup.value = group
|
_iconGroup.value = group
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ class FakeMobileIconsInteractor(
|
|||||||
private val _isUserSetup = MutableStateFlow(true)
|
private val _isUserSetup = MutableStateFlow(true)
|
||||||
override val isUserSetup = _isUserSetup
|
override val isUserSetup = _isUserSetup
|
||||||
|
|
||||||
|
override val isForceHidden = MutableStateFlow(false)
|
||||||
|
|
||||||
/** Always returns a new fake interactor */
|
/** Always returns a new fake interactor */
|
||||||
override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor {
|
override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor {
|
||||||
return FakeMobileIconInteractor(tableLogBuffer)
|
return FakeMobileIconInteractor(tableLogBuffer)
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
|
|||||||
mobileIconsInteractor.defaultMobileIconGroup,
|
mobileIconsInteractor.defaultMobileIconGroup,
|
||||||
mobileIconsInteractor.defaultDataSubId,
|
mobileIconsInteractor.defaultDataSubId,
|
||||||
mobileIconsInteractor.isDefaultConnectionFailed,
|
mobileIconsInteractor.isDefaultConnectionFailed,
|
||||||
|
mobileIconsInteractor.isForceHidden,
|
||||||
connectionRepository,
|
connectionRepository,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -550,6 +551,21 @@ class MobileIconInteractorTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isForceHidden_matchesParent() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
var latest: Boolean? = null
|
||||||
|
val job = underTest.isForceHidden.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
mobileIconsInteractor.isForceHidden.value = true
|
||||||
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
|
mobileIconsInteractor.isForceHidden.value = false
|
||||||
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobile
|
|||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
||||||
|
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
|
||||||
|
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
|
||||||
import com.android.systemui.util.CarrierConfigTracker
|
import com.android.systemui.util.CarrierConfigTracker
|
||||||
import com.android.systemui.util.mockito.mock
|
import com.android.systemui.util.mockito.mock
|
||||||
import com.android.systemui.util.mockito.whenever
|
import com.android.systemui.util.mockito.whenever
|
||||||
@@ -50,6 +52,7 @@ import org.mockito.MockitoAnnotations
|
|||||||
@SmallTest
|
@SmallTest
|
||||||
class MobileIconsInteractorTest : SysuiTestCase() {
|
class MobileIconsInteractorTest : SysuiTestCase() {
|
||||||
private lateinit var underTest: MobileIconsInteractor
|
private lateinit var underTest: MobileIconsInteractor
|
||||||
|
private lateinit var connectivityRepository: FakeConnectivityRepository
|
||||||
private lateinit var connectionsRepository: FakeMobileConnectionsRepository
|
private lateinit var connectionsRepository: FakeMobileConnectionsRepository
|
||||||
private val userSetupRepository = FakeUserSetupRepository()
|
private val userSetupRepository = FakeUserSetupRepository()
|
||||||
private val mobileMappingsProxy = FakeMobileMappingsProxy()
|
private val mobileMappingsProxy = FakeMobileMappingsProxy()
|
||||||
@@ -63,6 +66,8 @@ class MobileIconsInteractorTest : SysuiTestCase() {
|
|||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
connectivityRepository = FakeConnectivityRepository()
|
||||||
|
|
||||||
connectionsRepository = FakeMobileConnectionsRepository(mobileMappingsProxy, tableLogBuffer)
|
connectionsRepository = FakeMobileConnectionsRepository(mobileMappingsProxy, tableLogBuffer)
|
||||||
connectionsRepository.setMobileConnectionRepositoryMap(
|
connectionsRepository.setMobileConnectionRepositoryMap(
|
||||||
mapOf(
|
mapOf(
|
||||||
@@ -79,6 +84,8 @@ class MobileIconsInteractorTest : SysuiTestCase() {
|
|||||||
connectionsRepository,
|
connectionsRepository,
|
||||||
carrierConfigTracker,
|
carrierConfigTracker,
|
||||||
logger = mock(),
|
logger = mock(),
|
||||||
|
tableLogger = mock(),
|
||||||
|
connectivityRepository,
|
||||||
userSetupRepository,
|
userSetupRepository,
|
||||||
testScope.backgroundScope,
|
testScope.backgroundScope,
|
||||||
)
|
)
|
||||||
@@ -609,6 +616,32 @@ class MobileIconsInteractorTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isForceHidden_repoHasMobileHidden_true() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Boolean? = null
|
||||||
|
val job = underTest.isForceHidden.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.MOBILE))
|
||||||
|
|
||||||
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isForceHidden_repoDoesNotHaveMobileHidden_false() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Boolean? = null
|
||||||
|
val job = underTest.isForceHidden.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
|
||||||
|
|
||||||
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val tableLogBuffer =
|
private val tableLogBuffer =
|
||||||
TableLogBuffer(8, "MobileIconsInteractorTest", FakeSystemClock())
|
TableLogBuffer(8, "MobileIconsInteractorTest", FakeSystemClock())
|
||||||
|
|||||||
@@ -29,12 +29,14 @@ import com.android.systemui.SysuiTestCase
|
|||||||
import com.android.systemui.log.table.TableLogBuffer
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
import com.android.systemui.statusbar.StatusBarIconView
|
import com.android.systemui.statusbar.StatusBarIconView
|
||||||
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
||||||
|
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
|
||||||
|
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
|
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
|
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel
|
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.QsMobileIconViewModel
|
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.QsMobileIconViewModel
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
|
||||||
import com.android.systemui.util.mockito.whenever
|
import com.android.systemui.util.mockito.whenever
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
@@ -58,31 +60,37 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
|
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
|
||||||
@Mock private lateinit var tableLogBuffer: TableLogBuffer
|
@Mock private lateinit var tableLogBuffer: TableLogBuffer
|
||||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
|
||||||
@Mock private lateinit var constants: ConnectivityConstants
|
@Mock private lateinit var constants: ConnectivityConstants
|
||||||
|
private lateinit var interactor: FakeMobileIconInteractor
|
||||||
|
private lateinit var airplaneModeRepository: FakeAirplaneModeRepository
|
||||||
|
private lateinit var airplaneModeInteractor: AirplaneModeInteractor
|
||||||
|
|
||||||
|
private lateinit var viewModelCommon: MobileIconViewModel
|
||||||
private lateinit var viewModel: LocationBasedMobileViewModel
|
private lateinit var viewModel: LocationBasedMobileViewModel
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
|
// This line was necessary to make the onDarkChanged and setStaticDrawableColor tests pass.
|
||||||
|
// But, it maybe *shouldn't* be necessary.
|
||||||
|
whenever(constants.hasDataCapabilities).thenReturn(true)
|
||||||
|
|
||||||
testableLooper = TestableLooper.get(this)
|
testableLooper = TestableLooper.get(this)
|
||||||
|
|
||||||
val interactor = FakeMobileIconInteractor(tableLogBuffer)
|
airplaneModeRepository = FakeAirplaneModeRepository()
|
||||||
|
airplaneModeInteractor =
|
||||||
val viewModelCommon =
|
AirplaneModeInteractor(
|
||||||
MobileIconViewModel(
|
airplaneModeRepository,
|
||||||
subscriptionId = 1,
|
FakeConnectivityRepository(),
|
||||||
interactor,
|
|
||||||
logger,
|
|
||||||
constants,
|
|
||||||
testScope.backgroundScope,
|
|
||||||
)
|
)
|
||||||
viewModel = QsMobileIconViewModel(viewModelCommon, statusBarPipelineFlags)
|
|
||||||
|
interactor = FakeMobileIconInteractor(tableLogBuffer)
|
||||||
|
createViewModel()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: The following tests are more like integration tests, since they stand up a full
|
// Note: The following tests are more like integration tests, since they stand up a full
|
||||||
// [WifiViewModel] and test the interactions between the view, view-binder, and view-model.
|
// [MobileIconViewModel] and test the interactions between the view, view-binder, and
|
||||||
|
// view-model.
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun setVisibleState_icon_iconShownDotHidden() {
|
fun setVisibleState_icon_iconShownDotHidden() {
|
||||||
@@ -130,7 +138,25 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun isIconVisible_alwaysTrue() {
|
fun isIconVisible_noData_outputsFalse() {
|
||||||
|
whenever(constants.hasDataCapabilities).thenReturn(false)
|
||||||
|
createViewModel()
|
||||||
|
|
||||||
|
val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||||
|
|
||||||
|
ViewUtils.attachView(view)
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
|
assertThat(view.isIconVisible).isFalse()
|
||||||
|
|
||||||
|
ViewUtils.detachView(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isIconVisible_hasData_outputsTrue() {
|
||||||
|
whenever(constants.hasDataCapabilities).thenReturn(true)
|
||||||
|
createViewModel()
|
||||||
|
|
||||||
val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
|
val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||||
|
|
||||||
ViewUtils.attachView(view)
|
ViewUtils.attachView(view)
|
||||||
@@ -141,6 +167,34 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() {
|
|||||||
ViewUtils.detachView(view)
|
ViewUtils.detachView(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isIconVisible_notAirplaneMode_outputsTrue() {
|
||||||
|
airplaneModeRepository.setIsAirplaneMode(false)
|
||||||
|
|
||||||
|
val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||||
|
|
||||||
|
ViewUtils.attachView(view)
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
|
assertThat(view.isIconVisible).isTrue()
|
||||||
|
|
||||||
|
ViewUtils.detachView(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isIconVisible_airplaneMode_outputsTrue() {
|
||||||
|
airplaneModeRepository.setIsAirplaneMode(true)
|
||||||
|
|
||||||
|
val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||||
|
|
||||||
|
ViewUtils.attachView(view)
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
|
assertThat(view.isIconVisible).isFalse()
|
||||||
|
|
||||||
|
ViewUtils.detachView(view)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun onDarkChanged_iconHasNewColor() {
|
fun onDarkChanged_iconHasNewColor() {
|
||||||
whenever(statusBarPipelineFlags.useDebugColoring()).thenReturn(false)
|
whenever(statusBarPipelineFlags.useDebugColoring()).thenReturn(false)
|
||||||
@@ -184,6 +238,18 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() {
|
|||||||
private fun View.getDotView(): View {
|
private fun View.getDotView(): View {
|
||||||
return this.requireViewById(R.id.status_bar_dot)
|
return this.requireViewById(R.id.status_bar_dot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createViewModel() {
|
||||||
|
viewModelCommon =
|
||||||
|
MobileIconViewModel(
|
||||||
|
subscriptionId = 1,
|
||||||
|
interactor,
|
||||||
|
airplaneModeInteractor,
|
||||||
|
constants,
|
||||||
|
testScope.backgroundScope,
|
||||||
|
)
|
||||||
|
viewModel = QsMobileIconViewModel(viewModelCommon, statusBarPipelineFlags)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val SLOT_NAME = "TestSlotName"
|
private const val SLOT_NAME = "TestSlotName"
|
||||||
|
|||||||
@@ -21,10 +21,13 @@ import com.android.settingslib.mobile.TelephonyIcons
|
|||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.log.table.TableLogBuffer
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
||||||
|
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
|
||||||
|
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
|
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModelTest.Companion.defaultSignal
|
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModelTest.Companion.defaultSignal
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
@@ -46,8 +49,8 @@ class LocationBasedMobileIconViewModelTest : SysuiTestCase() {
|
|||||||
private lateinit var qsIcon: QsMobileIconViewModel
|
private lateinit var qsIcon: QsMobileIconViewModel
|
||||||
private lateinit var keyguardIcon: KeyguardMobileIconViewModel
|
private lateinit var keyguardIcon: KeyguardMobileIconViewModel
|
||||||
private lateinit var interactor: FakeMobileIconInteractor
|
private lateinit var interactor: FakeMobileIconInteractor
|
||||||
|
private lateinit var airplaneModeInteractor: AirplaneModeInteractor
|
||||||
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
|
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
|
||||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
|
||||||
@Mock private lateinit var constants: ConnectivityConstants
|
@Mock private lateinit var constants: ConnectivityConstants
|
||||||
@Mock private lateinit var tableLogBuffer: TableLogBuffer
|
@Mock private lateinit var tableLogBuffer: TableLogBuffer
|
||||||
|
|
||||||
@@ -57,6 +60,11 @@ class LocationBasedMobileIconViewModelTest : SysuiTestCase() {
|
|||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
|
airplaneModeInteractor =
|
||||||
|
AirplaneModeInteractor(
|
||||||
|
FakeAirplaneModeRepository(),
|
||||||
|
FakeConnectivityRepository(),
|
||||||
|
)
|
||||||
interactor = FakeMobileIconInteractor(tableLogBuffer)
|
interactor = FakeMobileIconInteractor(tableLogBuffer)
|
||||||
interactor.apply {
|
interactor.apply {
|
||||||
setLevel(1)
|
setLevel(1)
|
||||||
@@ -68,7 +76,13 @@ class LocationBasedMobileIconViewModelTest : SysuiTestCase() {
|
|||||||
isDataConnected.value = true
|
isDataConnected.value = true
|
||||||
}
|
}
|
||||||
commonImpl =
|
commonImpl =
|
||||||
MobileIconViewModel(SUB_1_ID, interactor, logger, constants, testScope.backgroundScope)
|
MobileIconViewModel(
|
||||||
|
SUB_1_ID,
|
||||||
|
interactor,
|
||||||
|
airplaneModeInteractor,
|
||||||
|
constants,
|
||||||
|
testScope.backgroundScope,
|
||||||
|
)
|
||||||
|
|
||||||
homeIcon = HomeMobileIconViewModel(commonImpl, statusBarPipelineFlags)
|
homeIcon = HomeMobileIconViewModel(commonImpl, statusBarPipelineFlags)
|
||||||
qsIcon = QsMobileIconViewModel(commonImpl, statusBarPipelineFlags)
|
qsIcon = QsMobileIconViewModel(commonImpl, statusBarPipelineFlags)
|
||||||
@@ -78,14 +92,14 @@ class LocationBasedMobileIconViewModelTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun `location based view models receive same icon id when common impl updates`() =
|
fun `location based view models receive same icon id when common impl updates`() =
|
||||||
testScope.runTest {
|
testScope.runTest {
|
||||||
var latestHome: Int? = null
|
var latestHome: SignalIconModel? = null
|
||||||
val homeJob = homeIcon.iconId.onEach { latestHome = it }.launchIn(this)
|
val homeJob = homeIcon.icon.onEach { latestHome = it }.launchIn(this)
|
||||||
|
|
||||||
var latestQs: Int? = null
|
var latestQs: SignalIconModel? = null
|
||||||
val qsJob = qsIcon.iconId.onEach { latestQs = it }.launchIn(this)
|
val qsJob = qsIcon.icon.onEach { latestQs = it }.launchIn(this)
|
||||||
|
|
||||||
var latestKeyguard: Int? = null
|
var latestKeyguard: SignalIconModel? = null
|
||||||
val keyguardJob = keyguardIcon.iconId.onEach { latestKeyguard = it }.launchIn(this)
|
val keyguardJob = keyguardIcon.icon.onEach { latestKeyguard = it }.launchIn(this)
|
||||||
|
|
||||||
var expected = defaultSignal(level = 1)
|
var expected = defaultSignal(level = 1)
|
||||||
|
|
||||||
|
|||||||
@@ -19,16 +19,18 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
|
|||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.settingslib.AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH
|
import com.android.settingslib.AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH
|
||||||
import com.android.settingslib.AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH_NONE
|
import com.android.settingslib.AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH_NONE
|
||||||
import com.android.settingslib.graph.SignalDrawable
|
|
||||||
import com.android.settingslib.mobile.TelephonyIcons.THREE_G
|
import com.android.settingslib.mobile.TelephonyIcons.THREE_G
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.common.shared.model.ContentDescription
|
import com.android.systemui.common.shared.model.ContentDescription
|
||||||
import com.android.systemui.common.shared.model.Icon
|
import com.android.systemui.common.shared.model.Icon
|
||||||
import com.android.systemui.log.table.TableLogBuffer
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
|
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
|
||||||
|
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
|
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
|
||||||
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
|
||||||
import com.android.systemui.util.mockito.whenever
|
import com.android.systemui.util.mockito.whenever
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
@@ -49,7 +51,8 @@ import org.mockito.MockitoAnnotations
|
|||||||
class MobileIconViewModelTest : SysuiTestCase() {
|
class MobileIconViewModelTest : SysuiTestCase() {
|
||||||
private lateinit var underTest: MobileIconViewModel
|
private lateinit var underTest: MobileIconViewModel
|
||||||
private lateinit var interactor: FakeMobileIconInteractor
|
private lateinit var interactor: FakeMobileIconInteractor
|
||||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
private lateinit var airplaneModeRepository: FakeAirplaneModeRepository
|
||||||
|
private lateinit var airplaneModeInteractor: AirplaneModeInteractor
|
||||||
@Mock private lateinit var constants: ConnectivityConstants
|
@Mock private lateinit var constants: ConnectivityConstants
|
||||||
@Mock private lateinit var tableLogBuffer: TableLogBuffer
|
@Mock private lateinit var tableLogBuffer: TableLogBuffer
|
||||||
|
|
||||||
@@ -59,6 +62,15 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
|||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
|
whenever(constants.hasDataCapabilities).thenReturn(true)
|
||||||
|
|
||||||
|
airplaneModeRepository = FakeAirplaneModeRepository()
|
||||||
|
airplaneModeInteractor =
|
||||||
|
AirplaneModeInteractor(
|
||||||
|
airplaneModeRepository,
|
||||||
|
FakeConnectivityRepository(),
|
||||||
|
)
|
||||||
|
|
||||||
interactor = FakeMobileIconInteractor(tableLogBuffer)
|
interactor = FakeMobileIconInteractor(tableLogBuffer)
|
||||||
interactor.apply {
|
interactor.apply {
|
||||||
setLevel(1)
|
setLevel(1)
|
||||||
@@ -69,15 +81,94 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
|||||||
setNumberOfLevels(4)
|
setNumberOfLevels(4)
|
||||||
isDataConnected.value = true
|
isDataConnected.value = true
|
||||||
}
|
}
|
||||||
underTest =
|
createAndSetViewModel()
|
||||||
MobileIconViewModel(SUB_1_ID, interactor, logger, constants, testScope.backgroundScope)
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isVisible_notDataCapable_alwaysFalse() =
|
||||||
|
testScope.runTest {
|
||||||
|
// Create a new view model here so the constants are properly read
|
||||||
|
whenever(constants.hasDataCapabilities).thenReturn(false)
|
||||||
|
createAndSetViewModel()
|
||||||
|
|
||||||
|
var latest: Boolean? = null
|
||||||
|
val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isVisible_notAirplane_notForceHidden_true() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Boolean? = null
|
||||||
|
val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
airplaneModeRepository.setIsAirplaneMode(false)
|
||||||
|
interactor.isForceHidden.value = false
|
||||||
|
|
||||||
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isVisible_airplane_false() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Boolean? = null
|
||||||
|
val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
airplaneModeRepository.setIsAirplaneMode(true)
|
||||||
|
interactor.isForceHidden.value = false
|
||||||
|
|
||||||
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isVisible_forceHidden_false() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Boolean? = null
|
||||||
|
val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
airplaneModeRepository.setIsAirplaneMode(false)
|
||||||
|
interactor.isForceHidden.value = true
|
||||||
|
|
||||||
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isVisible_respondsToUpdates() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Boolean? = null
|
||||||
|
val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
airplaneModeRepository.setIsAirplaneMode(false)
|
||||||
|
interactor.isForceHidden.value = false
|
||||||
|
|
||||||
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
|
airplaneModeRepository.setIsAirplaneMode(true)
|
||||||
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
|
airplaneModeRepository.setIsAirplaneMode(false)
|
||||||
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
|
interactor.isForceHidden.value = true
|
||||||
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun iconId_correctLevel_notCutout() =
|
fun iconId_correctLevel_notCutout() =
|
||||||
testScope.runTest {
|
testScope.runTest {
|
||||||
var latest: Int? = null
|
var latest: SignalIconModel? = null
|
||||||
val job = underTest.iconId.onEach { latest = it }.launchIn(this)
|
val job = underTest.icon.onEach { latest = it }.launchIn(this)
|
||||||
val expected = defaultSignal()
|
val expected = defaultSignal()
|
||||||
|
|
||||||
assertThat(latest).isEqualTo(expected)
|
assertThat(latest).isEqualTo(expected)
|
||||||
@@ -90,8 +181,8 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
|||||||
testScope.runTest {
|
testScope.runTest {
|
||||||
interactor.setIsDefaultDataEnabled(false)
|
interactor.setIsDefaultDataEnabled(false)
|
||||||
|
|
||||||
var latest: Int? = null
|
var latest: SignalIconModel? = null
|
||||||
val job = underTest.iconId.onEach { latest = it }.launchIn(this)
|
val job = underTest.icon.onEach { latest = it }.launchIn(this)
|
||||||
val expected = defaultSignal(level = 1, connected = false)
|
val expected = defaultSignal(level = 1, connected = false)
|
||||||
|
|
||||||
assertThat(latest).isEqualTo(expected)
|
assertThat(latest).isEqualTo(expected)
|
||||||
@@ -102,8 +193,8 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun `icon - uses empty state - when not in service`() =
|
fun `icon - uses empty state - when not in service`() =
|
||||||
testScope.runTest {
|
testScope.runTest {
|
||||||
var latest: Int? = null
|
var latest: SignalIconModel? = null
|
||||||
val job = underTest.iconId.onEach { latest = it }.launchIn(this)
|
val job = underTest.icon.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
interactor.isInService.value = false
|
interactor.isInService.value = false
|
||||||
|
|
||||||
@@ -364,14 +455,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
|||||||
testScope.runTest {
|
testScope.runTest {
|
||||||
// Create a new view model here so the constants are properly read
|
// Create a new view model here so the constants are properly read
|
||||||
whenever(constants.shouldShowActivityConfig).thenReturn(false)
|
whenever(constants.shouldShowActivityConfig).thenReturn(false)
|
||||||
underTest =
|
createAndSetViewModel()
|
||||||
MobileIconViewModel(
|
|
||||||
SUB_1_ID,
|
|
||||||
interactor,
|
|
||||||
logger,
|
|
||||||
constants,
|
|
||||||
testScope.backgroundScope,
|
|
||||||
)
|
|
||||||
|
|
||||||
var inVisible: Boolean? = null
|
var inVisible: Boolean? = null
|
||||||
val inJob = underTest.activityInVisible.onEach { inVisible = it }.launchIn(this)
|
val inJob = underTest.activityInVisible.onEach { inVisible = it }.launchIn(this)
|
||||||
@@ -403,14 +487,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
|||||||
testScope.runTest {
|
testScope.runTest {
|
||||||
// Create a new view model here so the constants are properly read
|
// Create a new view model here so the constants are properly read
|
||||||
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
||||||
underTest =
|
createAndSetViewModel()
|
||||||
MobileIconViewModel(
|
|
||||||
SUB_1_ID,
|
|
||||||
interactor,
|
|
||||||
logger,
|
|
||||||
constants,
|
|
||||||
testScope.backgroundScope,
|
|
||||||
)
|
|
||||||
|
|
||||||
var inVisible: Boolean? = null
|
var inVisible: Boolean? = null
|
||||||
val inJob = underTest.activityInVisible.onEach { inVisible = it }.launchIn(this)
|
val inJob = underTest.activityInVisible.onEach { inVisible = it }.launchIn(this)
|
||||||
@@ -459,6 +536,16 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
|||||||
containerJob.cancel()
|
containerJob.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createAndSetViewModel() {
|
||||||
|
underTest = MobileIconViewModel(
|
||||||
|
SUB_1_ID,
|
||||||
|
interactor,
|
||||||
|
airplaneModeInteractor,
|
||||||
|
constants,
|
||||||
|
testScope.backgroundScope,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val SUB_1_ID = 1
|
private const val SUB_1_ID = 1
|
||||||
|
|
||||||
@@ -466,10 +553,11 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
|||||||
fun defaultSignal(
|
fun defaultSignal(
|
||||||
level: Int = 1,
|
level: Int = 1,
|
||||||
connected: Boolean = true,
|
connected: Boolean = true,
|
||||||
): Int {
|
): SignalIconModel {
|
||||||
return SignalDrawable.getState(level, /* numLevels */ 4, !connected)
|
return SignalIconModel(level, numberOfLevels = 4, showExclamationMark = !connected)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun emptySignal(): Int = SignalDrawable.getEmptyState(4)
|
fun emptySignal(): SignalIconModel =
|
||||||
|
SignalIconModel(level = 0, numberOfLevels = 4, showExclamationMark = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,14 @@ import androidx.test.filters.SmallTest
|
|||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.statusbar.phone.StatusBarLocation
|
import com.android.systemui.statusbar.phone.StatusBarLocation
|
||||||
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
||||||
|
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
|
||||||
|
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
|
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||||
|
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
|
||||||
import com.android.systemui.util.mockito.mock
|
import com.android.systemui.util.mockito.mock
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
@@ -46,6 +49,7 @@ class MobileIconsViewModelTest : SysuiTestCase() {
|
|||||||
private lateinit var underTest: MobileIconsViewModel
|
private lateinit var underTest: MobileIconsViewModel
|
||||||
private val interactor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
|
private val interactor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
|
||||||
|
|
||||||
|
private lateinit var airplaneModeInteractor: AirplaneModeInteractor
|
||||||
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
|
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
|
||||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||||
@Mock private lateinit var constants: ConnectivityConstants
|
@Mock private lateinit var constants: ConnectivityConstants
|
||||||
@@ -57,6 +61,12 @@ class MobileIconsViewModelTest : SysuiTestCase() {
|
|||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
airplaneModeInteractor =
|
||||||
|
AirplaneModeInteractor(
|
||||||
|
FakeAirplaneModeRepository(),
|
||||||
|
FakeConnectivityRepository(),
|
||||||
|
)
|
||||||
|
|
||||||
val subscriptionIdsFlow =
|
val subscriptionIdsFlow =
|
||||||
interactor.filteredSubscriptions
|
interactor.filteredSubscriptions
|
||||||
.map { subs -> subs.map { it.subscriptionId } }
|
.map { subs -> subs.map { it.subscriptionId } }
|
||||||
@@ -66,6 +76,7 @@ class MobileIconsViewModelTest : SysuiTestCase() {
|
|||||||
MobileIconsViewModel(
|
MobileIconsViewModel(
|
||||||
subscriptionIdsFlow,
|
subscriptionIdsFlow,
|
||||||
interactor,
|
interactor,
|
||||||
|
airplaneModeInteractor,
|
||||||
logger,
|
logger,
|
||||||
constants,
|
constants,
|
||||||
testScope.backgroundScope,
|
testScope.backgroundScope,
|
||||||
|
|||||||
Reference in New Issue
Block a user