Merge changes I91b545e9,Iac6ce358 into udc-qpr-dev

* changes:
  [Status Bar][Wifi] Flip WIFI_TRACKER_LIB_FOR_WIFI_ICON to teamfood.
  [Status Bar][Wifi] Track secondary networks in TrackerLibRepo.
This commit is contained in:
Caitlin Shkuratov
2023-08-08 22:13:22 +00:00
committed by Android (Google) Code Review
10 changed files with 299 additions and 11 deletions

View File

@@ -369,7 +369,7 @@ object Flags {
// TODO(b/292533677): Tracking Bug
val WIFI_TRACKER_LIB_FOR_WIFI_ICON =
unreleasedFlag(613, "wifi_tracker_lib_for_wifi_icon")
unreleasedFlag(613, "wifi_tracker_lib_for_wifi_icon", teamfood = true)
// TODO(b/293863612): Tracking Bug
@JvmField val INCOMPATIBLE_CHARGING_BATTERY_ICON =
@@ -378,6 +378,9 @@ object Flags {
// TODO(b/293585143): Tracking Bug
val INSTANT_TETHER = unreleasedFlag(615, "instant_tether")
// TODO(b/294588085): Tracking Bug
val WIFI_SECONDARY_NETWORKS = unreleasedFlag(617, "wifi_secondary_networks")
// 700 - dialer/calls
// TODO(b/254512734): Tracking Bug
val ONGOING_CALL_STATUS_BAR_CHIP = releasedFlag(700, "ongoing_call_status_bar_chip")

View File

@@ -29,9 +29,18 @@ interface WifiRepository {
/** Observable for the current wifi default status. */
val isWifiDefault: StateFlow<Boolean>
/** Observable for the current wifi network. */
/** Observable for the current primary wifi network. */
val wifiNetwork: StateFlow<WifiNetworkModel>
/**
* Observable for secondary wifi networks (if any). Should specifically exclude the primary
* network emitted by [wifiNetwork].
*
* This isn't used by phones/tablets, which only display the primary network, but may be used by
* other variants like Car.
*/
val secondaryNetworks: StateFlow<List<WifiNetworkModel>>
/** Observable for the current wifi network activity. */
val wifiActivity: StateFlow<DataActivityModel>

View File

@@ -115,6 +115,11 @@ constructor(
.flatMapLatest { it.wifiNetwork }
.stateIn(scope, SharingStarted.WhileSubscribed(), realImpl.wifiNetwork.value)
override val secondaryNetworks: StateFlow<List<WifiNetworkModel>> =
activeRepo
.flatMapLatest { it.secondaryNetworks }
.stateIn(scope, SharingStarted.WhileSubscribed(), realImpl.secondaryNetworks.value)
override val wifiActivity: StateFlow<DataActivityModel> =
activeRepo
.flatMapLatest { it.wifiActivity }

View File

@@ -48,6 +48,9 @@ constructor(
private val _wifiNetwork = MutableStateFlow<WifiNetworkModel>(WifiNetworkModel.Inactive)
override val wifiNetwork: StateFlow<WifiNetworkModel> = _wifiNetwork
private val _secondaryNetworks = MutableStateFlow<List<WifiNetworkModel>>(emptyList())
override val secondaryNetworks: StateFlow<List<WifiNetworkModel>> = _secondaryNetworks
private val _wifiActivity =
MutableStateFlow(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
override val wifiActivity: StateFlow<DataActivityModel> = _wifiActivity

View File

@@ -43,6 +43,9 @@ class DisabledWifiRepository @Inject constructor() :
override val wifiNetwork: StateFlow<WifiNetworkModel> = MutableStateFlow(NETWORK).asStateFlow()
override val secondaryNetworks: StateFlow<List<WifiNetworkModel>> =
MutableStateFlow(emptyList<WifiNetworkModel>()).asStateFlow()
override val wifiActivity: StateFlow<DataActivityModel> =
MutableStateFlow(ACTIVITY).asStateFlow()

View File

@@ -56,8 +56,10 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
@@ -216,6 +218,10 @@ constructor(
initialValue = WIFI_NETWORK_DEFAULT,
)
// Secondary networks can only be supported by [WifiRepositoryViaTrackerLib].
override val secondaryNetworks: StateFlow<List<WifiNetworkModel>> =
MutableStateFlow(emptyList<WifiNetworkModel>()).asStateFlow()
override val wifiActivity: StateFlow<DataActivityModel> =
WifiRepositoryHelper.createActivityFlow(
wifiManager,

View File

@@ -93,7 +93,8 @@ constructor(
WifiPickerTrackerInfo(
state = WIFI_STATE_DEFAULT,
isDefault = false,
network = WIFI_NETWORK_DEFAULT,
primaryNetwork = WIFI_NETWORK_DEFAULT,
secondaryNetworks = emptyList(),
)
callbackFlow {
val callback =
@@ -102,6 +103,17 @@ constructor(
val connectedEntry = wifiPickerTracker?.connectedWifiEntry
logOnWifiEntriesChanged(connectedEntry)
val secondaryNetworks =
if (featureFlags.isEnabled(Flags.WIFI_SECONDARY_NETWORKS)) {
val activeNetworks =
wifiPickerTracker?.activeWifiEntries ?: emptyList()
activeNetworks
.filter { it != connectedEntry && !it.isPrimaryNetwork }
.map { it.toWifiNetworkModel() }
} else {
emptyList()
}
// [WifiPickerTracker.connectedWifiEntry] will return the same instance
// but with updated internals. For example, when its validation status
// changes from false to true, the same instance is re-used but with the
@@ -112,8 +124,9 @@ constructor(
// into our internal model immediately. [toWifiNetworkModel] always
// returns a new instance, so the flow is guaranteed to emit.
send(
newNetwork = connectedEntry?.toWifiNetworkModel()
newPrimaryNetwork = connectedEntry?.toPrimaryWifiNetworkModel()
?: WIFI_NETWORK_DEFAULT,
newSecondaryNetworks = secondaryNetworks,
newIsDefault = connectedEntry?.isDefaultNetwork ?: false,
)
}
@@ -131,9 +144,17 @@ constructor(
private fun send(
newState: Int = current.state,
newIsDefault: Boolean = current.isDefault,
newNetwork: WifiNetworkModel = current.network,
newPrimaryNetwork: WifiNetworkModel = current.primaryNetwork,
newSecondaryNetworks: List<WifiNetworkModel> =
current.secondaryNetworks,
) {
val new = WifiPickerTrackerInfo(newState, newIsDefault, newNetwork)
val new =
WifiPickerTrackerInfo(
newState,
newIsDefault,
newPrimaryNetwork,
newSecondaryNetworks,
)
current = new
trySend(new)
}
@@ -170,7 +191,7 @@ constructor(
override val wifiNetwork: StateFlow<WifiNetworkModel> =
wifiPickerTrackerInfo
.map { it.network }
.map { it.primaryNetwork }
.distinctUntilChanged()
.logDiffsForTable(
wifiTrackerLibTableLogBuffer,
@@ -179,11 +200,32 @@ constructor(
)
.stateIn(scope, SharingStarted.Eagerly, WIFI_NETWORK_DEFAULT)
override val secondaryNetworks: StateFlow<List<WifiNetworkModel>> =
wifiPickerTrackerInfo
.map { it.secondaryNetworks }
.distinctUntilChanged()
.logDiffsForTable(
wifiTrackerLibTableLogBuffer,
columnPrefix = "",
columnName = "secondaryNetworks",
initialValue = emptyList(),
)
.stateIn(scope, SharingStarted.Eagerly, emptyList())
/**
* Converts WifiTrackerLib's [WifiEntry] into our internal model only if the entry is the
* primary network. Returns an inactive network if it's not primary.
*/
private fun WifiEntry.toPrimaryWifiNetworkModel(): WifiNetworkModel {
return if (!this.isPrimaryNetwork) {
WIFI_NETWORK_DEFAULT
} else {
this.toWifiNetworkModel()
}
}
/** Converts WifiTrackerLib's [WifiEntry] into our internal model. */
private fun WifiEntry.toWifiNetworkModel(): WifiNetworkModel {
if (!this.isPrimaryNetwork) {
return WIFI_NETWORK_DEFAULT
}
return if (this is MergedCarrierEntry) {
this.convertCarrierMergedToModel()
} else {
@@ -291,7 +333,9 @@ constructor(
/** True if wifi is currently the default connection and false otherwise. */
val isDefault: Boolean,
/** The currently primary wifi network. */
val network: WifiNetworkModel,
val primaryNetwork: WifiNetworkModel,
/** The current secondary network(s), if any. Specifically excludes the primary network. */
val secondaryNetworks: List<WifiNetworkModel>
)
@SysUISingleton

View File

@@ -34,6 +34,8 @@ class FakeWifiRepository : WifiRepository {
MutableStateFlow(WifiNetworkModel.Inactive)
override val wifiNetwork: StateFlow<WifiNetworkModel> = _wifiNetwork
override val secondaryNetworks = MutableStateFlow<List<WifiNetworkModel>>(emptyList())
private val _wifiActivity = MutableStateFlow(ACTIVITY_DEFAULT)
override val wifiActivity: StateFlow<DataActivityModel> = _wifiActivity

View File

@@ -1003,6 +1003,27 @@ class WifiRepositoryImplTest : SysuiTestCase() {
assertThat(latest2Active.ssid).isEqualTo(SSID)
}
@Test
fun secondaryNetworks_alwaysEmpty() =
testScope.runTest {
val latest by collectLastValue(underTest.secondaryNetworks)
collectLastValue(underTest.wifiNetwork)
// Even WHEN we do have non-primary wifi info
val wifiInfo =
mock<WifiInfo>().apply {
whenever(this.ssid).thenReturn(SSID)
whenever(this.isPrimary).thenReturn(false)
}
val network = mock<Network>().apply { whenever(this.getNetId()).thenReturn(NETWORK_ID) }
getNetworkCallback()
.onCapabilitiesChanged(network, createWifiNetworkCapabilities(wifiInfo))
// THEN the secondary networks list is empty because this repo doesn't support it
assertThat(latest).isEmpty()
}
@Test
fun isWifiConnectedWithValidSsid_inactiveNetwork_false() =
testScope.runTest {

View File

@@ -101,6 +101,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
@Before
fun setUp() {
featureFlags.set(Flags.INSTANT_TETHER, false)
featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, false)
whenever(wifiPickerTrackerFactory.create(any(), capture(callbackCaptor)))
.thenReturn(wifiPickerTracker)
}
@@ -762,6 +763,197 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(latest2Active.ssid).isEqualTo(TITLE)
}
@Test
fun secondaryNetworks_activeEntriesEmpty_isEmpty() =
testScope.runTest {
featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf())
getCallback().onWifiEntriesChanged()
assertThat(latest).isEmpty()
}
@Test
fun secondaryNetworks_oneActiveEntry_hasOne() =
testScope.runTest {
featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val wifiEntry = mock<WifiEntry>()
whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf(wifiEntry))
getCallback().onWifiEntriesChanged()
assertThat(latest).hasSize(1)
}
@Test
fun secondaryNetworks_multipleActiveEntries_hasMultiple() =
testScope.runTest {
featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val wifiEntry1 = mock<WifiEntry>()
val wifiEntry2 = mock<WifiEntry>()
whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf(wifiEntry1, wifiEntry2))
getCallback().onWifiEntriesChanged()
assertThat(latest).hasSize(2)
}
@Test
fun secondaryNetworks_mapsToInactive() =
testScope.runTest {
featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val inactiveEntry =
mock<WifiEntry>().apply { whenever(this.level).thenReturn(WIFI_LEVEL_UNREACHABLE) }
whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf(inactiveEntry))
getCallback().onWifiEntriesChanged()
assertThat(latest).hasSize(1)
assertThat(latest!![0]).isInstanceOf(WifiNetworkModel.Inactive::class.java)
}
@Test
fun secondaryNetworks_mapsToActive() =
testScope.runTest {
featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val activeEntry = mock<WifiEntry>().apply { whenever(this.level).thenReturn(2) }
whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf(activeEntry))
getCallback().onWifiEntriesChanged()
assertThat(latest).hasSize(1)
assertThat(latest!![0]).isInstanceOf(WifiNetworkModel.Active::class.java)
assertThat((latest!![0] as WifiNetworkModel.Active).level).isEqualTo(2)
}
@Test
fun secondaryNetworks_mapsToCarrierMerged() =
testScope.runTest {
featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val carrierMergedEntry =
mock<MergedCarrierEntry>().apply { whenever(this.level).thenReturn(3) }
whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf(carrierMergedEntry))
getCallback().onWifiEntriesChanged()
assertThat(latest).hasSize(1)
assertThat(latest!![0]).isInstanceOf(WifiNetworkModel.CarrierMerged::class.java)
assertThat((latest!![0] as WifiNetworkModel.CarrierMerged).level).isEqualTo(3)
}
@Test
fun secondaryNetworks_mapsMultipleInOrder() =
testScope.runTest {
featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val activeEntry = mock<WifiEntry>().apply { whenever(this.level).thenReturn(2) }
val carrierMergedEntry =
mock<MergedCarrierEntry>().apply { whenever(this.level).thenReturn(3) }
whenever(wifiPickerTracker.activeWifiEntries)
.thenReturn(listOf(activeEntry, carrierMergedEntry))
getCallback().onWifiEntriesChanged()
assertThat(latest!![0]).isInstanceOf(WifiNetworkModel.Active::class.java)
assertThat((latest!![0] as WifiNetworkModel.Active).level).isEqualTo(2)
assertThat(latest!![1]).isInstanceOf(WifiNetworkModel.CarrierMerged::class.java)
assertThat((latest!![1] as WifiNetworkModel.CarrierMerged).level).isEqualTo(3)
}
@Test
fun secondaryNetworks_filtersOutConnectedEntry() =
testScope.runTest {
featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val connectedEntry = mock<WifiEntry>().apply { whenever(this.level).thenReturn(1) }
val secondaryEntry1 = mock<WifiEntry>().apply { whenever(this.level).thenReturn(2) }
val secondaryEntry2 = mock<WifiEntry>().apply { whenever(this.level).thenReturn(3) }
// WHEN the active list has both a primary and secondary networks
whenever(wifiPickerTracker.activeWifiEntries)
.thenReturn(listOf(connectedEntry, secondaryEntry1, secondaryEntry2))
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(connectedEntry)
getCallback().onWifiEntriesChanged()
// THEN only the secondary networks are included
assertThat(latest).hasSize(2)
assertThat((latest!![0] as WifiNetworkModel.Active).level).isEqualTo(2)
assertThat((latest!![1] as WifiNetworkModel.Active).level).isEqualTo(3)
}
@Test
fun secondaryNetworks_noConnectedEntry_hasAllActiveEntries() =
testScope.runTest {
featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val secondaryEntry1 = mock<WifiEntry>().apply { whenever(this.level).thenReturn(2) }
val secondaryEntry2 = mock<WifiEntry>().apply { whenever(this.level).thenReturn(3) }
whenever(wifiPickerTracker.activeWifiEntries)
.thenReturn(listOf(secondaryEntry1, secondaryEntry2))
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null)
getCallback().onWifiEntriesChanged()
assertThat(latest).hasSize(2)
assertThat((latest!![0] as WifiNetworkModel.Active).level).isEqualTo(2)
assertThat((latest!![1] as WifiNetworkModel.Active).level).isEqualTo(3)
}
@Test
fun secondaryNetworks_filtersOutPrimaryNetwork() =
testScope.runTest {
featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val primaryEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(1)
}
val secondaryEntry1 = mock<WifiEntry>().apply { whenever(this.level).thenReturn(2) }
val secondaryEntry2 = mock<WifiEntry>().apply { whenever(this.level).thenReturn(3) }
// WHEN the active list has both a primary and secondary networks
whenever(wifiPickerTracker.activeWifiEntries)
.thenReturn(listOf(secondaryEntry1, primaryEntry, secondaryEntry2))
getCallback().onWifiEntriesChanged()
// THEN only the secondary networks are included
assertThat(latest).hasSize(2)
assertThat((latest!![0] as WifiNetworkModel.Active).level).isEqualTo(2)
assertThat((latest!![1] as WifiNetworkModel.Active).level).isEqualTo(3)
}
@Test
fun secondaryNetworks_flagOff_noNetworks() =
testScope.runTest {
featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, false)
val latest by collectLastValue(underTest.secondaryNetworks)
val wifiEntry = mock<WifiEntry>()
whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf(wifiEntry))
getCallback().onWifiEntriesChanged()
assertThat(latest).isEmpty()
}
@Test
fun isWifiConnectedWithValidSsid_inactiveNetwork_false() =
testScope.runTest {