[SB Refactor] Migrate the isWifiDefault bit to the new pipeline.
This migrates WifiStatusTracker's `isDefaultNetwork` tracking, and WifiSignalController's `wifiVisible` calculation. Bug: 238425913 Test: manual: Turn wifi off then back on, verify that wifi icon shows up as soon as wifi becomes default again. Test: statusbar.pipeline tests Change-Id: Ice2bbb217e5c834ccef9905dca0ce47388775c67
This commit is contained in:
@@ -39,7 +39,6 @@ import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
|
||||
import java.util.concurrent.Executor
|
||||
@@ -64,6 +63,9 @@ interface WifiRepository {
|
||||
/** Observable for the current wifi enabled status. */
|
||||
val isWifiEnabled: StateFlow<Boolean>
|
||||
|
||||
/** Observable for the current wifi default status. */
|
||||
val isWifiDefault: StateFlow<Boolean>
|
||||
|
||||
/** Observable for the current wifi network. */
|
||||
val wifiNetwork: StateFlow<WifiNetworkModel>
|
||||
|
||||
@@ -103,7 +105,7 @@ class WifiRepositoryImpl @Inject constructor(
|
||||
merge(wifiNetworkChangeEvents, wifiStateChangeEvents)
|
||||
.mapLatest { wifiManager.isWifiEnabled }
|
||||
.distinctUntilChanged()
|
||||
.logOutputChange(logger, "enabled")
|
||||
.logInputChange(logger, "enabled")
|
||||
.stateIn(
|
||||
scope = scope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
@@ -111,6 +113,39 @@ class WifiRepositoryImpl @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
override val isWifiDefault: StateFlow<Boolean> = conflatedCallbackFlow {
|
||||
// Note: This callback doesn't do any logging because we already log every network change
|
||||
// in the [wifiNetwork] callback.
|
||||
val callback = object : ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
|
||||
override fun onCapabilitiesChanged(
|
||||
network: Network,
|
||||
networkCapabilities: NetworkCapabilities
|
||||
) {
|
||||
// This method will always be called immediately after the network becomes the
|
||||
// default, in addition to any time the capabilities change while the network is
|
||||
// the default.
|
||||
// If this network contains valid wifi info, then wifi is the default network.
|
||||
val wifiInfo = networkCapabilitiesToWifiInfo(networkCapabilities)
|
||||
trySend(wifiInfo != null)
|
||||
}
|
||||
|
||||
override fun onLost(network: Network) {
|
||||
// The system no longer has a default network, so wifi is definitely not default.
|
||||
trySend(false)
|
||||
}
|
||||
}
|
||||
|
||||
connectivityManager.registerDefaultNetworkCallback(callback)
|
||||
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.logInputChange(logger, "isWifiDefault")
|
||||
.stateIn(
|
||||
scope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue = false
|
||||
)
|
||||
|
||||
override val wifiNetwork: StateFlow<WifiNetworkModel> = conflatedCallbackFlow {
|
||||
var currentWifi: WifiNetworkModel = WIFI_NETWORK_DEFAULT
|
||||
|
||||
|
||||
@@ -59,6 +59,9 @@ class WifiInteractor @Inject constructor(
|
||||
/** Our current enabled status. */
|
||||
val isEnabled: Flow<Boolean> = wifiRepository.isWifiEnabled
|
||||
|
||||
/** Our current default status. */
|
||||
val isDefault: Flow<Boolean> = wifiRepository.isWifiDefault
|
||||
|
||||
/** Our current wifi network. See [WifiNetworkModel]. */
|
||||
val wifiNetwork: Flow<WifiNetworkModel> = wifiRepository.wifiNetwork
|
||||
|
||||
|
||||
@@ -124,9 +124,10 @@ constructor(
|
||||
private val wifiIcon: StateFlow<Icon.Resource?> =
|
||||
combine(
|
||||
interactor.isEnabled,
|
||||
interactor.isDefault,
|
||||
interactor.isForceHidden,
|
||||
interactor.wifiNetwork,
|
||||
) { isEnabled, isForceHidden, wifiNetwork ->
|
||||
) { isEnabled, isDefault, isForceHidden, wifiNetwork ->
|
||||
if (!isEnabled || isForceHidden || wifiNetwork is WifiNetworkModel.CarrierMerged) {
|
||||
return@combine null
|
||||
}
|
||||
@@ -135,6 +136,7 @@ constructor(
|
||||
val icon = Icon.Resource(iconResId, wifiNetwork.contentDescription())
|
||||
|
||||
return@combine when {
|
||||
isDefault -> icon
|
||||
wifiConstants.alwaysShowIconIfEnabled -> icon
|
||||
!connectivityConstants.hasDataCapabilities -> icon
|
||||
wifiNetwork is WifiNetworkModel.Active && wifiNetwork.isValidated -> icon
|
||||
|
||||
@@ -27,6 +27,9 @@ class FakeWifiRepository : WifiRepository {
|
||||
private val _isWifiEnabled: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||
override val isWifiEnabled: StateFlow<Boolean> = _isWifiEnabled
|
||||
|
||||
private val _isWifiDefault: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||
override val isWifiDefault: StateFlow<Boolean> = _isWifiDefault
|
||||
|
||||
private val _wifiNetwork: MutableStateFlow<WifiNetworkModel> =
|
||||
MutableStateFlow(WifiNetworkModel.Inactive)
|
||||
override val wifiNetwork: StateFlow<WifiNetworkModel> = _wifiNetwork
|
||||
@@ -38,6 +41,10 @@ class FakeWifiRepository : WifiRepository {
|
||||
_isWifiEnabled.value = enabled
|
||||
}
|
||||
|
||||
fun setIsWifiDefault(default: Boolean) {
|
||||
_isWifiDefault.value = default
|
||||
}
|
||||
|
||||
fun setWifiNetwork(wifiNetworkModel: WifiNetworkModel) {
|
||||
_wifiNetwork.value = wifiNetworkModel
|
||||
}
|
||||
|
||||
@@ -221,6 +221,83 @@ class WifiRepositoryImplTest : SysuiTestCase() {
|
||||
enabledJob.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isWifiDefault_initiallyGetsDefault() = runBlocking(IMMEDIATE) {
|
||||
val job = underTest.isWifiDefault.launchIn(this)
|
||||
|
||||
assertThat(underTest.isWifiDefault.value).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isWifiDefault_wifiNetwork_isTrue() = runBlocking(IMMEDIATE) {
|
||||
val job = underTest.isWifiDefault.launchIn(this)
|
||||
|
||||
val wifiInfo = mock<WifiInfo>().apply {
|
||||
whenever(this.ssid).thenReturn(SSID)
|
||||
}
|
||||
|
||||
getDefaultNetworkCallback().onCapabilitiesChanged(
|
||||
NETWORK,
|
||||
createWifiNetworkCapabilities(wifiInfo)
|
||||
)
|
||||
|
||||
assertThat(underTest.isWifiDefault.value).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isWifiDefault_cellularVcnNetwork_isTrue() = runBlocking(IMMEDIATE) {
|
||||
val job = underTest.isWifiDefault.launchIn(this)
|
||||
|
||||
val capabilities = mock<NetworkCapabilities>().apply {
|
||||
whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
|
||||
whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO))
|
||||
}
|
||||
|
||||
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
|
||||
|
||||
assertThat(underTest.isWifiDefault.value).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isWifiDefault_cellularNotVcnNetwork_isFalse() = runBlocking(IMMEDIATE) {
|
||||
val job = underTest.isWifiDefault.launchIn(this)
|
||||
|
||||
val capabilities = mock<NetworkCapabilities>().apply {
|
||||
whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
|
||||
whenever(this.transportInfo).thenReturn(mock())
|
||||
}
|
||||
|
||||
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
|
||||
|
||||
assertThat(underTest.isWifiDefault.value).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isWifiDefault_wifiNetworkLost_isFalse() = runBlocking(IMMEDIATE) {
|
||||
val job = underTest.isWifiDefault.launchIn(this)
|
||||
|
||||
// First, add a network
|
||||
getDefaultNetworkCallback()
|
||||
.onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
|
||||
assertThat(underTest.isWifiDefault.value).isTrue()
|
||||
|
||||
// WHEN the network is lost
|
||||
getDefaultNetworkCallback().onLost(NETWORK)
|
||||
|
||||
// THEN we update to false
|
||||
assertThat(underTest.isWifiDefault.value).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiNetwork_initiallyGetsDefault() = runBlocking(IMMEDIATE) {
|
||||
var latest: WifiNetworkModel? = null
|
||||
@@ -745,6 +822,12 @@ class WifiRepositoryImplTest : SysuiTestCase() {
|
||||
return callbackCaptor.value!!
|
||||
}
|
||||
|
||||
private fun getDefaultNetworkCallback(): ConnectivityManager.NetworkCallback {
|
||||
val callbackCaptor = argumentCaptor<ConnectivityManager.NetworkCallback>()
|
||||
verify(connectivityManager).registerDefaultNetworkCallback(callbackCaptor.capture())
|
||||
return callbackCaptor.value!!
|
||||
}
|
||||
|
||||
private fun createWifiNetworkCapabilities(
|
||||
wifiInfo: WifiInfo,
|
||||
isValidated: Boolean = true,
|
||||
|
||||
@@ -177,6 +177,29 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isDefault_matchesRepoIsDefault() = runBlocking(IMMEDIATE) {
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isDefault
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
wifiRepository.setIsWifiDefault(true)
|
||||
yield()
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
wifiRepository.setIsWifiDefault(false)
|
||||
yield()
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
wifiRepository.setIsWifiDefault(true)
|
||||
yield()
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiNetwork_matchesRepoWifiNetwork() = runBlocking(IMMEDIATE) {
|
||||
val wifiNetwork = WifiNetworkModel.Active(
|
||||
|
||||
@@ -88,6 +88,7 @@ internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase
|
||||
fun wifiIcon() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setIsWifiEnabled(testCase.enabled)
|
||||
wifiRepository.setIsWifiDefault(testCase.isDefault)
|
||||
connectivityRepository.setForceHiddenIcons(
|
||||
if (testCase.forceHidden) {
|
||||
setOf(ConnectivitySlot.WIFI)
|
||||
@@ -152,6 +153,7 @@ internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase
|
||||
val forceHidden: Boolean = false,
|
||||
val alwaysShowIconWhenEnabled: Boolean = false,
|
||||
val hasDataCapabilities: Boolean = true,
|
||||
val isDefault: Boolean = false,
|
||||
val network: WifiNetworkModel,
|
||||
|
||||
/** The expected output. Null if we expect the output to be null. */
|
||||
@@ -162,6 +164,7 @@ internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase
|
||||
"forceHidden=$forceHidden, " +
|
||||
"showWhenEnabled=$alwaysShowIconWhenEnabled, " +
|
||||
"hasDataCaps=$hasDataCapabilities, " +
|
||||
"isDefault=$isDefault, " +
|
||||
"network=$network) then " +
|
||||
"EXPECTED($expected)"
|
||||
}
|
||||
@@ -296,6 +299,46 @@ internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase
|
||||
),
|
||||
),
|
||||
|
||||
// isDefault = true => all Inactive and Active networks shown
|
||||
TestCase(
|
||||
isDefault = true,
|
||||
network = WifiNetworkModel.Inactive,
|
||||
expected =
|
||||
Expected(
|
||||
iconResource = WIFI_NO_NETWORK,
|
||||
contentDescription = { context ->
|
||||
"${context.getString(WIFI_NO_CONNECTION)}," +
|
||||
context.getString(NO_INTERNET)
|
||||
},
|
||||
description = "No network icon",
|
||||
),
|
||||
),
|
||||
TestCase(
|
||||
isDefault = true,
|
||||
network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 3),
|
||||
expected =
|
||||
Expected(
|
||||
iconResource = WIFI_NO_INTERNET_ICONS[3],
|
||||
contentDescription = { context ->
|
||||
"${context.getString(WIFI_CONNECTION_STRENGTH[3])}," +
|
||||
context.getString(NO_INTERNET)
|
||||
},
|
||||
description = "No internet level 3 icon",
|
||||
),
|
||||
),
|
||||
TestCase(
|
||||
isDefault = true,
|
||||
network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 1),
|
||||
expected =
|
||||
Expected(
|
||||
iconResource = WIFI_FULL_ICONS[1],
|
||||
contentDescription = { context ->
|
||||
context.getString(WIFI_CONNECTION_STRENGTH[1])
|
||||
},
|
||||
description = "Full internet level 1 icon",
|
||||
),
|
||||
),
|
||||
|
||||
// network = CarrierMerged => not shown
|
||||
TestCase(
|
||||
network = WifiNetworkModel.CarrierMerged,
|
||||
|
||||
@@ -76,6 +76,8 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
scope.cancel()
|
||||
}
|
||||
|
||||
// See [WifiViewModelIconParameterizedTest] for additional view model tests.
|
||||
|
||||
// Note on testing: [WifiViewModel] exposes 3 different instances of
|
||||
// [LocationBasedWifiViewModel]. In practice, these 3 different instances will get the exact
|
||||
// same data for icon, activity, etc. flows. So, most of these tests will test just one of the
|
||||
|
||||
Reference in New Issue
Block a user