Merge changes from topic "wifi-constants" into tm-qpr-dev
* changes: [Sb refactor] Mobile icon view model logging [Sb refactor] Add logging to mobile connections pipeline [Sb refactor] Move shouldShowActivityConfig to ConnectivityConstants [Sb refactor] Add location to mobile view models
This commit is contained in:
committed by
Android (Google) Code Review
commit
5bba501a33
@@ -60,10 +60,12 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da
|
||||
private int mColor;
|
||||
|
||||
private final MobileIconsViewModel mMobileIconsViewModel;
|
||||
private final StatusBarLocation mLocation;
|
||||
|
||||
public DemoStatusIcons(
|
||||
LinearLayout statusIcons,
|
||||
MobileIconsViewModel mobileIconsViewModel,
|
||||
StatusBarLocation location,
|
||||
int iconSize
|
||||
) {
|
||||
super(statusIcons.getContext());
|
||||
@@ -71,6 +73,7 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da
|
||||
mIconSize = iconSize;
|
||||
mColor = DarkIconDispatcher.DEFAULT_ICON_TINT;
|
||||
mMobileIconsViewModel = mobileIconsViewModel;
|
||||
mLocation = location;
|
||||
|
||||
if (statusIcons instanceof StatusIconContainer) {
|
||||
setShouldRestrictIcons(((StatusIconContainer) statusIcons).isRestrictingIcons());
|
||||
@@ -287,7 +290,7 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da
|
||||
ModernStatusBarMobileView view = ModernStatusBarMobileView.constructAndBind(
|
||||
mobileContext,
|
||||
"mobile",
|
||||
mMobileIconsViewModel.viewModelForSub(subId)
|
||||
mMobileIconsViewModel.viewModelForSub(subId, mLocation)
|
||||
);
|
||||
|
||||
// mobile always goes at the end
|
||||
|
||||
@@ -359,6 +359,7 @@ public interface StatusBarIconController {
|
||||
// Whether or not these icons show up in dumpsys
|
||||
protected boolean mShouldLog = false;
|
||||
private StatusBarIconController mController;
|
||||
private final StatusBarLocation mLocation;
|
||||
|
||||
// Enables SystemUI demo mode to take effect in this group
|
||||
protected boolean mDemoable = true;
|
||||
@@ -381,11 +382,12 @@ public interface StatusBarIconController {
|
||||
mContext = group.getContext();
|
||||
mIconSize = mContext.getResources().getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.status_bar_icon_size);
|
||||
mLocation = location;
|
||||
|
||||
if (statusBarPipelineFlags.runNewMobileIconsBackend()) {
|
||||
// This starts the flow for the new pipeline, and will notify us of changes if
|
||||
// {@link StatusBarPipelineFlags#useNewMobileIcons} is also true.
|
||||
mMobileIconsViewModel = mobileUiAdapter.createMobileIconsViewModel();
|
||||
mMobileIconsViewModel = mobileUiAdapter.getMobileIconsViewModel();
|
||||
MobileIconsBinder.bind(mGroup, mMobileIconsViewModel);
|
||||
} else {
|
||||
mMobileIconsViewModel = null;
|
||||
@@ -394,7 +396,7 @@ public interface StatusBarIconController {
|
||||
if (statusBarPipelineFlags.runNewWifiIconBackend()) {
|
||||
// This starts the flow for the new pipeline, and will notify us of changes if
|
||||
// {@link StatusBarPipelineFlags#useNewWifiIcon} is also true.
|
||||
mWifiViewModel = wifiUiAdapter.bindGroup(mGroup, location);
|
||||
mWifiViewModel = wifiUiAdapter.bindGroup(mGroup, mLocation);
|
||||
} else {
|
||||
mWifiViewModel = null;
|
||||
}
|
||||
@@ -569,7 +571,7 @@ public interface StatusBarIconController {
|
||||
.constructAndBind(
|
||||
mobileContext,
|
||||
slot,
|
||||
mMobileIconsViewModel.viewModelForSub(subId)
|
||||
mMobileIconsViewModel.viewModelForSub(subId, mLocation)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -705,7 +707,12 @@ public interface StatusBarIconController {
|
||||
}
|
||||
|
||||
protected DemoStatusIcons createDemoStatusIcons() {
|
||||
return new DemoStatusIcons((LinearLayout) mGroup, mMobileIconsViewModel, mIconSize);
|
||||
return new DemoStatusIcons(
|
||||
(LinearLayout) mGroup,
|
||||
mMobileIconsViewModel,
|
||||
mLocation,
|
||||
mIconSize
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ import android.telephony.TelephonyCallback.ServiceStateListener
|
||||
import android.telephony.TelephonyCallback.SignalStrengthsListener
|
||||
import android.telephony.TelephonyDisplayInfo
|
||||
import android.telephony.TelephonyManager
|
||||
import com.android.systemui.log.table.Diffable
|
||||
import com.android.systemui.log.table.TableRowLogger
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Disconnected
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||
|
||||
@@ -79,4 +81,72 @@ data class MobileConnectionModel(
|
||||
* [TelephonyDisplayInfo.getNetworkType]. This is used to look up the proper network type icon
|
||||
*/
|
||||
val resolvedNetworkType: ResolvedNetworkType = ResolvedNetworkType.UnknownNetworkType,
|
||||
)
|
||||
) : Diffable<MobileConnectionModel> {
|
||||
override fun logDiffs(prevVal: MobileConnectionModel, row: TableRowLogger) {
|
||||
if (prevVal.dataConnectionState != dataConnectionState) {
|
||||
row.logChange(COL_CONNECTION_STATE, dataConnectionState.toString())
|
||||
}
|
||||
|
||||
if (prevVal.isEmergencyOnly != isEmergencyOnly) {
|
||||
row.logChange(COL_EMERGENCY, isEmergencyOnly)
|
||||
}
|
||||
|
||||
if (prevVal.isRoaming != isRoaming) {
|
||||
row.logChange(COL_ROAMING, isRoaming)
|
||||
}
|
||||
|
||||
if (prevVal.operatorAlphaShort != operatorAlphaShort) {
|
||||
row.logChange(COL_OPERATOR, operatorAlphaShort)
|
||||
}
|
||||
|
||||
if (prevVal.isGsm != isGsm) {
|
||||
row.logChange(COL_IS_GSM, isGsm)
|
||||
}
|
||||
|
||||
if (prevVal.cdmaLevel != cdmaLevel) {
|
||||
row.logChange(COL_CDMA_LEVEL, cdmaLevel)
|
||||
}
|
||||
|
||||
if (prevVal.primaryLevel != primaryLevel) {
|
||||
row.logChange(COL_PRIMARY_LEVEL, primaryLevel)
|
||||
}
|
||||
|
||||
if (prevVal.dataActivityDirection != dataActivityDirection) {
|
||||
row.logChange(COL_ACTIVITY_DIRECTION, dataActivityDirection.toString())
|
||||
}
|
||||
|
||||
if (prevVal.carrierNetworkChangeActive != carrierNetworkChangeActive) {
|
||||
row.logChange(COL_CARRIER_NETWORK_CHANGE, carrierNetworkChangeActive)
|
||||
}
|
||||
|
||||
if (prevVal.resolvedNetworkType != resolvedNetworkType) {
|
||||
row.logChange(COL_RESOLVED_NETWORK_TYPE, resolvedNetworkType.toString())
|
||||
}
|
||||
}
|
||||
|
||||
override fun logFull(row: TableRowLogger) {
|
||||
row.logChange(COL_CONNECTION_STATE, dataConnectionState.toString())
|
||||
row.logChange(COL_EMERGENCY, isEmergencyOnly)
|
||||
row.logChange(COL_ROAMING, isRoaming)
|
||||
row.logChange(COL_OPERATOR, operatorAlphaShort)
|
||||
row.logChange(COL_IS_GSM, isGsm)
|
||||
row.logChange(COL_CDMA_LEVEL, cdmaLevel)
|
||||
row.logChange(COL_PRIMARY_LEVEL, primaryLevel)
|
||||
row.logChange(COL_ACTIVITY_DIRECTION, dataActivityDirection.toString())
|
||||
row.logChange(COL_CARRIER_NETWORK_CHANGE, carrierNetworkChangeActive)
|
||||
row.logChange(COL_RESOLVED_NETWORK_TYPE, resolvedNetworkType.toString())
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val COL_EMERGENCY = "EmergencyOnly"
|
||||
const val COL_ROAMING = "Roaming"
|
||||
const val COL_OPERATOR = "OperatorName"
|
||||
const val COL_IS_GSM = "IsGsm"
|
||||
const val COL_CDMA_LEVEL = "CdmaLevel"
|
||||
const val COL_PRIMARY_LEVEL = "PrimaryLevel"
|
||||
const val COL_CONNECTION_STATE = "ConnectionState"
|
||||
const val COL_ACTIVITY_DIRECTION = "DataActivity"
|
||||
const val COL_CARRIER_NETWORK_CHANGE = "CarrierNetworkChangeActive"
|
||||
const val COL_RESOLVED_NETWORK_TYPE = "NetworkType"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,22 +21,48 @@ import android.telephony.TelephonyManager.EXTRA_DATA_SPN
|
||||
import android.telephony.TelephonyManager.EXTRA_PLMN
|
||||
import android.telephony.TelephonyManager.EXTRA_SHOW_PLMN
|
||||
import android.telephony.TelephonyManager.EXTRA_SHOW_SPN
|
||||
import com.android.systemui.log.table.Diffable
|
||||
import com.android.systemui.log.table.TableRowLogger
|
||||
|
||||
/**
|
||||
* Encapsulates the data needed to show a network name for a mobile network. The data is parsed from
|
||||
* the intent sent by [android.telephony.TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED].
|
||||
*/
|
||||
sealed interface NetworkNameModel {
|
||||
sealed interface NetworkNameModel : Diffable<NetworkNameModel> {
|
||||
val name: String
|
||||
|
||||
/** The default name is read from [com.android.internal.R.string.lockscreen_carrier_default] */
|
||||
data class Default(override val name: String) : NetworkNameModel
|
||||
data class Default(override val name: String) : NetworkNameModel {
|
||||
override fun logDiffs(prevVal: NetworkNameModel, row: TableRowLogger) {
|
||||
if (prevVal !is Default || prevVal.name != name) {
|
||||
row.logChange(COL_NETWORK_NAME, "Default($name)")
|
||||
}
|
||||
}
|
||||
|
||||
override fun logFull(row: TableRowLogger) {
|
||||
row.logChange(COL_NETWORK_NAME, "Default($name)")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This name has been derived from telephony intents. see
|
||||
* [android.telephony.TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED]
|
||||
*/
|
||||
data class Derived(override val name: String) : NetworkNameModel
|
||||
data class Derived(override val name: String) : NetworkNameModel {
|
||||
override fun logDiffs(prevVal: NetworkNameModel, row: TableRowLogger) {
|
||||
if (prevVal !is Derived || prevVal.name != name) {
|
||||
row.logChange(COL_NETWORK_NAME, "Derived($name)")
|
||||
}
|
||||
}
|
||||
|
||||
override fun logFull(row: TableRowLogger) {
|
||||
row.logChange(COL_NETWORK_NAME, "Derived($name)")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val COL_NETWORK_NAME = "networkName"
|
||||
}
|
||||
}
|
||||
|
||||
fun Intent.toNetworkNameModel(separator: String): NetworkNameModel? {
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.telephony.SubscriptionInfo
|
||||
import android.telephony.SubscriptionManager
|
||||
import android.telephony.TelephonyCallback
|
||||
import android.telephony.TelephonyManager
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -39,6 +40,13 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
interface MobileConnectionRepository {
|
||||
/** The subscriptionId that this connection represents */
|
||||
val subId: Int
|
||||
|
||||
/**
|
||||
* The table log buffer created for this connection. Will have the name "MobileConnectionLog
|
||||
* [subId]"
|
||||
*/
|
||||
val tableLogBuffer: TableLogBuffer
|
||||
|
||||
/**
|
||||
* A flow that aggregates all necessary callbacks from [TelephonyCallback] into a single
|
||||
* listener + model.
|
||||
|
||||
@@ -24,6 +24,8 @@ import com.android.settingslib.SignalIcon
|
||||
import com.android.settingslib.mobile.MobileMappings
|
||||
import com.android.settingslib.mobile.TelephonyIcons
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.log.table.TableLogBufferFactory
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
|
||||
@@ -60,6 +62,7 @@ constructor(
|
||||
private val dataSource: DemoModeMobileConnectionDataSource,
|
||||
@Application private val scope: CoroutineScope,
|
||||
context: Context,
|
||||
private val logFactory: TableLogBufferFactory,
|
||||
) : MobileConnectionsRepository {
|
||||
|
||||
private var demoCommandJob: Job? = null
|
||||
@@ -149,7 +152,16 @@ constructor(
|
||||
|
||||
override fun getRepoForSubId(subId: Int): DemoMobileConnectionRepository {
|
||||
return connectionRepoCache[subId]
|
||||
?: DemoMobileConnectionRepository(subId).also { connectionRepoCache[subId] = it }
|
||||
?: createDemoMobileConnectionRepo(subId).also { connectionRepoCache[subId] = it }
|
||||
}
|
||||
|
||||
private fun createDemoMobileConnectionRepo(subId: Int): DemoMobileConnectionRepository {
|
||||
val tableLogBuffer = logFactory.create("DemoMobileConnectionLog [$subId]", 100)
|
||||
|
||||
return DemoMobileConnectionRepository(
|
||||
subId,
|
||||
tableLogBuffer,
|
||||
)
|
||||
}
|
||||
|
||||
override val globalMobileDataSettingChangedEvent = MutableStateFlow(Unit)
|
||||
@@ -260,7 +272,10 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
class DemoMobileConnectionRepository(override val subId: Int) : MobileConnectionRepository {
|
||||
class DemoMobileConnectionRepository(
|
||||
override val subId: Int,
|
||||
override val tableLogBuffer: TableLogBuffer,
|
||||
) : MobileConnectionRepository {
|
||||
override val connectionInfo = MutableStateFlow(MobileConnectionModel())
|
||||
|
||||
override val dataEnabled = MutableStateFlow(true)
|
||||
|
||||
@@ -36,6 +36,9 @@ import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.log.table.TableLogBufferFactory
|
||||
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.NetworkNameModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
|
||||
@@ -46,7 +49,6 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameMo
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
|
||||
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
||||
import com.android.systemui.util.settings.GlobalSettings
|
||||
import javax.inject.Inject
|
||||
@@ -59,6 +61,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.merge
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@@ -79,6 +82,7 @@ class MobileConnectionRepositoryImpl(
|
||||
mobileMappingsProxy: MobileMappingsProxy,
|
||||
bgDispatcher: CoroutineDispatcher,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
mobileLogger: TableLogBuffer,
|
||||
scope: CoroutineScope,
|
||||
) : MobileConnectionRepository {
|
||||
init {
|
||||
@@ -92,10 +96,11 @@ class MobileConnectionRepositoryImpl(
|
||||
|
||||
private val telephonyCallbackEvent = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
|
||||
|
||||
override val tableLogBuffer: TableLogBuffer = mobileLogger
|
||||
|
||||
override val connectionInfo: StateFlow<MobileConnectionModel> = run {
|
||||
var state = MobileConnectionModel()
|
||||
conflatedCallbackFlow {
|
||||
// TODO (b/240569788): log all of these into the connectivity logger
|
||||
val callback =
|
||||
object :
|
||||
TelephonyCallback(),
|
||||
@@ -106,6 +111,7 @@ class MobileConnectionRepositoryImpl(
|
||||
TelephonyCallback.CarrierNetworkListener,
|
||||
TelephonyCallback.DisplayInfoListener {
|
||||
override fun onServiceStateChanged(serviceState: ServiceState) {
|
||||
logger.logOnServiceStateChanged(serviceState, subId)
|
||||
state =
|
||||
state.copy(
|
||||
isEmergencyOnly = serviceState.isEmergencyOnly,
|
||||
@@ -116,6 +122,7 @@ class MobileConnectionRepositoryImpl(
|
||||
}
|
||||
|
||||
override fun onSignalStrengthsChanged(signalStrength: SignalStrength) {
|
||||
logger.logOnSignalStrengthsChanged(signalStrength, subId)
|
||||
val cdmaLevel =
|
||||
signalStrength
|
||||
.getCellSignalStrengths(CellSignalStrengthCdma::class.java)
|
||||
@@ -142,12 +149,14 @@ class MobileConnectionRepositoryImpl(
|
||||
dataState: Int,
|
||||
networkType: Int
|
||||
) {
|
||||
logger.logOnDataConnectionStateChanged(dataState, networkType, subId)
|
||||
state =
|
||||
state.copy(dataConnectionState = dataState.toDataConnectionType())
|
||||
trySend(state)
|
||||
}
|
||||
|
||||
override fun onDataActivity(direction: Int) {
|
||||
logger.logOnDataActivity(direction, subId)
|
||||
state =
|
||||
state.copy(
|
||||
dataActivityDirection = direction.toMobileDataActivityModel()
|
||||
@@ -156,6 +165,7 @@ class MobileConnectionRepositoryImpl(
|
||||
}
|
||||
|
||||
override fun onCarrierNetworkChange(active: Boolean) {
|
||||
logger.logOnCarrierNetworkChange(active, subId)
|
||||
state = state.copy(carrierNetworkChangeActive = active)
|
||||
trySend(state)
|
||||
}
|
||||
@@ -163,6 +173,7 @@ class MobileConnectionRepositoryImpl(
|
||||
override fun onDisplayInfoChanged(
|
||||
telephonyDisplayInfo: TelephonyDisplayInfo
|
||||
) {
|
||||
logger.logOnDisplayInfoChanged(telephonyDisplayInfo, subId)
|
||||
|
||||
val networkType =
|
||||
if (telephonyDisplayInfo.networkType == NETWORK_TYPE_UNKNOWN) {
|
||||
@@ -193,7 +204,11 @@ class MobileConnectionRepositoryImpl(
|
||||
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
|
||||
}
|
||||
.onEach { telephonyCallbackEvent.tryEmit(Unit) }
|
||||
.logOutputChange(logger, "MobileSubscriptionModel")
|
||||
.logDiffsForTable(
|
||||
mobileLogger,
|
||||
columnPrefix = "MobileConnection ($subId)",
|
||||
initialValue = state,
|
||||
)
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), state)
|
||||
}
|
||||
|
||||
@@ -243,19 +258,43 @@ class MobileConnectionRepositoryImpl(
|
||||
intent.toNetworkNameModel(networkNameSeparator) ?: defaultNetworkName
|
||||
}
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.logDiffsForTable(
|
||||
mobileLogger,
|
||||
columnPrefix = "",
|
||||
initialValue = defaultNetworkName,
|
||||
)
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
|
||||
|
||||
override val dataEnabled: StateFlow<Boolean> =
|
||||
override val dataEnabled: StateFlow<Boolean> = run {
|
||||
val initial = dataConnectionAllowed()
|
||||
telephonyPollingEvent
|
||||
.mapLatest { dataConnectionAllowed() }
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), dataConnectionAllowed())
|
||||
.distinctUntilChanged()
|
||||
.logDiffsForTable(
|
||||
mobileLogger,
|
||||
columnPrefix = "",
|
||||
columnName = "dataEnabled",
|
||||
initialValue = initial,
|
||||
)
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
|
||||
}
|
||||
|
||||
private fun dataConnectionAllowed(): Boolean = telephonyManager.isDataConnectionAllowed
|
||||
|
||||
override val isDefaultDataSubscription: StateFlow<Boolean> =
|
||||
override val isDefaultDataSubscription: StateFlow<Boolean> = run {
|
||||
val initialValue = defaultDataSubId.value == subId
|
||||
defaultDataSubId
|
||||
.mapLatest { it == subId }
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultDataSubId.value == subId)
|
||||
.distinctUntilChanged()
|
||||
.logDiffsForTable(
|
||||
mobileLogger,
|
||||
columnPrefix = "",
|
||||
columnName = "isDefaultDataSub",
|
||||
initialValue = initialValue,
|
||||
)
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), initialValue)
|
||||
}
|
||||
|
||||
class Factory
|
||||
@Inject
|
||||
@@ -266,6 +305,7 @@ class MobileConnectionRepositoryImpl(
|
||||
private val logger: ConnectivityPipelineLogger,
|
||||
private val globalSettings: GlobalSettings,
|
||||
private val mobileMappingsProxy: MobileMappingsProxy,
|
||||
private val logFactory: TableLogBufferFactory,
|
||||
@Background private val bgDispatcher: CoroutineDispatcher,
|
||||
@Application private val scope: CoroutineScope,
|
||||
) {
|
||||
@@ -276,6 +316,8 @@ class MobileConnectionRepositoryImpl(
|
||||
defaultDataSubId: StateFlow<Int>,
|
||||
globalMobileDataSettingChangedEvent: Flow<Unit>,
|
||||
): MobileConnectionRepository {
|
||||
val mobileLogger = logFactory.create(tableBufferLogName(subId), 100)
|
||||
|
||||
return MobileConnectionRepositoryImpl(
|
||||
context,
|
||||
subId,
|
||||
@@ -289,8 +331,13 @@ class MobileConnectionRepositoryImpl(
|
||||
mobileMappingsProxy,
|
||||
bgDispatcher,
|
||||
logger,
|
||||
mobileLogger,
|
||||
scope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun tableBufferLogName(subId: Int): String = "MobileConnectionLog [$subId]"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConn
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
|
||||
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
|
||||
import com.android.systemui.util.settings.GlobalSettings
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
@@ -120,6 +121,7 @@ constructor(
|
||||
awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(callback) }
|
||||
}
|
||||
.mapLatest { fetchSubscriptionsList().map { it.toSubscriptionModel() } }
|
||||
.logInputChange(logger, "onSubscriptionsChanged")
|
||||
.onEach { infos -> dropUnusedReposFromCache(infos) }
|
||||
.stateIn(scope, started = SharingStarted.WhileSubscribed(), listOf())
|
||||
|
||||
@@ -136,6 +138,8 @@ constructor(
|
||||
telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
|
||||
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.logInputChange(logger, "onActiveDataSubscriptionIdChanged")
|
||||
.stateIn(scope, started = SharingStarted.WhileSubscribed(), INVALID_SUBSCRIPTION_ID)
|
||||
|
||||
private val defaultDataSubIdChangeEvent: MutableSharedFlow<Unit> =
|
||||
@@ -149,6 +153,7 @@ constructor(
|
||||
intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.logInputChange(logger, "ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED")
|
||||
.onEach { defaultDataSubIdChangeEvent.tryEmit(Unit) }
|
||||
.stateIn(
|
||||
scope,
|
||||
@@ -157,13 +162,15 @@ constructor(
|
||||
)
|
||||
|
||||
private val carrierConfigChangedEvent =
|
||||
broadcastDispatcher.broadcastFlow(
|
||||
IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)
|
||||
)
|
||||
broadcastDispatcher
|
||||
.broadcastFlow(IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED))
|
||||
.logInputChange(logger, "ACTION_CARRIER_CONFIG_CHANGED")
|
||||
|
||||
override val defaultDataSubRatConfig: StateFlow<Config> =
|
||||
merge(defaultDataSubIdChangeEvent, carrierConfigChangedEvent)
|
||||
.mapLatest { Config.readConfig(context) }
|
||||
.distinctUntilChanged()
|
||||
.logInputChange(logger, "defaultDataSubRatConfig")
|
||||
.stateIn(
|
||||
scope,
|
||||
SharingStarted.WhileSubscribed(),
|
||||
@@ -171,10 +178,16 @@ constructor(
|
||||
)
|
||||
|
||||
override val defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>> =
|
||||
defaultDataSubRatConfig.map { mobileMappingsProxy.mapIconSets(it) }
|
||||
defaultDataSubRatConfig
|
||||
.map { mobileMappingsProxy.mapIconSets(it) }
|
||||
.distinctUntilChanged()
|
||||
.logInputChange(logger, "defaultMobileIconMapping")
|
||||
|
||||
override val defaultMobileIconGroup: Flow<MobileIconGroup> =
|
||||
defaultDataSubRatConfig.map { mobileMappingsProxy.getDefaultIcons(it) }
|
||||
defaultDataSubRatConfig
|
||||
.map { mobileMappingsProxy.getDefaultIcons(it) }
|
||||
.distinctUntilChanged()
|
||||
.logInputChange(logger, "defaultMobileIconGroup")
|
||||
|
||||
override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
|
||||
if (!isValidSubId(subId)) {
|
||||
@@ -191,22 +204,24 @@ constructor(
|
||||
* In single-SIM devices, the [MOBILE_DATA] setting is phone-wide. For multi-SIM, the individual
|
||||
* connection repositories also observe the URI for [MOBILE_DATA] + subId.
|
||||
*/
|
||||
override val globalMobileDataSettingChangedEvent: Flow<Unit> = conflatedCallbackFlow {
|
||||
val observer =
|
||||
object : ContentObserver(null) {
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
trySend(Unit)
|
||||
}
|
||||
override val globalMobileDataSettingChangedEvent: Flow<Unit> =
|
||||
conflatedCallbackFlow {
|
||||
val observer =
|
||||
object : ContentObserver(null) {
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
trySend(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
globalSettings.registerContentObserver(
|
||||
globalSettings.getUriFor(MOBILE_DATA),
|
||||
true,
|
||||
observer
|
||||
)
|
||||
|
||||
awaitClose { context.contentResolver.unregisterContentObserver(observer) }
|
||||
}
|
||||
|
||||
globalSettings.registerContentObserver(
|
||||
globalSettings.getUriFor(MOBILE_DATA),
|
||||
true,
|
||||
observer
|
||||
)
|
||||
|
||||
awaitClose { context.contentResolver.unregisterContentObserver(observer) }
|
||||
}
|
||||
.logInputChange(logger, "globalMobileDataSettingChangedEvent")
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
override val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel> =
|
||||
@@ -236,6 +251,8 @@ constructor(
|
||||
|
||||
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.logInputChange(logger, "defaultMobileNetworkConnectivity")
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectivityModel())
|
||||
|
||||
private fun isValidSubId(subId: Int): Boolean {
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
|
||||
import android.telephony.CarrierConfigManager
|
||||
import com.android.settingslib.SignalIcon.MobileIconGroup
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Connected
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
|
||||
@@ -35,6 +36,9 @@ import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
interface MobileIconInteractor {
|
||||
/** The table log created for this connection */
|
||||
val tableLogBuffer: TableLogBuffer
|
||||
|
||||
/** The current mobile data activity */
|
||||
val activity: Flow<DataActivityModel>
|
||||
|
||||
@@ -97,6 +101,8 @@ class MobileIconInteractorImpl(
|
||||
) : MobileIconInteractor {
|
||||
private val connectionInfo = connectionRepository.connectionInfo
|
||||
|
||||
override val tableLogBuffer: TableLogBuffer = connectionRepository.tableLogBuffer
|
||||
|
||||
override val activity = connectionInfo.mapLatest { it.dataActivityDirection }
|
||||
|
||||
override val isDataEnabled: StateFlow<Boolean> = connectionRepository.dataEnabled
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.android.systemui.CoreStartable
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.statusbar.phone.StatusBarIconController
|
||||
import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager
|
||||
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
|
||||
@@ -70,6 +69,9 @@ constructor(
|
||||
private val mobileSubIdsState: StateFlow<List<Int>> =
|
||||
mobileSubIds.stateIn(scope, SharingStarted.WhileSubscribed(), listOf())
|
||||
|
||||
/** In order to keep the logs tame, we will reuse the same top-level mobile icons view model */
|
||||
val mobileIconsViewModel = iconsViewModelFactory.create(mobileSubIdsState)
|
||||
|
||||
override fun start() {
|
||||
// Only notify the icon controller if we want to *render* the new icons.
|
||||
// Note that this flow may still run if
|
||||
@@ -81,12 +83,4 @@ constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a MobileIconsViewModel for a given [IconManager], and bind it to to the manager's
|
||||
* lifecycle. This will start collecting on [mobileSubIdsState] and link our new pipeline with
|
||||
* the old view system.
|
||||
*/
|
||||
fun createMobileIconsViewModel(): MobileIconsViewModel =
|
||||
iconsViewModelFactory.create(mobileSubIdsState)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import com.android.settingslib.graph.SignalDrawable
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.common.ui.binder.IconViewBinder
|
||||
import com.android.systemui.lifecycle.repeatWhenAttached
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -39,7 +39,7 @@ object MobileIconBinder {
|
||||
@JvmStatic
|
||||
fun bind(
|
||||
view: ViewGroup,
|
||||
viewModel: MobileIconViewModel,
|
||||
viewModel: LocationBasedMobileViewModel,
|
||||
) {
|
||||
val activityContainer = view.requireViewById<View>(R.id.inout_container)
|
||||
val activityIn = view.requireViewById<ImageView>(R.id.mobile_in)
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.android.systemui.R
|
||||
import com.android.systemui.statusbar.BaseStatusBarFrameLayout
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconBinder
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
|
||||
import java.util.ArrayList
|
||||
|
||||
class ModernStatusBarMobileView(
|
||||
@@ -71,7 +71,7 @@ class ModernStatusBarMobileView(
|
||||
fun constructAndBind(
|
||||
context: Context,
|
||||
slot: String,
|
||||
viewModel: MobileIconViewModel,
|
||||
viewModel: LocationBasedMobileViewModel,
|
||||
): ModernStatusBarMobileView {
|
||||
return (LayoutInflater.from(context)
|
||||
.inflate(R.layout.status_bar_mobile_signal_group_new, null)
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.viewmodel
|
||||
|
||||
import android.graphics.Color
|
||||
import com.android.systemui.statusbar.phone.StatusBarLocation
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
/**
|
||||
* A view model for an individual mobile icon that embeds the notion of a [StatusBarLocation]. This
|
||||
* allows the mobile icon to change some view parameters at different locations
|
||||
*
|
||||
* @param commonImpl for convenience, this class wraps a base interface that can provides all of the
|
||||
* common implementations between locations. See [MobileIconViewModel]
|
||||
*/
|
||||
abstract class LocationBasedMobileViewModel(
|
||||
val commonImpl: MobileIconViewModelCommon,
|
||||
val logger: ConnectivityPipelineLogger,
|
||||
) : MobileIconViewModelCommon by commonImpl {
|
||||
abstract val tint: Flow<Int>
|
||||
|
||||
companion object {
|
||||
fun viewModelForLocation(
|
||||
commonImpl: MobileIconViewModelCommon,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
loc: StatusBarLocation,
|
||||
): LocationBasedMobileViewModel =
|
||||
when (loc) {
|
||||
StatusBarLocation.HOME -> HomeMobileIconViewModel(commonImpl, logger)
|
||||
StatusBarLocation.KEYGUARD -> KeyguardMobileIconViewModel(commonImpl, logger)
|
||||
StatusBarLocation.QS -> QsMobileIconViewModel(commonImpl, logger)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HomeMobileIconViewModel(
|
||||
commonImpl: MobileIconViewModelCommon,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
) : MobileIconViewModelCommon, LocationBasedMobileViewModel(commonImpl, logger) {
|
||||
override val tint: Flow<Int> =
|
||||
flowOf(Color.CYAN)
|
||||
.distinctUntilChanged()
|
||||
.logOutputChange(logger, "HOME tint(${commonImpl.subscriptionId})")
|
||||
}
|
||||
|
||||
class QsMobileIconViewModel(
|
||||
commonImpl: MobileIconViewModelCommon,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
) : MobileIconViewModelCommon, LocationBasedMobileViewModel(commonImpl, logger) {
|
||||
override val tint: Flow<Int> =
|
||||
flowOf(Color.GREEN)
|
||||
.distinctUntilChanged()
|
||||
.logOutputChange(logger, "QS tint(${commonImpl.subscriptionId})")
|
||||
}
|
||||
|
||||
class KeyguardMobileIconViewModel(
|
||||
commonImpl: MobileIconViewModelCommon,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
) : MobileIconViewModelCommon, LocationBasedMobileViewModel(commonImpl, logger) {
|
||||
override val tint: Flow<Int> =
|
||||
flowOf(Color.MAGENTA)
|
||||
.distinctUntilChanged()
|
||||
.logOutputChange(logger, "KEYGUARD tint(${commonImpl.subscriptionId})")
|
||||
}
|
||||
@@ -16,23 +16,40 @@
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
|
||||
|
||||
import android.graphics.Color
|
||||
import com.android.settingslib.graph.SignalDrawable
|
||||
import com.android.systemui.common.shared.model.ContentDescription
|
||||
import com.android.systemui.common.shared.model.Icon
|
||||
import com.android.systemui.log.table.logDiffsForTable
|
||||
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.shared.ConnectivityConstants
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
/** Common interface for all of the location-based mobile icon view models. */
|
||||
interface MobileIconViewModelCommon {
|
||||
val subscriptionId: Int
|
||||
/** An int consumable by [SignalDrawable] for display */
|
||||
val iconId: Flow<Int>
|
||||
val roaming: Flow<Boolean>
|
||||
/** The RAT icon (LTE, 3G, 5G, etc) to be displayed. Null if we shouldn't show anything */
|
||||
val networkTypeIcon: Flow<Icon?>
|
||||
val activityInVisible: Flow<Boolean>
|
||||
val activityOutVisible: Flow<Boolean>
|
||||
val activityContainerVisible: Flow<Boolean>
|
||||
}
|
||||
|
||||
/**
|
||||
* View model for the state of a single mobile icon. Each [MobileIconViewModel] will keep watch over
|
||||
@@ -40,25 +57,29 @@ import kotlinx.coroutines.flow.mapLatest
|
||||
* subscription's information.
|
||||
*
|
||||
* There will be exactly one [MobileIconViewModel] per filtered subscription offered from
|
||||
* [MobileIconsInteractor.filteredSubscriptions]
|
||||
* [MobileIconsInteractor.filteredSubscriptions].
|
||||
*
|
||||
* TODO: figure out where carrier merged and VCN models go (probably here?)
|
||||
* For the sake of keeping log spam in check, every flow funding the [MobileIconViewModelCommon]
|
||||
* interface is implemented as a [StateFlow]. This ensures that each location-based mobile icon view
|
||||
* model gets the exact same information, as well as allows us to log that unified state only once
|
||||
* per icon.
|
||||
*/
|
||||
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class MobileIconViewModel
|
||||
constructor(
|
||||
val subscriptionId: Int,
|
||||
override val subscriptionId: Int,
|
||||
iconInteractor: MobileIconInteractor,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
constants: ConnectivityConstants,
|
||||
) {
|
||||
scope: CoroutineScope,
|
||||
) : MobileIconViewModelCommon {
|
||||
/** Whether or not to show the error state of [SignalDrawable] */
|
||||
private val showExclamationMark: Flow<Boolean> =
|
||||
iconInteractor.isDefaultDataEnabled.mapLatest { !it }
|
||||
|
||||
/** An int consumable by [SignalDrawable] for display */
|
||||
val iconId: Flow<Int> =
|
||||
override val iconId: Flow<Int> = run {
|
||||
val initial = SignalDrawable.getEmptyState(iconInteractor.numberOfLevels.value)
|
||||
combine(iconInteractor.level, iconInteractor.numberOfLevels, showExclamationMark) {
|
||||
level,
|
||||
numberOfLevels,
|
||||
@@ -66,32 +87,56 @@ constructor(
|
||||
SignalDrawable.getState(level, numberOfLevels, showExclamationMark)
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.logOutputChange(logger, "iconId($subscriptionId)")
|
||||
.logDiffsForTable(
|
||||
iconInteractor.tableLogBuffer,
|
||||
columnPrefix = "",
|
||||
columnName = "iconId",
|
||||
initialValue = initial,
|
||||
)
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
|
||||
}
|
||||
|
||||
/** The RAT icon (LTE, 3G, 5G, etc) to be displayed. Null if we shouldn't show anything */
|
||||
val networkTypeIcon: Flow<Icon?> =
|
||||
override val networkTypeIcon: Flow<Icon?> =
|
||||
combine(
|
||||
iconInteractor.networkTypeIconGroup,
|
||||
iconInteractor.isDataConnected,
|
||||
iconInteractor.isDataEnabled,
|
||||
iconInteractor.isDefaultConnectionFailed,
|
||||
iconInteractor.alwaysShowDataRatIcon,
|
||||
) { networkTypeIconGroup, dataConnected, dataEnabled, failedConnection, alwaysShow ->
|
||||
val desc =
|
||||
if (networkTypeIconGroup.dataContentDescription != 0)
|
||||
ContentDescription.Resource(networkTypeIconGroup.dataContentDescription)
|
||||
else null
|
||||
val icon = Icon.Resource(networkTypeIconGroup.dataType, desc)
|
||||
return@combine when {
|
||||
alwaysShow -> icon
|
||||
!dataConnected -> null
|
||||
!dataEnabled -> null
|
||||
failedConnection -> null
|
||||
else -> icon
|
||||
iconInteractor.networkTypeIconGroup,
|
||||
iconInteractor.isDataConnected,
|
||||
iconInteractor.isDataEnabled,
|
||||
iconInteractor.isDefaultConnectionFailed,
|
||||
iconInteractor.alwaysShowDataRatIcon,
|
||||
) { networkTypeIconGroup, dataConnected, dataEnabled, failedConnection, alwaysShow ->
|
||||
val desc =
|
||||
if (networkTypeIconGroup.dataContentDescription != 0)
|
||||
ContentDescription.Resource(networkTypeIconGroup.dataContentDescription)
|
||||
else null
|
||||
val icon = Icon.Resource(networkTypeIconGroup.dataType, desc)
|
||||
return@combine when {
|
||||
alwaysShow -> icon
|
||||
!dataConnected -> null
|
||||
!dataEnabled -> null
|
||||
failedConnection -> null
|
||||
else -> icon
|
||||
}
|
||||
}
|
||||
}
|
||||
.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)
|
||||
|
||||
val roaming: Flow<Boolean> = iconInteractor.isRoaming
|
||||
override val roaming: StateFlow<Boolean> =
|
||||
iconInteractor.isRoaming
|
||||
.logDiffsForTable(
|
||||
iconInteractor.tableLogBuffer,
|
||||
columnPrefix = "",
|
||||
columnName = "roaming",
|
||||
initialValue = false,
|
||||
)
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||
|
||||
private val activity: Flow<DataActivityModel?> =
|
||||
if (!constants.shouldShowActivityConfig) {
|
||||
@@ -100,10 +145,39 @@ constructor(
|
||||
iconInteractor.activity
|
||||
}
|
||||
|
||||
val activityInVisible: Flow<Boolean> = activity.map { it?.hasActivityIn ?: false }
|
||||
val activityOutVisible: Flow<Boolean> = activity.map { it?.hasActivityOut ?: false }
|
||||
val activityContainerVisible: Flow<Boolean> =
|
||||
activity.map { it != null && (it.hasActivityIn || it.hasActivityOut) }
|
||||
override val activityInVisible: Flow<Boolean> =
|
||||
activity
|
||||
.map { it?.hasActivityIn ?: false }
|
||||
.distinctUntilChanged()
|
||||
.logDiffsForTable(
|
||||
iconInteractor.tableLogBuffer,
|
||||
columnPrefix = "",
|
||||
columnName = "activityInVisible",
|
||||
initialValue = false,
|
||||
)
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||
|
||||
val tint: Flow<Int> = flowOf(Color.CYAN)
|
||||
override val activityOutVisible: Flow<Boolean> =
|
||||
activity
|
||||
.map { it?.hasActivityOut ?: false }
|
||||
.distinctUntilChanged()
|
||||
.logDiffsForTable(
|
||||
iconInteractor.tableLogBuffer,
|
||||
columnPrefix = "",
|
||||
columnName = "activityOutVisible",
|
||||
initialValue = false,
|
||||
)
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||
|
||||
override val activityContainerVisible: Flow<Boolean> =
|
||||
activity
|
||||
.map { it != null && (it.hasActivityIn || it.hasActivityOut) }
|
||||
.distinctUntilChanged()
|
||||
.logDiffsForTable(
|
||||
iconInteractor.tableLogBuffer,
|
||||
columnPrefix = "",
|
||||
columnName = "activityContainerVisible",
|
||||
initialValue = false,
|
||||
)
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||
}
|
||||
|
||||
@@ -14,17 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:OptIn(InternalCoroutinesApi::class)
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.statusbar.phone.StatusBarLocation
|
||||
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.shared.ConnectivityConstants
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* View model for describing the system's current mobile cellular connections. The result is a list
|
||||
@@ -38,15 +40,33 @@ constructor(
|
||||
private val interactor: MobileIconsInteractor,
|
||||
private val logger: ConnectivityPipelineLogger,
|
||||
private val constants: ConnectivityConstants,
|
||||
@Application private val scope: CoroutineScope,
|
||||
) {
|
||||
/** TODO: do we need to cache these? */
|
||||
fun viewModelForSub(subId: Int): MobileIconViewModel =
|
||||
MobileIconViewModel(
|
||||
subId,
|
||||
interactor.createMobileConnectionInteractorForSubId(subId),
|
||||
logger,
|
||||
constants,
|
||||
)
|
||||
@VisibleForTesting val mobileIconSubIdCache = mutableMapOf<Int, MobileIconViewModel>()
|
||||
|
||||
init {
|
||||
scope.launch { subscriptionIdsFlow.collect { removeInvalidModelsFromCache(it) } }
|
||||
}
|
||||
|
||||
fun viewModelForSub(subId: Int, location: StatusBarLocation): LocationBasedMobileViewModel {
|
||||
val common =
|
||||
mobileIconSubIdCache[subId]
|
||||
?: MobileIconViewModel(
|
||||
subId,
|
||||
interactor.createMobileConnectionInteractorForSubId(subId),
|
||||
logger,
|
||||
constants,
|
||||
scope,
|
||||
)
|
||||
.also { mobileIconSubIdCache[subId] = it }
|
||||
|
||||
return LocationBasedMobileViewModel.viewModelForLocation(common, logger, location)
|
||||
}
|
||||
|
||||
private fun removeInvalidModelsFromCache(subIds: List<Int>) {
|
||||
val subIdsToRemove = mobileIconSubIdCache.keys.filter { !subIds.contains(it) }
|
||||
subIdsToRemove.forEach { mobileIconSubIdCache.remove(it) }
|
||||
}
|
||||
|
||||
class Factory
|
||||
@Inject
|
||||
@@ -54,6 +74,7 @@ constructor(
|
||||
private val interactor: MobileIconsInteractor,
|
||||
private val logger: ConnectivityPipelineLogger,
|
||||
private val constants: ConnectivityConstants,
|
||||
@Application private val scope: CoroutineScope,
|
||||
) {
|
||||
fun create(subscriptionIdsFlow: StateFlow<List<Int>>): MobileIconsViewModel {
|
||||
return MobileIconsViewModel(
|
||||
@@ -61,6 +82,7 @@ constructor(
|
||||
interactor,
|
||||
logger,
|
||||
constants,
|
||||
scope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,11 @@ package com.android.systemui.statusbar.pipeline.shared
|
||||
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import com.android.systemui.log.dagger.StatusBarConnectivityLog
|
||||
import android.telephony.ServiceState
|
||||
import android.telephony.SignalStrength
|
||||
import android.telephony.TelephonyDisplayInfo
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.log.dagger.StatusBarConnectivityLog
|
||||
import com.android.systemui.plugins.log.LogBuffer
|
||||
import com.android.systemui.plugins.log.LogLevel
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.toString
|
||||
@@ -28,7 +31,9 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
@SysUISingleton
|
||||
class ConnectivityPipelineLogger @Inject constructor(
|
||||
class ConnectivityPipelineLogger
|
||||
@Inject
|
||||
constructor(
|
||||
@StatusBarConnectivityLog private val buffer: LogBuffer,
|
||||
) {
|
||||
/**
|
||||
@@ -37,34 +42,23 @@ class ConnectivityPipelineLogger @Inject constructor(
|
||||
* Use this method for inputs that don't have any extra information besides their callback name.
|
||||
*/
|
||||
fun logInputChange(callbackName: String) {
|
||||
buffer.log(SB_LOGGING_TAG, LogLevel.INFO, { str1 = callbackName }, { "Input: $str1" })
|
||||
}
|
||||
|
||||
/** Logs a change in one of the **raw inputs** to the connectivity pipeline. */
|
||||
fun logInputChange(callbackName: String, changeInfo: String?) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{ str1 = callbackName },
|
||||
{ "Input: $str1" }
|
||||
{
|
||||
str1 = callbackName
|
||||
str2 = changeInfo
|
||||
},
|
||||
{ "Input: $str1: $str2" }
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a change in one of the **raw inputs** to the connectivity pipeline.
|
||||
*/
|
||||
fun logInputChange(callbackName: String, changeInfo: String?) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
str1 = callbackName
|
||||
str2 = changeInfo
|
||||
},
|
||||
{
|
||||
"Input: $str1: $str2"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a **data transformation** that we performed within the connectivity pipeline.
|
||||
*/
|
||||
/** Logs a **data transformation** that we performed within the connectivity pipeline. */
|
||||
fun logTransformation(transformationName: String, oldValue: Any?, newValue: Any?) {
|
||||
if (oldValue == newValue) {
|
||||
buffer.log(
|
||||
@@ -74,9 +68,7 @@ class ConnectivityPipelineLogger @Inject constructor(
|
||||
str1 = transformationName
|
||||
str2 = oldValue.toString()
|
||||
},
|
||||
{
|
||||
"Transform: $str1: $str2 (transformation didn't change it)"
|
||||
}
|
||||
{ "Transform: $str1: $str2 (transformation didn't change it)" }
|
||||
)
|
||||
} else {
|
||||
buffer.log(
|
||||
@@ -87,27 +79,21 @@ class ConnectivityPipelineLogger @Inject constructor(
|
||||
str2 = oldValue.toString()
|
||||
str3 = newValue.toString()
|
||||
},
|
||||
{
|
||||
"Transform: $str1: $str2 -> $str3"
|
||||
}
|
||||
{ "Transform: $str1: $str2 -> $str3" }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a change in one of the **outputs** to the connectivity pipeline.
|
||||
*/
|
||||
/** Logs a change in one of the **outputs** to the connectivity pipeline. */
|
||||
fun logOutputChange(outputParamName: String, changeInfo: String) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
str1 = outputParamName
|
||||
str2 = changeInfo
|
||||
},
|
||||
{
|
||||
"Output: $str1: $str2"
|
||||
}
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
str1 = outputParamName
|
||||
str2 = changeInfo
|
||||
},
|
||||
{ "Output: $str1: $str2" }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -119,31 +105,101 @@ class ConnectivityPipelineLogger @Inject constructor(
|
||||
int1 = network.getNetId()
|
||||
str1 = networkCapabilities.toString()
|
||||
},
|
||||
{
|
||||
"onCapabilitiesChanged: net=$int1 capabilities=$str1"
|
||||
}
|
||||
{ "onCapabilitiesChanged: net=$int1 capabilities=$str1" }
|
||||
)
|
||||
}
|
||||
|
||||
fun logOnLost(network: Network) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{ int1 = network.getNetId() },
|
||||
{ "onLost: net=$int1" }
|
||||
)
|
||||
}
|
||||
|
||||
fun logOnServiceStateChanged(serviceState: ServiceState, subId: Int) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
int1 = network.getNetId()
|
||||
int1 = subId
|
||||
bool1 = serviceState.isEmergencyOnly
|
||||
bool2 = serviceState.roaming
|
||||
str1 = serviceState.operatorAlphaShort
|
||||
},
|
||||
{
|
||||
"onLost: net=$int1"
|
||||
"onServiceStateChanged: subId=$int1 emergencyOnly=$bool1 roaming=$bool2" +
|
||||
" operator=$str1"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun logOnSignalStrengthsChanged(signalStrength: SignalStrength, subId: Int) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
int1 = subId
|
||||
str1 = signalStrength.toString()
|
||||
},
|
||||
{ "onSignalStrengthsChanged: subId=$int1 strengths=$str1" }
|
||||
)
|
||||
}
|
||||
|
||||
fun logOnDataConnectionStateChanged(dataState: Int, networkType: Int, subId: Int) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
int1 = subId
|
||||
int2 = dataState
|
||||
str1 = networkType.toString()
|
||||
},
|
||||
{ "onDataConnectionStateChanged: subId=$int1 dataState=$int2 networkType=$str1" },
|
||||
)
|
||||
}
|
||||
|
||||
fun logOnDataActivity(direction: Int, subId: Int) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
int1 = subId
|
||||
int2 = direction
|
||||
},
|
||||
{ "onDataActivity: subId=$int1 direction=$int2" },
|
||||
)
|
||||
}
|
||||
|
||||
fun logOnCarrierNetworkChange(active: Boolean, subId: Int) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
int1 = subId
|
||||
bool1 = active
|
||||
},
|
||||
{ "onCarrierNetworkChange: subId=$int1 active=$bool1" },
|
||||
)
|
||||
}
|
||||
|
||||
fun logOnDisplayInfoChanged(displayInfo: TelephonyDisplayInfo, subId: Int) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
int1 = subId
|
||||
str1 = displayInfo.toString()
|
||||
},
|
||||
{ "onDisplayInfoChanged: subId=$int1 displayInfo=$str1" },
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val SB_LOGGING_TAG = "SbConnectivity"
|
||||
|
||||
/**
|
||||
* Log a change in one of the **inputs** to the connectivity pipeline.
|
||||
*/
|
||||
/** Log a change in one of the **inputs** to the connectivity pipeline. */
|
||||
fun Flow<Unit>.logInputChange(
|
||||
logger: ConnectivityPipelineLogger,
|
||||
inputParamName: String,
|
||||
@@ -155,26 +211,26 @@ class ConnectivityPipelineLogger @Inject constructor(
|
||||
* Log a change in one of the **inputs** to the connectivity pipeline.
|
||||
*
|
||||
* @param prettyPrint an optional function to transform the value into a readable string.
|
||||
* [toString] is used if no custom function is provided.
|
||||
* [toString] is used if no custom function is provided.
|
||||
*/
|
||||
fun <T> Flow<T>.logInputChange(
|
||||
logger: ConnectivityPipelineLogger,
|
||||
inputParamName: String,
|
||||
prettyPrint: (T) -> String = { it.toString() }
|
||||
): Flow<T> {
|
||||
return this.onEach {logger.logInputChange(inputParamName, prettyPrint(it)) }
|
||||
return this.onEach { logger.logInputChange(inputParamName, prettyPrint(it)) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a change in one of the **outputs** to the connectivity pipeline.
|
||||
*
|
||||
* @param prettyPrint an optional function to transform the value into a readable string.
|
||||
* [toString] is used if no custom function is provided.
|
||||
* [toString] is used if no custom function is provided.
|
||||
*/
|
||||
fun <T> Flow<T>.logOutputChange(
|
||||
logger: ConnectivityPipelineLogger,
|
||||
outputParamName: String,
|
||||
prettyPrint: (T) -> String = { it.toString() }
|
||||
logger: ConnectivityPipelineLogger,
|
||||
outputParamName: String,
|
||||
prettyPrint: (T) -> String = { it.toString() }
|
||||
): Flow<T> {
|
||||
return this.onEach { logger.logOutputChange(outputParamName, prettyPrint(it)) }
|
||||
}
|
||||
|
||||
@@ -38,16 +38,12 @@ class WifiConstants @Inject constructor(
|
||||
dumpManager.registerDumpable("${SB_LOGGING_TAG}WifiConstants", this)
|
||||
}
|
||||
|
||||
/** True if we should show the activityIn/activityOut icons and false otherwise. */
|
||||
val shouldShowActivityConfig = context.resources.getBoolean(R.bool.config_showActivity)
|
||||
|
||||
/** True if we should always show the wifi icon when wifi is enabled and false otherwise. */
|
||||
val alwaysShowIconIfEnabled =
|
||||
context.resources.getBoolean(R.bool.config_showWifiIndicatorWhenEnabled)
|
||||
|
||||
override fun dump(pw: PrintWriter, args: Array<out String>) {
|
||||
pw.apply {
|
||||
println("shouldShowActivityConfig=$shouldShowActivityConfig")
|
||||
println("alwaysShowIconIfEnabled=$alwaysShowIconIfEnabled")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ constructor(
|
||||
|
||||
/** The wifi activity status. Null if we shouldn't display the activity status. */
|
||||
private val activity: Flow<DataActivityModel?> =
|
||||
if (!wifiConstants.shouldShowActivityConfig) {
|
||||
if (!connectivityConstants.shouldShowActivityConfig) {
|
||||
flowOf(null)
|
||||
} else {
|
||||
combine(interactor.activity, interactor.ssid) { activity, ssid ->
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.model
|
||||
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.log.table.TableRowLogger
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_ACTIVITY_DIRECTION
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_CARRIER_NETWORK_CHANGE
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_CDMA_LEVEL
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_CONNECTION_STATE
|
||||
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_IS_GSM
|
||||
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.MobileConnectionModel.Companion.COL_RESOLVED_NETWORK_TYPE
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_ROAMING
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
@SmallTest
|
||||
class MobileConnectionModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun `log diff - initial log contains all columns`() {
|
||||
val logger = TestLogger()
|
||||
val connection = MobileConnectionModel()
|
||||
|
||||
connection.logFull(logger)
|
||||
|
||||
assertThat(logger.changes)
|
||||
.contains(Pair(COL_EMERGENCY, connection.isEmergencyOnly.toString()))
|
||||
assertThat(logger.changes).contains(Pair(COL_ROAMING, connection.isRoaming.toString()))
|
||||
assertThat(logger.changes)
|
||||
.contains(Pair(COL_OPERATOR, connection.operatorAlphaShort.toString()))
|
||||
assertThat(logger.changes).contains(Pair(COL_IS_GSM, connection.isGsm.toString()))
|
||||
assertThat(logger.changes).contains(Pair(COL_CDMA_LEVEL, connection.cdmaLevel.toString()))
|
||||
assertThat(logger.changes)
|
||||
.contains(Pair(COL_PRIMARY_LEVEL, connection.primaryLevel.toString()))
|
||||
assertThat(logger.changes)
|
||||
.contains(Pair(COL_CONNECTION_STATE, connection.dataConnectionState.toString()))
|
||||
assertThat(logger.changes)
|
||||
.contains(Pair(COL_ACTIVITY_DIRECTION, connection.dataActivityDirection.toString()))
|
||||
assertThat(logger.changes)
|
||||
.contains(
|
||||
Pair(COL_CARRIER_NETWORK_CHANGE, connection.carrierNetworkChangeActive.toString())
|
||||
)
|
||||
assertThat(logger.changes)
|
||||
.contains(Pair(COL_RESOLVED_NETWORK_TYPE, connection.resolvedNetworkType.toString()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `log diff - primary level changes - only level is logged`() {
|
||||
val logger = TestLogger()
|
||||
val connectionOld = MobileConnectionModel(primaryLevel = 1)
|
||||
|
||||
val connectionNew = MobileConnectionModel(primaryLevel = 2)
|
||||
|
||||
connectionNew.logDiffs(connectionOld, logger)
|
||||
|
||||
assertThat(logger.changes).isEqualTo(listOf(Pair(COL_PRIMARY_LEVEL, "2")))
|
||||
}
|
||||
|
||||
private class TestLogger : TableRowLogger {
|
||||
val changes = mutableListOf<Pair<String, String>>()
|
||||
|
||||
override fun logChange(columnName: String, value: String?) {
|
||||
changes.add(Pair(columnName, value.toString()))
|
||||
}
|
||||
|
||||
override fun logChange(columnName: String, value: Int) {
|
||||
changes.add(Pair(columnName, value.toString()))
|
||||
}
|
||||
|
||||
override fun logChange(columnName: String, value: Boolean) {
|
||||
changes.add(Pair(columnName, value.toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,12 +16,16 @@
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.mobile.data.repository
|
||||
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
// TODO(b/261632894): remove this in favor of the real impl or DemoMobileConnectionRepository
|
||||
class FakeMobileConnectionRepository(override val subId: Int) : MobileConnectionRepository {
|
||||
class FakeMobileConnectionRepository(
|
||||
override val subId: Int,
|
||||
override val tableLogBuffer: TableLogBuffer,
|
||||
) : MobileConnectionRepository {
|
||||
private val _connectionInfo = MutableStateFlow(MobileConnectionModel())
|
||||
override val connectionInfo = _connectionInfo
|
||||
|
||||
|
||||
@@ -22,14 +22,17 @@ import android.telephony.TelephonyManager
|
||||
import com.android.settingslib.SignalIcon
|
||||
import com.android.settingslib.mobile.MobileMappings
|
||||
import com.android.settingslib.mobile.TelephonyIcons
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
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.util.MobileMappingsProxy
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
// TODO(b/261632894): remove this in favor of the real impl or DemoMobileConnectionsRepository
|
||||
class FakeMobileConnectionsRepository(mobileMappings: MobileMappingsProxy) :
|
||||
MobileConnectionsRepository {
|
||||
class FakeMobileConnectionsRepository(
|
||||
mobileMappings: MobileMappingsProxy,
|
||||
val tableLogBuffer: TableLogBuffer,
|
||||
) : MobileConnectionsRepository {
|
||||
val GSM_KEY = mobileMappings.toIconKey(GSM)
|
||||
val LTE_KEY = mobileMappings.toIconKey(LTE)
|
||||
val UMTS_KEY = mobileMappings.toIconKey(UMTS)
|
||||
@@ -63,7 +66,7 @@ class FakeMobileConnectionsRepository(mobileMappings: MobileMappingsProxy) :
|
||||
private val subIdRepos = mutableMapOf<Int, MobileConnectionRepository>()
|
||||
override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
|
||||
return subIdRepos[subId]
|
||||
?: FakeMobileConnectionRepository(subId).also { subIdRepos[subId] = it }
|
||||
?: FakeMobileConnectionRepository(subId, tableLogBuffer).also { subIdRepos[subId] = it }
|
||||
}
|
||||
|
||||
private val _globalMobileDataSettingChangedEvent = MutableStateFlow(Unit)
|
||||
|
||||
@@ -24,6 +24,8 @@ import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.demomode.DemoMode
|
||||
import com.android.systemui.demomode.DemoModeController
|
||||
import com.android.systemui.dump.DumpManager
|
||||
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.repository.demo.DemoMobileConnectionsRepository
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoModeMobileConnectionDataSource
|
||||
@@ -37,6 +39,7 @@ import com.android.systemui.util.mockito.kotlinArgumentCaptor
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.android.systemui.util.settings.FakeSettings
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -69,12 +72,14 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
|
||||
private lateinit var realRepo: MobileConnectionsRepositoryImpl
|
||||
private lateinit var demoRepo: DemoMobileConnectionsRepository
|
||||
private lateinit var mockDataSource: DemoModeMobileConnectionDataSource
|
||||
private lateinit var logFactory: TableLogBufferFactory
|
||||
|
||||
@Mock private lateinit var connectivityManager: ConnectivityManager
|
||||
@Mock private lateinit var subscriptionManager: SubscriptionManager
|
||||
@Mock private lateinit var telephonyManager: TelephonyManager
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var demoModeController: DemoModeController
|
||||
@Mock private lateinit var dumpManager: DumpManager
|
||||
|
||||
private val globalSettings = FakeSettings()
|
||||
private val fakeNetworkEventsFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
|
||||
@@ -86,6 +91,8 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
logFactory = TableLogBufferFactory(dumpManager, FakeSystemClock())
|
||||
|
||||
// Never start in demo mode
|
||||
whenever(demoModeController.isInDemoMode).thenReturn(false)
|
||||
|
||||
@@ -114,6 +121,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
|
||||
dataSource = mockDataSource,
|
||||
scope = scope,
|
||||
context = context,
|
||||
logFactory = logFactory,
|
||||
)
|
||||
|
||||
underTest =
|
||||
|
||||
@@ -23,6 +23,7 @@ import androidx.test.filters.SmallTest
|
||||
import com.android.settingslib.SignalIcon
|
||||
import com.android.settingslib.mobile.TelephonyIcons
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.log.table.TableLogBufferFactory
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||
@@ -30,6 +31,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.cancel
|
||||
@@ -54,6 +56,9 @@ import org.junit.runners.Parameterized.Parameters
|
||||
@RunWith(Parameterized::class)
|
||||
internal class DemoMobileConnectionParameterizedTest(private val testCase: TestCase) :
|
||||
SysuiTestCase() {
|
||||
|
||||
private val logFactory = TableLogBufferFactory(mock(), FakeSystemClock())
|
||||
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
|
||||
@@ -76,6 +81,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
|
||||
dataSource = mockDataSource,
|
||||
scope = testScope.backgroundScope,
|
||||
context = context,
|
||||
logFactory = logFactory,
|
||||
)
|
||||
|
||||
connectionsRepo.startProcessingCommands()
|
||||
|
||||
@@ -23,6 +23,8 @@ import androidx.test.filters.SmallTest
|
||||
import com.android.settingslib.SignalIcon
|
||||
import com.android.settingslib.mobile.TelephonyIcons.THREE_G
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.log.table.TableLogBufferFactory
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||
@@ -32,6 +34,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import junit.framework.Assert
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
@@ -47,6 +50,9 @@ import org.junit.Test
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
|
||||
private val dumpManager: DumpManager = mock()
|
||||
private val logFactory = TableLogBufferFactory(dumpManager, FakeSystemClock())
|
||||
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
|
||||
@@ -68,6 +74,7 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
|
||||
dataSource = mockDataSource,
|
||||
scope = testScope.backgroundScope,
|
||||
context = context,
|
||||
logFactory = logFactory,
|
||||
)
|
||||
|
||||
underTest.startProcessingCommands()
|
||||
|
||||
@@ -50,6 +50,7 @@ import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
|
||||
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||
@@ -87,14 +88,15 @@ import org.mockito.MockitoAnnotations
|
||||
@SmallTest
|
||||
class MobileConnectionRepositoryTest : SysuiTestCase() {
|
||||
private lateinit var underTest: MobileConnectionRepositoryImpl
|
||||
private lateinit var connectionsRepo: FakeMobileConnectionsRepository
|
||||
|
||||
@Mock private lateinit var telephonyManager: TelephonyManager
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var tableLogger: TableLogBuffer
|
||||
|
||||
private val scope = CoroutineScope(IMMEDIATE)
|
||||
private val mobileMappings = FakeMobileMappingsProxy()
|
||||
private val globalSettings = FakeSettings()
|
||||
private val connectionsRepo = FakeMobileConnectionsRepository(mobileMappings)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
@@ -102,6 +104,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
||||
globalSettings.userId = UserHandle.USER_ALL
|
||||
whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
|
||||
|
||||
connectionsRepo = FakeMobileConnectionsRepository(mobileMappings, tableLogger)
|
||||
|
||||
underTest =
|
||||
MobileConnectionRepositoryImpl(
|
||||
context,
|
||||
@@ -116,6 +120,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
||||
mobileMappings,
|
||||
IMMEDIATE,
|
||||
logger,
|
||||
tableLogger,
|
||||
scope,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -34,12 +34,15 @@ import com.android.internal.telephony.PhoneConstants
|
||||
import com.android.settingslib.R
|
||||
import com.android.settingslib.mobile.MobileMappings
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.log.table.TableLogBufferFactory
|
||||
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.util.FakeMobileMappingsProxy
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.android.systemui.util.settings.FakeSettings
|
||||
@@ -57,6 +60,7 @@ import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.ArgumentMatchers.anyString
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
@@ -72,6 +76,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
||||
@Mock private lateinit var subscriptionManager: SubscriptionManager
|
||||
@Mock private lateinit var telephonyManager: TelephonyManager
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var logBufferFactory: TableLogBufferFactory
|
||||
|
||||
private val mobileMappings = FakeMobileMappingsProxy()
|
||||
|
||||
@@ -89,6 +94,10 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
whenever(logBufferFactory.create(anyString(), anyInt())).thenAnswer { _ ->
|
||||
mock<TableLogBuffer>()
|
||||
}
|
||||
|
||||
connectionFactory =
|
||||
MobileConnectionRepositoryImpl.Factory(
|
||||
fakeBroadcastDispatcher,
|
||||
@@ -99,6 +108,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
||||
logger = logger,
|
||||
mobileMappingsProxy = mobileMappings,
|
||||
scope = scope,
|
||||
logFactory = logBufferFactory,
|
||||
)
|
||||
|
||||
underTest =
|
||||
@@ -270,6 +280,32 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `connection repository - log buffer contains sub id in its name`() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
val job = underTest.subscriptions.launchIn(this)
|
||||
|
||||
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
|
||||
.thenReturn(listOf(SUB_1, SUB_2))
|
||||
getSubscriptionCallback().onSubscriptionsChanged()
|
||||
|
||||
// Get repos to trigger creation
|
||||
underTest.getRepoForSubId(SUB_1_ID)
|
||||
verify(logBufferFactory)
|
||||
.create(
|
||||
eq(MobileConnectionRepositoryImpl.tableBufferLogName(SUB_1_ID)),
|
||||
anyInt(),
|
||||
)
|
||||
underTest.getRepoForSubId(SUB_2_ID)
|
||||
verify(logBufferFactory)
|
||||
.create(
|
||||
eq(MobileConnectionRepositoryImpl.tableBufferLogName(SUB_2_ID)),
|
||||
anyInt(),
|
||||
)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDefaultDataSubId_updatesOnBroadcast() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
|
||||
@@ -19,11 +19,14 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
|
||||
import android.telephony.CellSignalStrength
|
||||
import com.android.settingslib.SignalIcon
|
||||
import com.android.settingslib.mobile.TelephonyIcons
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class FakeMobileIconInteractor : MobileIconInteractor {
|
||||
class FakeMobileIconInteractor(
|
||||
override val tableLogBuffer: TableLogBuffer,
|
||||
) : MobileIconInteractor {
|
||||
override val alwaysShowDataRatIcon = MutableStateFlow(false)
|
||||
|
||||
override val activity =
|
||||
|
||||
@@ -22,12 +22,15 @@ import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
|
||||
import android.telephony.TelephonyManager.NETWORK_TYPE_UMTS
|
||||
import com.android.settingslib.SignalIcon.MobileIconGroup
|
||||
import com.android.settingslib.mobile.TelephonyIcons
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class FakeMobileIconsInteractor(mobileMappings: MobileMappingsProxy) : MobileIconsInteractor {
|
||||
class FakeMobileIconsInteractor(
|
||||
mobileMappings: MobileMappingsProxy,
|
||||
val tableLogBuffer: TableLogBuffer,
|
||||
) : MobileIconsInteractor {
|
||||
val THREE_G_KEY = mobileMappings.toIconKey(THREE_G)
|
||||
val LTE_KEY = mobileMappings.toIconKey(LTE)
|
||||
val FOUR_G_KEY = mobileMappings.toIconKey(FOUR_G)
|
||||
@@ -48,8 +51,7 @@ class FakeMobileIconsInteractor(mobileMappings: MobileMappingsProxy) : MobileIco
|
||||
|
||||
override val isDefaultConnectionFailed = MutableStateFlow(false)
|
||||
|
||||
private val _filteredSubscriptions = MutableStateFlow<List<SubscriptionModel>>(listOf())
|
||||
override val filteredSubscriptions: Flow<List<SubscriptionModel>> = _filteredSubscriptions
|
||||
override val filteredSubscriptions = MutableStateFlow<List<SubscriptionModel>>(listOf())
|
||||
|
||||
private val _activeDataConnectionHasDataEnabled = MutableStateFlow(false)
|
||||
override val activeDataConnectionHasDataEnabled = _activeDataConnectionHasDataEnabled
|
||||
@@ -67,7 +69,7 @@ class FakeMobileIconsInteractor(mobileMappings: MobileMappingsProxy) : MobileIco
|
||||
|
||||
/** Always returns a new fake interactor */
|
||||
override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor {
|
||||
return FakeMobileIconInteractor()
|
||||
return FakeMobileIconInteractor(tableLogBuffer)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -49,8 +49,8 @@ import org.junit.Test
|
||||
class MobileIconInteractorTest : SysuiTestCase() {
|
||||
private lateinit var underTest: MobileIconInteractor
|
||||
private val mobileMappingsProxy = FakeMobileMappingsProxy()
|
||||
private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy)
|
||||
private val connectionRepository = FakeMobileConnectionRepository(SUB_1_ID)
|
||||
private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock())
|
||||
private val connectionRepository = FakeMobileConnectionRepository(SUB_1_ID, mock())
|
||||
|
||||
private val scope = CoroutineScope(IMMEDIATE)
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.settingslib.mobile.MobileMappings
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
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.repository.FakeMobileConnectionRepository
|
||||
@@ -28,6 +29,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSe
|
||||
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
||||
import com.android.systemui.util.CarrierConfigTracker
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -44,9 +46,9 @@ import org.mockito.MockitoAnnotations
|
||||
@SmallTest
|
||||
class MobileIconsInteractorTest : SysuiTestCase() {
|
||||
private lateinit var underTest: MobileIconsInteractor
|
||||
private lateinit var connectionsRepository: FakeMobileConnectionsRepository
|
||||
private val userSetupRepository = FakeUserSetupRepository()
|
||||
private val mobileMappingsProxy = FakeMobileMappingsProxy()
|
||||
private val connectionsRepository = FakeMobileConnectionsRepository(mobileMappingsProxy)
|
||||
private val scope = CoroutineScope(IMMEDIATE)
|
||||
|
||||
@Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
|
||||
@@ -55,6 +57,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
connectionsRepository = FakeMobileConnectionsRepository(mobileMappingsProxy, tableLogBuffer)
|
||||
connectionsRepository.setMobileConnectionRepositoryMap(
|
||||
mapOf(
|
||||
SUB_1_ID to CONNECTION_1,
|
||||
@@ -290,21 +293,23 @@ class MobileIconsInteractorTest : SysuiTestCase() {
|
||||
|
||||
companion object {
|
||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||
private val tableLogBuffer =
|
||||
TableLogBuffer(8, "MobileIconsInteractorTest", FakeSystemClock())
|
||||
|
||||
private const val SUB_1_ID = 1
|
||||
private val SUB_1 = SubscriptionModel(subscriptionId = SUB_1_ID)
|
||||
private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID)
|
||||
private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID, tableLogBuffer)
|
||||
|
||||
private const val SUB_2_ID = 2
|
||||
private val SUB_2 = SubscriptionModel(subscriptionId = SUB_2_ID)
|
||||
private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID)
|
||||
private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, tableLogBuffer)
|
||||
|
||||
private const val SUB_3_ID = 3
|
||||
private val SUB_3_OPP = SubscriptionModel(subscriptionId = SUB_3_ID, isOpportunistic = true)
|
||||
private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID)
|
||||
private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, tableLogBuffer)
|
||||
|
||||
private const val SUB_4_ID = 4
|
||||
private val SUB_4_OPP = SubscriptionModel(subscriptionId = SUB_4_ID, isOpportunistic = true)
|
||||
private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID)
|
||||
private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, tableLogBuffer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.viewmodel
|
||||
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.settingslib.mobile.TelephonyIcons
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
|
||||
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.ConnectivityPipelineLogger
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
class LocationBasedMobileIconViewModelTest : SysuiTestCase() {
|
||||
private lateinit var commonImpl: MobileIconViewModelCommon
|
||||
private lateinit var homeIcon: HomeMobileIconViewModel
|
||||
private lateinit var qsIcon: QsMobileIconViewModel
|
||||
private lateinit var keyguardIcon: KeyguardMobileIconViewModel
|
||||
private lateinit var interactor: FakeMobileIconInteractor
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var constants: ConnectivityConstants
|
||||
@Mock private lateinit var tableLogBuffer: TableLogBuffer
|
||||
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
interactor = FakeMobileIconInteractor(tableLogBuffer)
|
||||
interactor.apply {
|
||||
setLevel(1)
|
||||
setIsDefaultDataEnabled(true)
|
||||
setIsFailedConnection(false)
|
||||
setIconGroup(TelephonyIcons.THREE_G)
|
||||
setIsEmergencyOnly(false)
|
||||
setNumberOfLevels(4)
|
||||
isDataConnected.value = true
|
||||
}
|
||||
commonImpl =
|
||||
MobileIconViewModel(SUB_1_ID, interactor, logger, constants, testScope.backgroundScope)
|
||||
|
||||
homeIcon = HomeMobileIconViewModel(commonImpl, logger)
|
||||
qsIcon = QsMobileIconViewModel(commonImpl, logger)
|
||||
keyguardIcon = KeyguardMobileIconViewModel(commonImpl, logger)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `location based view models receive same icon id when common impl updates`() =
|
||||
testScope.runTest {
|
||||
var latestHome: Int? = null
|
||||
val homeJob = homeIcon.iconId.onEach { latestHome = it }.launchIn(this)
|
||||
|
||||
var latestQs: Int? = null
|
||||
val qsJob = qsIcon.iconId.onEach { latestQs = it }.launchIn(this)
|
||||
|
||||
var latestKeyguard: Int? = null
|
||||
val keyguardJob = keyguardIcon.iconId.onEach { latestKeyguard = it }.launchIn(this)
|
||||
|
||||
var expected = defaultSignal(level = 1)
|
||||
|
||||
assertThat(latestHome).isEqualTo(expected)
|
||||
assertThat(latestQs).isEqualTo(expected)
|
||||
assertThat(latestKeyguard).isEqualTo(expected)
|
||||
|
||||
interactor.setLevel(2)
|
||||
expected = defaultSignal(level = 2)
|
||||
|
||||
assertThat(latestHome).isEqualTo(expected)
|
||||
assertThat(latestQs).isEqualTo(expected)
|
||||
assertThat(latestKeyguard).isEqualTo(expected)
|
||||
|
||||
homeJob.cancel()
|
||||
qsJob.cancel()
|
||||
keyguardJob.cancel()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SUB_1_ID = 1
|
||||
}
|
||||
}
|
||||
@@ -22,32 +22,42 @@ import com.android.settingslib.mobile.TelephonyIcons.THREE_G
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.common.shared.model.ContentDescription
|
||||
import com.android.systemui.common.shared.model.Icon
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
|
||||
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.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.coroutines.yield
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
class MobileIconViewModelTest : SysuiTestCase() {
|
||||
private lateinit var underTest: MobileIconViewModel
|
||||
private val interactor = FakeMobileIconInteractor()
|
||||
private lateinit var interactor: FakeMobileIconInteractor
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var constants: ConnectivityConstants
|
||||
@Mock private lateinit var tableLogBuffer: TableLogBuffer
|
||||
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
interactor = FakeMobileIconInteractor(tableLogBuffer)
|
||||
interactor.apply {
|
||||
setLevel(1)
|
||||
setIsDefaultDataEnabled(true)
|
||||
@@ -57,12 +67,13 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
setNumberOfLevels(4)
|
||||
isDataConnected.value = true
|
||||
}
|
||||
underTest = MobileIconViewModel(SUB_1_ID, interactor, logger, constants)
|
||||
underTest =
|
||||
MobileIconViewModel(SUB_1_ID, interactor, logger, constants, testScope.backgroundScope)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun iconId_correctLevel_notCutout() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
testScope.runTest {
|
||||
var latest: Int? = null
|
||||
val job = underTest.iconId.onEach { latest = it }.launchIn(this)
|
||||
val expected = defaultSignal()
|
||||
@@ -74,7 +85,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun iconId_cutout_whenDefaultDataDisabled() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
testScope.runTest {
|
||||
interactor.setIsDefaultDataEnabled(false)
|
||||
|
||||
var latest: Int? = null
|
||||
@@ -88,7 +99,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun networkType_dataEnabled_groupIsRepresented() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
testScope.runTest {
|
||||
val expected =
|
||||
Icon.Resource(
|
||||
THREE_G.dataType,
|
||||
@@ -106,7 +117,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun networkType_nullWhenDisabled() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
testScope.runTest {
|
||||
interactor.setIconGroup(THREE_G)
|
||||
interactor.setIsDataEnabled(false)
|
||||
var latest: Icon? = null
|
||||
@@ -119,7 +130,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun networkType_nullWhenFailedConnection() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
testScope.runTest {
|
||||
interactor.setIconGroup(THREE_G)
|
||||
interactor.setIsDataEnabled(true)
|
||||
interactor.setIsFailedConnection(true)
|
||||
@@ -133,7 +144,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun networkType_nullWhenDataDisconnects() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
testScope.runTest {
|
||||
val initial =
|
||||
Icon.Resource(
|
||||
THREE_G.dataType,
|
||||
@@ -157,7 +168,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun networkType_null_changeToDisabled() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
testScope.runTest {
|
||||
val expected =
|
||||
Icon.Resource(
|
||||
THREE_G.dataType,
|
||||
@@ -180,7 +191,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun networkType_alwaysShow_shownEvenWhenDisabled() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
testScope.runTest {
|
||||
interactor.setIconGroup(THREE_G)
|
||||
interactor.setIsDataEnabled(true)
|
||||
interactor.alwaysShowDataRatIcon.value = true
|
||||
@@ -200,7 +211,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun networkType_alwaysShow_shownEvenWhenDisconnected() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
testScope.runTest {
|
||||
interactor.setIconGroup(THREE_G)
|
||||
interactor.isDataConnected.value = false
|
||||
interactor.alwaysShowDataRatIcon.value = true
|
||||
@@ -220,7 +231,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun networkType_alwaysShow_shownEvenWhenFailedConnection() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
testScope.runTest {
|
||||
interactor.setIconGroup(THREE_G)
|
||||
interactor.setIsFailedConnection(true)
|
||||
interactor.alwaysShowDataRatIcon.value = true
|
||||
@@ -240,7 +251,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun roaming() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
testScope.runTest {
|
||||
interactor.isRoaming.value = true
|
||||
var latest: Boolean? = null
|
||||
val job = underTest.roaming.onEach { latest = it }.launchIn(this)
|
||||
@@ -256,10 +267,17 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun `data activity - null when config is off`() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
testScope.runTest {
|
||||
// Create a new view model here so the constants are properly read
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(false)
|
||||
underTest = MobileIconViewModel(SUB_1_ID, interactor, logger, constants)
|
||||
underTest =
|
||||
MobileIconViewModel(
|
||||
SUB_1_ID,
|
||||
interactor,
|
||||
logger,
|
||||
constants,
|
||||
testScope.backgroundScope,
|
||||
)
|
||||
|
||||
var inVisible: Boolean? = null
|
||||
val inJob = underTest.activityInVisible.onEach { inVisible = it }.launchIn(this)
|
||||
@@ -288,10 +306,17 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun `data activity - config on - test indicators`() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
testScope.runTest {
|
||||
// Create a new view model here so the constants are properly read
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
||||
underTest = MobileIconViewModel(SUB_1_ID, interactor, logger, constants)
|
||||
underTest =
|
||||
MobileIconViewModel(
|
||||
SUB_1_ID,
|
||||
interactor,
|
||||
logger,
|
||||
constants,
|
||||
testScope.backgroundScope,
|
||||
)
|
||||
|
||||
var inVisible: Boolean? = null
|
||||
val inJob = underTest.activityInVisible.onEach { inVisible = it }.launchIn(this)
|
||||
@@ -340,16 +365,15 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
containerJob.cancel()
|
||||
}
|
||||
|
||||
/** Convenience constructor for these tests */
|
||||
private fun defaultSignal(
|
||||
level: Int = 1,
|
||||
connected: Boolean = true,
|
||||
): Int {
|
||||
return SignalDrawable.getState(level, /* numLevels */ 4, !connected)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||
private const val SUB_1_ID = 1
|
||||
|
||||
/** Convenience constructor for these tests */
|
||||
fun defaultSignal(
|
||||
level: Int = 1,
|
||||
connected: Boolean = true,
|
||||
): Int {
|
||||
return SignalDrawable.getState(level, /* numLevels */ 4, !connected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.viewmodel
|
||||
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.phone.StatusBarLocation
|
||||
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.util.FakeMobileMappingsProxy
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
class MobileIconsViewModelTest : SysuiTestCase() {
|
||||
private lateinit var underTest: MobileIconsViewModel
|
||||
private val interactor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
|
||||
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var constants: ConnectivityConstants
|
||||
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
val subscriptionIdsFlow =
|
||||
interactor.filteredSubscriptions
|
||||
.map { subs -> subs.map { it.subscriptionId } }
|
||||
.stateIn(testScope.backgroundScope, SharingStarted.WhileSubscribed(), listOf())
|
||||
|
||||
underTest =
|
||||
MobileIconsViewModel(
|
||||
subscriptionIdsFlow,
|
||||
interactor,
|
||||
logger,
|
||||
constants,
|
||||
testScope.backgroundScope,
|
||||
)
|
||||
|
||||
interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `caching - mobile icon view model is reused for same sub id`() =
|
||||
testScope.runTest {
|
||||
val model1 = underTest.viewModelForSub(1, StatusBarLocation.HOME)
|
||||
val model2 = underTest.viewModelForSub(1, StatusBarLocation.QS)
|
||||
|
||||
assertThat(model1.commonImpl).isSameInstanceAs(model2.commonImpl)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `caching - invalid view models are removed from cache when sub disappears`() =
|
||||
testScope.runTest {
|
||||
// Retrieve models to trigger caching
|
||||
val model1 = underTest.viewModelForSub(1, StatusBarLocation.HOME)
|
||||
val model2 = underTest.viewModelForSub(2, StatusBarLocation.QS)
|
||||
|
||||
// Both impls are cached
|
||||
assertThat(underTest.mobileIconSubIdCache)
|
||||
.containsExactly(1, model1.commonImpl, 2, model2.commonImpl)
|
||||
|
||||
// SUB_1 is removed from the list...
|
||||
interactor.filteredSubscriptions.value = listOf(SUB_2)
|
||||
|
||||
// ... and dropped from the cache
|
||||
assertThat(underTest.mobileIconSubIdCache).containsExactly(2, model2.commonImpl)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val SUB_1 = SubscriptionModel(subscriptionId = 1, isOpportunistic = false)
|
||||
private val SUB_2 = SubscriptionModel(subscriptionId = 2, isOpportunistic = false)
|
||||
}
|
||||
}
|
||||
@@ -146,7 +146,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun activity_showActivityConfigFalse_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
whenever(wifiConstants.shouldShowActivityConfig).thenReturn(false)
|
||||
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(false)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
@@ -183,7 +183,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun activity_showActivityConfigFalse_noUpdatesReceived() = runBlocking(IMMEDIATE) {
|
||||
whenever(wifiConstants.shouldShowActivityConfig).thenReturn(false)
|
||||
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(false)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
@@ -225,7 +225,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun activity_nullSsid_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, ssid = null))
|
||||
@@ -268,7 +268,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun activity_allLocationViewModelsReceiveSameData() = runBlocking(IMMEDIATE) {
|
||||
whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
@@ -308,7 +308,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun activityIn_hasActivityInTrue_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
@@ -330,7 +330,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun activityIn_hasActivityInFalse_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
@@ -352,7 +352,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun activityOut_hasActivityOutTrue_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
@@ -374,7 +374,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun activityOut_hasActivityOutFalse_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
@@ -396,7 +396,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun activityContainer_hasActivityInTrue_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
@@ -418,7 +418,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun activityContainer_hasActivityOutTrue_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
@@ -440,7 +440,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun activityContainer_inAndOutTrue_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
@@ -462,7 +462,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun activityContainer_inAndOutFalse_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user