summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt83
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt43
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt2
8 files changed, 201 insertions, 3 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
index 681cf7254ae7..93448c1dee0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
@@ -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
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
index 04b17ed2924a..3a3e611de96a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
@@ -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
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
index ebbd77b72014..160c577042a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
@@ -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
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
index f751afc195b2..2f18ce31217e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
@@ -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
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
index 0ba0bd623c39..a64a4bd2e57a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
@@ -222,6 +222,83 @@ class WifiRepositoryImplTest : SysuiTestCase() {
}
@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
val job = underTest
@@ -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,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
index 39b886af1cb8..71b8bab87d19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
@@ -178,6 +178,29 @@ class WifiInteractorTest : SysuiTestCase() {
}
@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(
networkId = 45,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
index e56623f9fea2..7686071206f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
@@ -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,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
index 3169eef83f07..79633d467b7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
@@ -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