Merge changes I040f8c30,Ifea61ce5,Idb0fc71f,Ia121ea81,I10921ebf, ... into udc-qpr-dev

* changes:
  [Status Bar][Wifi] Protect against invalid levels from WifiTrackerLib.
  [Status Bar][Wifi] Disable wifi scanning in TrackerLibRepo.
  [Status Bar][Wifi] Add carrier merged sub ID to TrackerLibRepo.
  [Status Bar] Wifi: Add support for hotspot device types to repo.
  [Status Bar] WifiTrackerLib: Use WifiEntry.title for SSID.
  [Status Bar] Implement wifi activity in WifiRepositoryViaTrackerLib.
This commit is contained in:
Caitlin Shkuratov
2023-08-07 21:08:22 +00:00
committed by Android (Google) Code Review
14 changed files with 660 additions and 143 deletions

View File

@@ -370,6 +370,9 @@ object Flags {
@JvmField val INCOMPATIBLE_CHARGING_BATTERY_ICON =
unreleasedFlag(614, "incompatible_charging_battery_icon")
// TODO(b/293585143): Tracking Bug
val INSTANT_TETHER = unreleasedFlag(615, "instant_tether")
// 700 - dialer/calls
// TODO(b/254512734): Tracking Bug
val ONGOING_CALL_STATUS_BAR_CHIP = releasedFlag(700, "ongoing_call_status_bar_chip")

View File

@@ -49,6 +49,9 @@ interface WifiRepository {
const val COL_NAME_IS_ENABLED = "isEnabled"
/** Column name to use for [isWifiDefault] for table logging. */
const val COL_NAME_IS_DEFAULT = "isDefault"
const val CARRIER_MERGED_INVALID_SUB_ID_REASON =
"Wifi network was carrier merged but had invalid sub ID"
}
}

View File

@@ -24,6 +24,7 @@ import com.android.systemui.demomode.DemoMode.COMMAND_NETWORK
import com.android.systemui.demomode.DemoModeController
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
@@ -56,12 +57,14 @@ constructor(
val activity = getString("activity").toActivity()
val ssid = getString("ssid")
val validated = getString("fully").toBoolean()
val hotspotDeviceType = getString("hotspot").toHotspotDeviceType()
return FakeWifiEventModel.Wifi(
level = level,
activity = activity,
ssid = ssid,
validated = validated,
hotspotDeviceType,
)
}
@@ -82,6 +85,20 @@ constructor(
else -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE
}
private fun String?.toHotspotDeviceType(): WifiNetworkModel.HotspotDeviceType {
return when (this) {
null,
"none" -> WifiNetworkModel.HotspotDeviceType.NONE
"unknown" -> WifiNetworkModel.HotspotDeviceType.UNKNOWN
"phone" -> WifiNetworkModel.HotspotDeviceType.PHONE
"tablet" -> WifiNetworkModel.HotspotDeviceType.TABLET
"laptop" -> WifiNetworkModel.HotspotDeviceType.LAPTOP
"watch" -> WifiNetworkModel.HotspotDeviceType.WATCH
"auto" -> WifiNetworkModel.HotspotDeviceType.AUTO
else -> WifiNetworkModel.HotspotDeviceType.INVALID
}
}
companion object {
const val DEFAULT_CARRIER_MERGED_SUB_ID = 10
}

View File

@@ -97,6 +97,7 @@ constructor(
isValidated = validated ?: true,
level = level ?: 0,
ssid = ssid ?: DEMO_NET_SSID,
hotspotDeviceType = hotspotDeviceType,
// These fields below aren't supported in demo mode, since they aren't needed to satisfy
// the interface.

View File

@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model
import android.telephony.Annotation
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
/**
* Model for demo wifi commands, ported from [NetworkControllerImpl]
@@ -29,6 +30,8 @@ sealed interface FakeWifiEventModel {
@Annotation.DataActivityType val activity: Int,
val ssid: String?,
val validated: Boolean?,
val hotspotDeviceType: WifiNetworkModel.HotspotDeviceType =
WifiNetworkModel.HotspotDeviceType.NONE,
) : FakeWifiEventModel
data class CarrierMerged(

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
import android.net.wifi.WifiManager
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel
import java.util.concurrent.Executor
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
/**
* Object to provide shared helper functions between [WifiRepositoryImpl] and
* [WifiRepositoryViaTrackerLib].
*/
object WifiRepositoryHelper {
/** Creates a flow that fetches the [DataActivityModel] from [WifiManager]. */
fun createActivityFlow(
wifiManager: WifiManager,
@Main mainExecutor: Executor,
scope: CoroutineScope,
tableLogBuffer: TableLogBuffer,
inputLogger: (String) -> Unit,
): StateFlow<DataActivityModel> {
return conflatedCallbackFlow {
val callback =
WifiManager.TrafficStateCallback { state ->
inputLogger.invoke(prettyPrintActivity(state))
trySend(state.toWifiDataActivityModel())
}
wifiManager.registerTrafficStateCallback(mainExecutor, callback)
awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
}
.logDiffsForTable(
tableLogBuffer,
columnPrefix = ACTIVITY_PREFIX,
initialValue = ACTIVITY_DEFAULT,
)
.stateIn(
scope,
started = SharingStarted.WhileSubscribed(),
initialValue = ACTIVITY_DEFAULT,
)
}
// TODO(b/292534484): This print should only be done in [MessagePrinter] part of the log buffer.
private fun prettyPrintActivity(activity: Int): String {
return when (activity) {
WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE -> "NONE"
WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN -> "IN"
WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT -> "OUT"
WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT -> "INOUT"
else -> "INVALID"
}
}
private const val ACTIVITY_PREFIX = "wifiActivity"
val ACTIVITY_DEFAULT = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
}

View File

@@ -28,7 +28,6 @@ import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.NetworkRequest
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
import android.net.wifi.WifiManager.TrafficStateCallback
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -40,10 +39,10 @@ import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.getMainOrUnderlyingWifiInfo
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.CARRIER_MERGED_INVALID_SUB_ID_REASON
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.COL_NAME_IS_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.COL_NAME_IS_ENABLED
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryDagger
@@ -218,29 +217,15 @@ constructor(
)
override val wifiActivity: StateFlow<DataActivityModel> =
conflatedCallbackFlow {
val callback = TrafficStateCallback { state ->
logger.logActivity(prettyPrintActivity(state))
trySend(state.toWifiDataActivityModel())
}
wifiManager.registerTrafficStateCallback(mainExecutor, callback)
awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
}
.logDiffsForTable(
wifiTableLogBuffer,
columnPrefix = ACTIVITY_PREFIX,
initialValue = ACTIVITY_DEFAULT,
)
.stateIn(
scope,
started = SharingStarted.WhileSubscribed(),
initialValue = ACTIVITY_DEFAULT,
)
WifiRepositoryHelper.createActivityFlow(
wifiManager,
mainExecutor,
scope,
wifiTableLogBuffer,
logger::logActivity,
)
companion object {
private const val ACTIVITY_PREFIX = "wifiActivity"
val ACTIVITY_DEFAULT = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
// Start out with no known wifi network.
// Note: [WifiStatusTracker] (the old implementation of connectivity logic) does do an
// initial fetch to get a starting wifi network. But, it uses a deprecated API
@@ -277,6 +262,8 @@ constructor(
isValidated = networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED),
level = wifiManager.calculateSignalLevel(wifiInfo.rssi),
wifiInfo.ssid,
// This repository doesn't support any hotspot information.
WifiNetworkModel.HotspotDeviceType.NONE,
wifiInfo.isPasspointAp,
wifiInfo.isOsuAp,
wifiInfo.passpointProviderFriendlyName
@@ -284,16 +271,6 @@ constructor(
}
}
private fun prettyPrintActivity(activity: Int): String {
return when (activity) {
TrafficStateCallback.DATA_ACTIVITY_NONE -> "NONE"
TrafficStateCallback.DATA_ACTIVITY_IN -> "IN"
TrafficStateCallback.DATA_ACTIVITY_OUT -> "OUT"
TrafficStateCallback.DATA_ACTIVITY_INOUT -> "INOUT"
else -> "INVALID"
}
}
private val WIFI_NETWORK_CALLBACK_REQUEST: NetworkRequest =
NetworkRequest.Builder()
.clearCapabilities()
@@ -301,9 +278,6 @@ constructor(
.addTransportType(TRANSPORT_WIFI)
.addTransportType(TRANSPORT_CELLULAR)
.build()
private const val CARRIER_MERGED_INVALID_SUB_ID_REASON =
"Wifi network was carrier merged but had invalid sub ID"
}
@SysUISingleton

View File

@@ -17,12 +17,15 @@
package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
import android.net.wifi.WifiManager
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.table.TableLogBuffer
@@ -31,20 +34,25 @@ import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
import com.android.systemui.statusbar.pipeline.dagger.WifiTrackerLibInputLog
import com.android.systemui.statusbar.pipeline.dagger.WifiTrackerLibTableLog
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.CARRIER_MERGED_INVALID_SUB_ID_REASON
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.COL_NAME_IS_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.COL_NAME_IS_ENABLED
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryViaTrackerLibDagger
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_STATE_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel.Inactive.toHotspotDeviceType
import com.android.wifitrackerlib.HotspotNetworkEntry
import com.android.wifitrackerlib.MergedCarrierEntry
import com.android.wifitrackerlib.WifiEntry
import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX
import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN
import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE
import com.android.wifitrackerlib.WifiPickerTracker
import java.util.concurrent.Executor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
@@ -62,6 +70,7 @@ import kotlinx.coroutines.flow.stateIn
class WifiRepositoryViaTrackerLib
@Inject
constructor(
featureFlags: FeatureFlags,
@Application private val scope: CoroutineScope,
@Main private val mainExecutor: Executor,
private val wifiPickerTrackerFactory: WifiPickerTrackerFactory,
@@ -75,6 +84,8 @@ constructor(
mainExecutor.execute { it.currentState = Lifecycle.State.CREATED }
}
private val isInstantTetherEnabled = featureFlags.isEnabled(Flags.INSTANT_TETHER)
private var wifiPickerTracker: WifiPickerTracker? = null
private val wifiPickerTrackerInfo: StateFlow<WifiPickerTrackerInfo> = run {
@@ -128,19 +139,21 @@ constructor(
}
}
// TODO(b/292591403): [WifiPickerTrackerFactory] currently scans to see all
// available wifi networks every 10s. Because SysUI only needs to display the
// **connected** network, we don't need scans to be running. We should disable these
// scans (ideal) or at least run them very infrequently.
wifiPickerTracker = wifiPickerTrackerFactory.create(lifecycle, callback)
wifiPickerTracker =
wifiPickerTrackerFactory.create(lifecycle, callback).apply {
// By default, [WifiPickerTracker] will scan to see all available wifi
// networks in the area. Because SysUI only needs to display the
// **connected** network, we don't need scans to be running (and in fact,
// running scans is costly and should be avoided whenever possible).
this?.disableScanning()
}
// The lifecycle must be STARTED in order for the callback to receive events.
mainExecutor.execute { lifecycle.currentState = Lifecycle.State.STARTED }
awaitClose {
mainExecutor.execute { lifecycle.currentState = Lifecycle.State.CREATED }
}
}
// TODO(b/292534484): Update to Eagerly once scans are disabled. (Here and other flows)
.stateIn(scope, SharingStarted.WhileSubscribed(), current)
.stateIn(scope, SharingStarted.Eagerly, current)
}
override val isWifiEnabled: StateFlow<Boolean> =
@@ -153,7 +166,7 @@ constructor(
columnName = COL_NAME_IS_ENABLED,
initialValue = false,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
.stateIn(scope, SharingStarted.Eagerly, false)
override val wifiNetwork: StateFlow<WifiNetworkModel> =
wifiPickerTrackerInfo
@@ -164,7 +177,7 @@ constructor(
columnPrefix = "",
initialValue = WIFI_NETWORK_DEFAULT,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), WIFI_NETWORK_DEFAULT)
.stateIn(scope, SharingStarted.Eagerly, WIFI_NETWORK_DEFAULT)
/** Converts WifiTrackerLib's [WifiEntry] into our internal model. */
private fun WifiEntry.toWifiNetworkModel(): WifiNetworkModel {
@@ -172,30 +185,58 @@ constructor(
return WIFI_NETWORK_DEFAULT
}
return if (this is MergedCarrierEntry) {
this.convertCarrierMergedToModel()
} else {
this.convertNormalToModel()
}
}
private fun MergedCarrierEntry.convertCarrierMergedToModel(): WifiNetworkModel {
return if (this.subscriptionId == INVALID_SUBSCRIPTION_ID) {
WifiNetworkModel.Invalid(CARRIER_MERGED_INVALID_SUB_ID_REASON)
} else {
WifiNetworkModel.CarrierMerged(
networkId = NETWORK_ID,
// TODO(b/292534484): Fetch the real subscription ID from [MergedCarrierEntry].
subscriptionId = TEMP_SUB_ID,
subscriptionId = this.subscriptionId,
level = this.level,
// WifiManager APIs to calculate the signal level start from 0, so
// maxSignalLevel + 1 represents the total level buckets count.
numberOfLevels = wifiManager.maxSignalLevel + 1,
)
} else {
WifiNetworkModel.Active(
networkId = NETWORK_ID,
isValidated = this.hasInternetAccess(),
level = this.level,
ssid = this.ssid,
// TODO(b/292534484): Fetch the real values from [WifiEntry] (#getTitle might be
// appropriate).
isPasspointAccessPoint = false,
isOnlineSignUpForPasspointAccessPoint = false,
passpointProviderFriendlyName = null,
)
}
}
private fun WifiEntry.convertNormalToModel(): WifiNetworkModel {
if (this.level == WIFI_LEVEL_UNREACHABLE || this.level !in WIFI_LEVEL_MIN..WIFI_LEVEL_MAX) {
// If our level means the network is unreachable or the level is otherwise invalid, we
// don't have an active network.
return WifiNetworkModel.Inactive
}
val hotspotDeviceType =
if (isInstantTetherEnabled && this is HotspotNetworkEntry) {
this.deviceType.toHotspotDeviceType()
} else {
WifiNetworkModel.HotspotDeviceType.NONE
}
return WifiNetworkModel.Active(
networkId = NETWORK_ID,
isValidated = this.hasInternetAccess(),
level = this.level,
ssid = this.title,
hotspotDeviceType = hotspotDeviceType,
// With WifiTrackerLib, [WifiEntry.title] will appropriately fetch the SSID for
// typical wifi networks *and* passpoint/OSU APs. So, the AP-specific values can
// always be false/null in this repository.
// TODO(b/292534484): Remove these fields from the wifi network model once this
// repository is fully enabled.
isPasspointAccessPoint = false,
isOnlineSignUpForPasspointAccessPoint = false,
passpointProviderFriendlyName = null,
)
}
override val isWifiDefault: StateFlow<Boolean> =
wifiPickerTrackerInfo
.map { it.isDefault }
@@ -206,12 +247,16 @@ constructor(
columnName = COL_NAME_IS_DEFAULT,
initialValue = false,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
.stateIn(scope, SharingStarted.Eagerly, false)
// TODO(b/292534484): Re-use WifiRepositoryImpl code to implement wifi activity since
// WifiTrackerLib doesn't expose activity details.
override val wifiActivity: StateFlow<DataActivityModel> =
MutableStateFlow(DataActivityModel(false, false))
WifiRepositoryHelper.createActivityFlow(
wifiManager,
mainExecutor,
scope,
wifiTrackerLibTableLogBuffer,
this::logActivity,
)
private fun logOnWifiEntriesChanged(connectedEntry: WifiEntry?) {
inputLogger.log(
@@ -231,6 +276,10 @@ constructor(
)
}
private fun logActivity(activity: String) {
inputLogger.log(TAG, LogLevel.DEBUG, { str1 = activity }, { "onActivityChanged: $str1" })
}
/**
* Data class storing all the information fetched from [WifiPickerTracker].
*
@@ -249,6 +298,7 @@ constructor(
class Factory
@Inject
constructor(
private val featureFlags: FeatureFlags,
@Application private val scope: CoroutineScope,
@Main private val mainExecutor: Executor,
private val wifiPickerTrackerFactory: WifiPickerTrackerFactory,
@@ -257,6 +307,7 @@ constructor(
) {
fun create(wifiManager: WifiManager): WifiRepositoryViaTrackerLib {
return WifiRepositoryViaTrackerLib(
featureFlags,
scope,
mainExecutor,
wifiPickerTrackerFactory,
@@ -283,13 +334,5 @@ constructor(
* to [WifiRepositoryViaTrackerLib].
*/
private const val NETWORK_ID = -1
/**
* A temporary subscription ID until WifiTrackerLib exposes a method to fetch the
* subscription ID.
*
* Use -2 because [SubscriptionManager.INVALID_SUBSCRIPTION_ID] is -1.
*/
private const val TEMP_SUB_ID = -2
}
}

View File

@@ -17,11 +17,13 @@
package com.android.systemui.statusbar.pipeline.wifi.shared.model
import android.net.wifi.WifiManager.UNKNOWN_SSID
import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo
import android.telephony.SubscriptionManager
import androidx.annotation.VisibleForTesting
import com.android.systemui.log.table.Diffable
import com.android.systemui.log.table.TableRowLogger
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.wifitrackerlib.HotspotNetworkEntry.DeviceType
/** Provides information about the current wifi network. */
sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
@@ -52,6 +54,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
row.logChange(COL_SSID, null)
row.logChange(COL_HOTSPOT, null)
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
row.logChange(COL_ONLINE_SIGN_UP, false)
row.logChange(COL_PASSPOINT_NAME, null)
@@ -83,6 +86,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
row.logChange(COL_SSID, null)
row.logChange(COL_HOTSPOT, null)
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
row.logChange(COL_ONLINE_SIGN_UP, false)
row.logChange(COL_PASSPOINT_NAME, null)
@@ -110,6 +114,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
row.logChange(COL_SSID, null)
row.logChange(COL_HOTSPOT, null)
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
row.logChange(COL_ONLINE_SIGN_UP, false)
row.logChange(COL_PASSPOINT_NAME, null)
@@ -184,6 +189,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
row.logChange(COL_LEVEL, level)
row.logChange(COL_NUM_LEVELS, numberOfLevels)
row.logChange(COL_SSID, null)
row.logChange(COL_HOTSPOT, null)
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
row.logChange(COL_ONLINE_SIGN_UP, false)
row.logChange(COL_PASSPOINT_NAME, null)
@@ -209,6 +215,12 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
/** See [android.net.wifi.WifiInfo.ssid]. */
val ssid: String? = null,
/**
* The type of device providing a hotspot connection, or [HotspotDeviceType.NONE] if this
* isn't a hotspot connection.
*/
val hotspotDeviceType: HotspotDeviceType = WifiNetworkModel.HotspotDeviceType.NONE,
/** See [android.net.wifi.WifiInfo.isPasspointAp]. */
val isPasspointAccessPoint: Boolean = false,
@@ -247,6 +259,9 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
if (prevVal.ssid != ssid) {
row.logChange(COL_SSID, ssid)
}
if (prevVal.hotspotDeviceType != hotspotDeviceType) {
row.logChange(COL_HOTSPOT, hotspotDeviceType.name)
}
// TODO(b/238425913): The passpoint-related values are frequently never used, so it
// would be great to not log them when they're not used.
@@ -272,6 +287,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
row.logChange(COL_LEVEL, level)
row.logChange(COL_NUM_LEVELS, null)
row.logChange(COL_SSID, ssid)
row.logChange(COL_HOTSPOT, hotspotDeviceType.name)
row.logChange(COL_PASSPOINT_ACCESS_POINT, isPasspointAccessPoint)
row.logChange(COL_ONLINE_SIGN_UP, isOnlineSignUpForPasspointAccessPoint)
row.logChange(COL_PASSPOINT_NAME, passpointProviderFriendlyName)
@@ -298,13 +314,51 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
}
companion object {
// TODO(b/292534484): Use [com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX] instead
// once the migration to WifiTrackerLib is complete.
@VisibleForTesting internal const val MAX_VALID_LEVEL = 4
}
}
companion object {
// TODO(b/292534484): Use [com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN] instead
// once the migration to WifiTrackerLib is complete.
@VisibleForTesting internal const val MIN_VALID_LEVEL = 0
}
/**
* Enum for the type of device providing the hotspot connection, or [NONE] if this connection
* isn't a hotspot.
*/
enum class HotspotDeviceType {
/* This wifi connection isn't a hotspot. */
NONE,
/** The device type for this hotspot is unknown. */
UNKNOWN,
PHONE,
TABLET,
LAPTOP,
WATCH,
AUTO,
/** The device type sent for this hotspot is invalid to SysUI. */
INVALID,
}
/**
* Converts a device type from [com.android.wifitrackerlib.HotspotNetworkEntry.deviceType] to
* our internal representation.
*/
fun @receiver:DeviceType Int.toHotspotDeviceType(): HotspotDeviceType {
return when (this) {
NetworkProviderInfo.DEVICE_TYPE_UNKNOWN -> HotspotDeviceType.UNKNOWN
NetworkProviderInfo.DEVICE_TYPE_PHONE -> HotspotDeviceType.PHONE
NetworkProviderInfo.DEVICE_TYPE_TABLET -> HotspotDeviceType.TABLET
NetworkProviderInfo.DEVICE_TYPE_LAPTOP -> HotspotDeviceType.LAPTOP
NetworkProviderInfo.DEVICE_TYPE_WATCH -> HotspotDeviceType.WATCH
NetworkProviderInfo.DEVICE_TYPE_AUTO -> HotspotDeviceType.AUTO
else -> HotspotDeviceType.INVALID
}
}
}
const val TYPE_CARRIER_MERGED = "CarrierMerged"
@@ -319,6 +373,7 @@ const val COL_VALIDATED = "isValidated"
const val COL_LEVEL = "level"
const val COL_NUM_LEVELS = "maxLevel"
const val COL_SSID = "ssid"
const val COL_HOTSPOT = "hotspot"
const val COL_PASSPOINT_ACCESS_POINT = "isPasspointAccessPoint"
const val COL_ONLINE_SIGN_UP = "isOnlineSignUpForPasspointAccessPoint"
const val COL_PASSPOINT_NAME = "passpointProviderFriendlyName"

View File

@@ -419,7 +419,15 @@ public class CarrierTextManagerTest extends SysuiTestCase {
assertFalse(mWifiRepository.isWifiConnectedWithValidSsid());
mWifiRepository.setWifiNetwork(
new WifiNetworkModel.Active(0, false, 0, "", false, false, null));
new WifiNetworkModel.Active(
/* networkId= */ 0,
/* isValidated= */ false,
/* level= */ 0,
/* ssid= */ "",
/* hotspotDeviceType= */ WifiNetworkModel.HotspotDeviceType.NONE,
/* isPasspointAccessPoint= */ false,
/* isOnlineSignUpForPasspointAccessPoint= */ false,
/* passpointProviderFriendlyName= */ null));
assertTrue(mWifiRepository.isWifiConnectedWithValidSsid());
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();

View File

@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.pipeline.wifi.data.repository
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryHelper.ACTIVITY_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

View File

@@ -488,6 +488,26 @@ class WifiRepositoryImplTest : SysuiTestCase() {
assertThat(latestActive.ssid).isEqualTo(SSID)
}
@Test
fun wifiNetwork_neverHasHotspot() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiNetwork)
val wifiInfo =
mock<WifiInfo>().apply {
whenever(this.ssid).thenReturn(SSID)
whenever(this.isPrimary).thenReturn(true)
}
val network = mock<Network>().apply { whenever(this.getNetId()).thenReturn(NETWORK_ID) }
getNetworkCallback()
.onCapabilitiesChanged(network, createWifiNetworkCapabilities(wifiInfo))
assertThat(latest is WifiNetworkModel.Active).isTrue()
assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
.isEqualTo(WifiNetworkModel.HotspotDeviceType.NONE)
}
@Test
fun wifiNetwork_isCarrierMerged_flowHasCarrierMerged() =
testScope.runTest {

View File

@@ -18,13 +18,18 @@ package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
import android.net.wifi.WifiManager
import android.net.wifi.WifiManager.UNKNOWN_SSID
import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.util.concurrency.FakeExecutor
@@ -34,8 +39,13 @@ import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.android.wifitrackerlib.HotspotNetworkEntry
import com.android.wifitrackerlib.HotspotNetworkEntry.DeviceType
import com.android.wifitrackerlib.MergedCarrierEntry
import com.android.wifitrackerlib.WifiEntry
import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX
import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN
import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE
import com.android.wifitrackerlib.WifiPickerTracker
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -45,6 +55,7 @@ import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito.verify
/**
* Note: Most of these tests are duplicates of [WifiRepositoryImplTest] tests.
@@ -57,10 +68,25 @@ import org.junit.Test
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
private lateinit var underTest: WifiRepositoryViaTrackerLib
// Using lazy means that the class will only be constructed once it's fetched. Because the
// repository internally sets some values on construction, we need to set up some test
// parameters (like feature flags) *before* construction. Using lazy allows us to do that setup
// inside each test case without needing to manually recreate the repository.
private val underTest: WifiRepositoryViaTrackerLib by lazy {
WifiRepositoryViaTrackerLib(
featureFlags,
testScope.backgroundScope,
executor,
wifiPickerTrackerFactory,
wifiManager,
logger,
tableLogger,
)
}
private val executor = FakeExecutor(FakeSystemClock())
private val logger = LogBuffer("name", maxSize = 100, logcatEchoTracker = mock())
private val featureFlags = FakeFeatureFlags()
private val tableLogger = mock<TableLogBuffer>()
private val wifiManager =
mock<WifiManager>().apply { whenever(this.maxSignalLevel).thenReturn(10) }
@@ -74,11 +100,20 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
@Before
fun setUp() {
featureFlags.set(Flags.INSTANT_TETHER, false)
whenever(wifiPickerTrackerFactory.create(any(), capture(callbackCaptor)))
.thenReturn(wifiPickerTracker)
underTest = createRepo()
}
@Test
fun wifiPickerTrackerCreation_scansDisabled() =
testScope.runTest {
collectLastValue(underTest.wifiNetwork)
testScope.runCurrent()
verify(wifiPickerTracker).disableScanning()
}
@Test
fun isWifiEnabled_enabled_true() =
testScope.runTest {
@@ -238,7 +273,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(3)
whenever(this.ssid).thenReturn(SSID)
whenever(this.title).thenReturn(TITLE)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -246,7 +281,240 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(latest is WifiNetworkModel.Active).isTrue()
val latestActive = latest as WifiNetworkModel.Active
assertThat(latestActive.level).isEqualTo(3)
assertThat(latestActive.ssid).isEqualTo(SSID)
assertThat(latestActive.ssid).isEqualTo(TITLE)
}
@Test
fun accessPointInfo_alwaysFalse() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(3)
whenever(this.title).thenReturn(TITLE)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat(latest is WifiNetworkModel.Active).isTrue()
val latestActive = latest as WifiNetworkModel.Active
assertThat(latestActive.isPasspointAccessPoint).isFalse()
assertThat(latestActive.isOnlineSignUpForPasspointAccessPoint).isFalse()
assertThat(latestActive.passpointProviderFriendlyName).isNull()
}
@Test
fun wifiNetwork_unreachableLevel_inactiveNetwork() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(WIFI_LEVEL_UNREACHABLE)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat(latest).isEqualTo(WifiNetworkModel.Inactive)
}
@Test
fun wifiNetwork_levelTooHigh_inactiveNetwork() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(WIFI_LEVEL_MAX + 1)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat(latest).isEqualTo(WifiNetworkModel.Inactive)
}
@Test
fun wifiNetwork_levelTooLow_inactiveNetwork() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(WIFI_LEVEL_MIN - 1)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat(latest).isEqualTo(WifiNetworkModel.Inactive)
}
@Test
fun wifiNetwork_levelIsMax_activeNetworkWithMaxLevel() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(WIFI_LEVEL_MAX)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat(latest).isInstanceOf(WifiNetworkModel.Active::class.java)
assertThat((latest as WifiNetworkModel.Active).level).isEqualTo(WIFI_LEVEL_MAX)
}
@Test
fun wifiNetwork_levelIsMin_activeNetworkWithMinLevel() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(WIFI_LEVEL_MIN)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat(latest).isInstanceOf(WifiNetworkModel.Active::class.java)
assertThat((latest as WifiNetworkModel.Active).level).isEqualTo(WIFI_LEVEL_MIN)
}
@Test
fun wifiNetwork_notHotspot_none() =
testScope.runTest {
featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry =
mock<WifiEntry>().apply { whenever(this.isPrimaryNetwork).thenReturn(true) }
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
.isEqualTo(WifiNetworkModel.HotspotDeviceType.NONE)
}
@Test
fun wifiNetwork_hotspot_unknown() =
testScope.runTest {
featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_UNKNOWN)
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
.isEqualTo(WifiNetworkModel.HotspotDeviceType.UNKNOWN)
}
@Test
fun wifiNetwork_hotspot_phone() =
testScope.runTest {
featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_PHONE)
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
.isEqualTo(WifiNetworkModel.HotspotDeviceType.PHONE)
}
@Test
fun wifiNetwork_hotspot_tablet() =
testScope.runTest {
featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_TABLET)
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
.isEqualTo(WifiNetworkModel.HotspotDeviceType.TABLET)
}
@Test
fun wifiNetwork_hotspot_laptop() =
testScope.runTest {
featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_LAPTOP)
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
.isEqualTo(WifiNetworkModel.HotspotDeviceType.LAPTOP)
}
@Test
fun wifiNetwork_hotspot_watch() =
testScope.runTest {
featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_WATCH)
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
.isEqualTo(WifiNetworkModel.HotspotDeviceType.WATCH)
}
@Test
fun wifiNetwork_hotspot_auto() =
testScope.runTest {
featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_AUTO)
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
.isEqualTo(WifiNetworkModel.HotspotDeviceType.AUTO)
}
@Test
fun wifiNetwork_hotspot_invalid() =
testScope.runTest {
featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(1234)
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
.isEqualTo(WifiNetworkModel.HotspotDeviceType.INVALID)
}
@Test
fun wifiNetwork_hotspot_flagOff_valueNotUsed() =
testScope.runTest {
// WHEN the flag is off
featureFlags.set(Flags.INSTANT_TETHER, false)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_WATCH)
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
// THEN NONE is always used, even if the wifi entry does have a hotspot device type
assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
.isEqualTo(WifiNetworkModel.HotspotDeviceType.NONE)
}
@Test
@@ -258,6 +526,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
mock<MergedCarrierEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(3)
whenever(this.subscriptionId).thenReturn(567)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -265,7 +534,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue()
val latestMerged = latest as WifiNetworkModel.CarrierMerged
assertThat(latestMerged.level).isEqualTo(3)
// numberOfLevels = maxSignalLevel + 1
assertThat(latestMerged.subscriptionId).isEqualTo(567)
}
@Test
@@ -288,30 +557,23 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(latestMerged.numberOfLevels).isEqualTo(6)
}
/* TODO(b/292534484): Re-enable this test once WifiTrackerLib gives us the subscription ID.
@Test
fun wifiNetwork_carrierMergedButInvalidSubId_flowHasInvalid() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiNetwork)
val wifiInfo =
mock<WifiInfo>().apply {
whenever(this.isPrimary).thenReturn(true)
whenever(this.isCarrierMerged).thenReturn(true)
val wifiEntry =
mock<MergedCarrierEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getNetworkCallback()
.onCapabilitiesChanged(
NETWORK,
createWifiNetworkCapabilities(wifiInfo),
)
getCallback().onWifiEntriesChanged()
assertThat(latest).isInstanceOf(WifiNetworkModel.Invalid::class.java)
}
*/
@Test
fun wifiNetwork_notValidated_networkNotValidated() =
testScope.runTest {
@@ -382,7 +644,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(3)
whenever(this.ssid).thenReturn("AB")
whenever(this.title).thenReturn("AB")
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -397,7 +659,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(4)
whenever(this.ssid).thenReturn("CD")
whenever(this.title).thenReturn("CD")
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(newWifiEntry)
getCallback().onWifiEntriesChanged()
@@ -430,12 +692,12 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.ssid).thenReturn(SSID)
whenever(this.title).thenReturn(TITLE)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
assertThat((latest as WifiNetworkModel.Active).ssid).isEqualTo(SSID)
assertThat((latest as WifiNetworkModel.Active).ssid).isEqualTo(TITLE)
// WHEN we lose our current network
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null)
@@ -480,7 +742,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(1)
whenever(this.ssid).thenReturn(SSID)
whenever(this.title).thenReturn(TITLE)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -488,7 +750,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(latest1 is WifiNetworkModel.Active).isTrue()
val latest1Active = latest1 as WifiNetworkModel.Active
assertThat(latest1Active.level).isEqualTo(1)
assertThat(latest1Active.ssid).isEqualTo(SSID)
assertThat(latest1Active.ssid).isEqualTo(TITLE)
// WHEN we add a second subscriber after having already emitted a value
val latest2 by collectLastValue(underTest.wifiNetwork)
@@ -497,7 +759,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(latest2 is WifiNetworkModel.Active).isTrue()
val latest2Active = latest2 as WifiNetworkModel.Active
assertThat(latest2Active.level).isEqualTo(1)
assertThat(latest2Active.ssid).isEqualTo(SSID)
assertThat(latest2Active.ssid).isEqualTo(TITLE)
}
@Test
@@ -541,40 +803,15 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
}
/* TODO(b/292534484): Re-enable this test once WifiTrackerLib gives us the subscription ID.
@Test
fun isWifiConnectedWithValidSsid_invalidNetwork_false() =
testScope.runTest {
collectLastValue(underTest.wifiNetwork)
val wifiInfo =
mock<WifiInfo>().apply {
whenever(this.isPrimary).thenReturn(true)
whenever(this.isCarrierMerged).thenReturn(true)
whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID)
}
getNetworkCallback()
.onCapabilitiesChanged(
NETWORK,
createWifiNetworkCapabilities(wifiInfo),
)
testScope.runCurrent()
assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
}
*/
@Test
fun isWifiConnectedWithValidSsid_activeNetwork_nullSsid_false() =
fun isWifiConnectedWithValidSsid_invalidNetwork_false() =
testScope.runTest {
collectLastValue(underTest.wifiNetwork)
val wifiEntry =
mock<WifiEntry>().apply {
mock<MergedCarrierEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.ssid).thenReturn(null)
whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -584,14 +821,14 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
}
@Test
fun isWifiConnectedWithValidSsid_activeNetwork_unknownSsid_false() =
fun isWifiConnectedWithValidSsid_activeNetwork_nullTitle_false() =
testScope.runTest {
collectLastValue(underTest.wifiNetwork)
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.ssid).thenReturn(UNKNOWN_SSID)
whenever(this.title).thenReturn(null)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -601,14 +838,31 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
}
@Test
fun isWifiConnectedWithValidSsid_activeNetwork_validSsid_true() =
fun isWifiConnectedWithValidSsid_activeNetwork_unknownTitle_false() =
testScope.runTest {
collectLastValue(underTest.wifiNetwork)
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.ssid).thenReturn("fakeSsid")
whenever(this.title).thenReturn(UNKNOWN_SSID)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
testScope.runCurrent()
assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
}
@Test
fun isWifiConnectedWithValidSsid_activeNetwork_validTitle_true() =
testScope.runTest {
collectLastValue(underTest.wifiNetwork)
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.title).thenReturn("fakeSsid")
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -626,7 +880,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.ssid).thenReturn("fakeSsid")
whenever(this.title).thenReturn("fakeSsid")
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -643,23 +897,74 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
}
@Test
fun wifiActivity_callbackGivesNone_activityFlowHasNone() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiActivity)
getTrafficStateCallback()
.onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE)
assertThat(latest)
.isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
}
@Test
fun wifiActivity_callbackGivesIn_activityFlowHasIn() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiActivity)
getTrafficStateCallback()
.onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN)
assertThat(latest)
.isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = false))
}
@Test
fun wifiActivity_callbackGivesOut_activityFlowHasOut() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiActivity)
getTrafficStateCallback()
.onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT)
assertThat(latest)
.isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = true))
}
@Test
fun wifiActivity_callbackGivesInout_activityFlowHasInAndOut() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiActivity)
getTrafficStateCallback()
.onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT)
assertThat(latest)
.isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true))
}
private fun getCallback(): WifiPickerTracker.WifiPickerTrackerCallback {
testScope.runCurrent()
return callbackCaptor.value
}
private fun createRepo(): WifiRepositoryViaTrackerLib {
return WifiRepositoryViaTrackerLib(
testScope.backgroundScope,
executor,
wifiPickerTrackerFactory,
wifiManager,
logger,
tableLogger,
)
private fun getTrafficStateCallback(): WifiManager.TrafficStateCallback {
testScope.runCurrent()
val callbackCaptor = argumentCaptor<WifiManager.TrafficStateCallback>()
verify(wifiManager).registerTrafficStateCallback(any(), callbackCaptor.capture())
return callbackCaptor.value!!
}
private fun createHotspotWithType(@DeviceType type: Int): HotspotNetworkEntry {
return mock<HotspotNetworkEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.deviceType).thenReturn(type)
}
}
private companion object {
const val SSID = "AB"
const val TITLE = "AB"
}
}

View File

@@ -136,7 +136,8 @@ class WifiNetworkModelTest : SysuiTestCase() {
networkId = 5,
isValidated = true,
level = 3,
ssid = "Test SSID"
ssid = "Test SSID",
hotspotDeviceType = WifiNetworkModel.HotspotDeviceType.LAPTOP,
)
activeNetwork.logDiffs(prevVal = WifiNetworkModel.Inactive, logger)
@@ -146,6 +147,7 @@ class WifiNetworkModelTest : SysuiTestCase() {
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "true"))
assertThat(logger.changes).contains(Pair(COL_LEVEL, "3"))
assertThat(logger.changes).contains(Pair(COL_SSID, "Test SSID"))
assertThat(logger.changes).contains(Pair(COL_HOTSPOT, "LAPTOP"))
}
@Test
fun logDiffs_activeToInactive_resetsAllActiveFields() {
@@ -165,6 +167,7 @@ class WifiNetworkModelTest : SysuiTestCase() {
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "false"))
assertThat(logger.changes).contains(Pair(COL_LEVEL, LEVEL_DEFAULT.toString()))
assertThat(logger.changes).contains(Pair(COL_SSID, "null"))
assertThat(logger.changes).contains(Pair(COL_HOTSPOT, "null"))
}
@Test
@@ -175,7 +178,8 @@ class WifiNetworkModelTest : SysuiTestCase() {
networkId = 5,
isValidated = true,
level = 3,
ssid = "Test SSID"
ssid = "Test SSID",
hotspotDeviceType = WifiNetworkModel.HotspotDeviceType.AUTO,
)
val prevVal =
WifiNetworkModel.CarrierMerged(
@@ -191,6 +195,7 @@ class WifiNetworkModelTest : SysuiTestCase() {
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "true"))
assertThat(logger.changes).contains(Pair(COL_LEVEL, "3"))
assertThat(logger.changes).contains(Pair(COL_SSID, "Test SSID"))
assertThat(logger.changes).contains(Pair(COL_HOTSPOT, "AUTO"))
}
@Test
fun logDiffs_activeToCarrierMerged_logsAllFields() {