[SB Refactor] Display the activity in and out icons using the new pipeline.
Bug: 238425913 Test: manual: Verified activity icons show and hide as the actual activity changes (see video in b/238425913#comment28) Test: statusbar.pipeline tests Change-Id: I454555db129fce0e7e168d55148c304ba43122c0
This commit is contained in:
@@ -133,7 +133,7 @@ class ConnectivityPipelineLogger @Inject constructor(
|
||||
* @param prettyPrint an optional function to transform the value into a readable string.
|
||||
* [toString] is used if no custom function is provided.
|
||||
*/
|
||||
fun <T : Any> Flow<T>.logOutputChange(
|
||||
fun <T> Flow<T>.logOutputChange(
|
||||
logger: ConnectivityPipelineLogger,
|
||||
outputParamName: String,
|
||||
prettyPrint: (T) -> String = { it.toString() }
|
||||
|
||||
@@ -36,8 +36,8 @@ import com.android.systemui.dagger.qualifiers.Application
|
||||
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.wifi.data.model.WifiActivityModel
|
||||
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
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
@@ -22,9 +22,10 @@ import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlo
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
|
||||
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
/**
|
||||
@@ -38,7 +39,11 @@ class WifiInteractor @Inject constructor(
|
||||
connectivityRepository: ConnectivityRepository,
|
||||
wifiRepository: WifiRepository,
|
||||
) {
|
||||
private val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
|
||||
/**
|
||||
* The SSID (service set identifier) of the wifi network. Null if we don't have a network, or
|
||||
* have a network but no valid SSID.
|
||||
*/
|
||||
val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
|
||||
when (info) {
|
||||
is WifiNetworkModel.Inactive -> null
|
||||
is WifiNetworkModel.CarrierMerged -> null
|
||||
@@ -54,14 +59,11 @@ class WifiInteractor @Inject constructor(
|
||||
/** Our current wifi network. See [WifiNetworkModel]. */
|
||||
val wifiNetwork: Flow<WifiNetworkModel> = wifiRepository.wifiNetwork
|
||||
|
||||
/** Our current wifi activity. See [WifiActivityModel]. */
|
||||
val activity: StateFlow<WifiActivityModel> = wifiRepository.wifiActivity
|
||||
|
||||
/** True if we're configured to force-hide the wifi icon and false otherwise. */
|
||||
val isForceHidden: Flow<Boolean> = connectivityRepository.forceHiddenSlots.map {
|
||||
it.contains(ConnectivitySlot.WIFI)
|
||||
}
|
||||
|
||||
/** True if our wifi network has activity in (download), and false otherwise. */
|
||||
val hasActivityIn: Flow<Boolean> =
|
||||
combine(wifiRepository.wifiActivity, ssid) { activity, ssid ->
|
||||
activity.hasActivityIn && ssid != null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.wifi.data.model
|
||||
package com.android.systemui.statusbar.pipeline.wifi.shared.model
|
||||
|
||||
/**
|
||||
* Provides information on the current wifi activity.
|
||||
*/
|
||||
/** Provides information on the current wifi activity. */
|
||||
data class WifiActivityModel(
|
||||
/** True if the wifi has activity in (download). */
|
||||
val hasActivityIn: Boolean,
|
||||
@@ -48,6 +48,9 @@ object WifiViewBinder {
|
||||
viewModel: WifiViewModel,
|
||||
) {
|
||||
val iconView = view.requireViewById<ImageView>(R.id.wifi_signal)
|
||||
val activityInView = view.requireViewById<ImageView>(R.id.wifi_in)
|
||||
val activityOutView = view.requireViewById<ImageView>(R.id.wifi_out)
|
||||
val activityContainerView = view.requireViewById<View>(R.id.inout_container)
|
||||
|
||||
view.isVisible = true
|
||||
iconView.isVisible = true
|
||||
@@ -61,20 +64,37 @@ object WifiViewBinder {
|
||||
// [ModernStatusBarWifiView.isIconVisible], which is what actually makes
|
||||
// the view GONE.
|
||||
view.isVisible = wifiIcon != null
|
||||
wifiIcon?.let {
|
||||
IconViewBinder.bind(wifiIcon, iconView)
|
||||
}
|
||||
wifiIcon?.let { IconViewBinder.bind(wifiIcon, iconView) }
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.tint.collect { tint ->
|
||||
iconView.imageTintList = ColorStateList.valueOf(tint)
|
||||
val tintList = ColorStateList.valueOf(tint)
|
||||
iconView.imageTintList = tintList
|
||||
activityInView.imageTintList = tintList
|
||||
activityOutView.imageTintList = tintList
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.isActivityInViewVisible.distinctUntilChanged().collect { visible ->
|
||||
activityInView.isVisible = visible
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.isActivityOutViewVisible.distinctUntilChanged().collect { visible ->
|
||||
activityOutView.isVisible = visible
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.isActivityContainerVisible.distinctUntilChanged().collect { visible ->
|
||||
activityContainerView.isVisible = visible
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/238425913): Hook up to [viewModel] to render actual changes to the wifi icon.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,9 +35,11 @@ import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
|
||||
import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
|
||||
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
@@ -46,11 +48,11 @@ import kotlinx.coroutines.flow.map
|
||||
* Models the UI state for the status bar wifi icon.
|
||||
*/
|
||||
class WifiViewModel @Inject constructor(
|
||||
statusBarPipelineFlags: StatusBarPipelineFlags,
|
||||
private val constants: WifiConstants,
|
||||
constants: WifiConstants,
|
||||
private val context: Context,
|
||||
private val logger: ConnectivityPipelineLogger,
|
||||
private val interactor: WifiInteractor,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
interactor: WifiInteractor,
|
||||
statusBarPipelineFlags: StatusBarPipelineFlags,
|
||||
) {
|
||||
/**
|
||||
* The drawable resource ID to use for the wifi icon. Null if we shouldn't display any icon.
|
||||
@@ -109,17 +111,36 @@ class WifiViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the activity in icon should be displayed and false otherwise.
|
||||
*/
|
||||
val isActivityInVisible: Flow<Boolean>
|
||||
get() =
|
||||
if (!constants.shouldShowActivityConfig) {
|
||||
flowOf(false)
|
||||
} else {
|
||||
interactor.hasActivityIn
|
||||
/** The wifi activity status. Null if we shouldn't display the activity status. */
|
||||
private val activity: Flow<WifiActivityModel?> =
|
||||
if (!constants.shouldShowActivityConfig) {
|
||||
flowOf(null)
|
||||
} else {
|
||||
combine(interactor.activity, interactor.ssid) { activity, ssid ->
|
||||
when (ssid) {
|
||||
null -> null
|
||||
else -> activity
|
||||
}
|
||||
}
|
||||
.logOutputChange(logger, "activityInVisible")
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.logOutputChange(logger, "activity")
|
||||
|
||||
/** True if the activity in view should be visible. */
|
||||
val isActivityInViewVisible: Flow<Boolean> = activity.map { it?.hasActivityIn == true }
|
||||
|
||||
/** True if the activity out view should be visible. */
|
||||
val isActivityOutViewVisible: Flow<Boolean> = activity.map { it?.hasActivityOut == true }
|
||||
|
||||
/** True if the activity container view should be visible. */
|
||||
val isActivityContainerVisible: Flow<Boolean> =
|
||||
combine(isActivityInViewVisible, isActivityOutViewVisible) { activityIn, activityOut ->
|
||||
activityIn || activityOut
|
||||
}
|
||||
|
||||
// TODO(b/238425913): Update this class to use state flows instead. Right now, we have a ton of
|
||||
// duplicate activity logs because the cold flows are getting duplicated for the three
|
||||
// activityVisible flows.
|
||||
|
||||
/** The tint that should be applied to the icon. */
|
||||
val tint: Flow<Int> = if (!statusBarPipelineFlags.useNewPipelineDebugColoring()) {
|
||||
|
||||
@@ -23,9 +23,15 @@ import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.log.LogBufferFactory
|
||||
import com.android.systemui.log.LogcatEchoTracker
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.mock
|
||||
@@ -64,12 +70,34 @@ class ConnectivityPipelineLoggerTest : SysuiTestCase() {
|
||||
assertThat(actualString).contains(expectedNetId)
|
||||
}
|
||||
|
||||
private val NET_1_ID = 100
|
||||
private val NET_1 = com.android.systemui.util.mockito.mock<Network>().also {
|
||||
Mockito.`when`(it.getNetId()).thenReturn(NET_1_ID)
|
||||
@Test
|
||||
fun logOutputChange_printsValuesAndNulls() = runBlocking(IMMEDIATE) {
|
||||
val flow: Flow<Int?> = flowOf(1, null, 3)
|
||||
|
||||
val job = flow
|
||||
.logOutputChange(logger, "testInts")
|
||||
.launchIn(this)
|
||||
|
||||
val stringWriter = StringWriter()
|
||||
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
|
||||
val actualString = stringWriter.toString()
|
||||
|
||||
assertThat(actualString).contains("1")
|
||||
assertThat(actualString).contains("null")
|
||||
assertThat(actualString).contains("3")
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val NET_1_ID = 100
|
||||
private val NET_1 = com.android.systemui.util.mockito.mock<Network>().also {
|
||||
Mockito.`when`(it.getNetId()).thenReturn(NET_1_ID)
|
||||
}
|
||||
private val NET_1_CAPS = NetworkCapabilities.Builder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
|
||||
.build()
|
||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||
}
|
||||
private val NET_1_CAPS = NetworkCapabilities.Builder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.wifi.data.repository
|
||||
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
|
||||
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
|
||||
@@ -29,10 +29,10 @@ import android.net.wifi.WifiManager.TrafficStateCallback
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
|
||||
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
|
||||
import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.wifi.domain.interactor
|
||||
|
||||
import android.net.wifi.WifiManager
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
|
||||
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
@@ -50,171 +51,105 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_noInOrOut_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
|
||||
)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.hasActivityIn
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_onlyOut_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
|
||||
)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.hasActivityIn
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_onlyIn_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.hasActivityIn
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_inAndOut_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.hasActivityIn
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_ssidNull_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = 1, ssid = null))
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.hasActivityIn
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_inactiveNetwork_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
fun ssid_inactiveNetwork_outputsNull() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
)
|
||||
|
||||
var latest: Boolean? = null
|
||||
var latest: String? = "default"
|
||||
val job = underTest
|
||||
.hasActivityIn
|
||||
.ssid
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isFalse()
|
||||
assertThat(latest).isNull()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_carrierMergedNetwork_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
fun ssid_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
)
|
||||
|
||||
var latest: Boolean? = null
|
||||
var latest: String? = "default"
|
||||
val job = underTest
|
||||
.hasActivityIn
|
||||
.ssid
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isFalse()
|
||||
assertThat(latest).isNull()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_multipleChanges_multipleOutputChanges() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
fun ssid_isPasspointAccessPoint_outputsPasspointName() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
|
||||
networkId = 1,
|
||||
isPasspointAccessPoint = true,
|
||||
passpointProviderFriendlyName = "friendly",
|
||||
))
|
||||
|
||||
var latest: Boolean? = null
|
||||
var latest: String? = null
|
||||
val job = underTest
|
||||
.hasActivityIn
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
.ssid
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
// Conduct a series of changes and verify we catch each of them in succession
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
)
|
||||
yield()
|
||||
assertThat(latest).isTrue()
|
||||
assertThat(latest).isEqualTo("friendly")
|
||||
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
|
||||
)
|
||||
yield()
|
||||
assertThat(latest).isFalse()
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
)
|
||||
yield()
|
||||
assertThat(latest).isTrue()
|
||||
@Test
|
||||
fun ssid_isOnlineSignUpForPasspoint_outputsPasspointName() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
|
||||
networkId = 1,
|
||||
isOnlineSignUpForPasspointAccessPoint = true,
|
||||
passpointProviderFriendlyName = "friendly",
|
||||
))
|
||||
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
)
|
||||
yield()
|
||||
assertThat(latest).isTrue()
|
||||
var latest: String? = null
|
||||
val job = underTest
|
||||
.ssid
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
|
||||
)
|
||||
yield()
|
||||
assertThat(latest).isFalse()
|
||||
assertThat(latest).isEqualTo("friendly")
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun ssid_unknownSsid_outputsNull() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
|
||||
networkId = 1,
|
||||
ssid = WifiManager.UNKNOWN_SSID,
|
||||
))
|
||||
|
||||
var latest: String? = "default"
|
||||
val job = underTest
|
||||
.ssid
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isNull()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun ssid_validSsid_outputsSsid() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
|
||||
networkId = 1,
|
||||
ssid = "MyAwesomeWifiNetwork",
|
||||
))
|
||||
|
||||
var latest: String? = null
|
||||
val job = underTest
|
||||
.ssid
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isEqualTo("MyAwesomeWifiNetwork")
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
@@ -241,6 +176,32 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activity_matchesRepoWifiActivity() = runBlocking(IMMEDIATE) {
|
||||
var latest: WifiActivityModel? = null
|
||||
val job = underTest
|
||||
.activity
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
val activity1 = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
wifiRepository.setWifiActivity(activity1)
|
||||
yield()
|
||||
assertThat(latest).isEqualTo(activity1)
|
||||
|
||||
val activity2 = WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
|
||||
wifiRepository.setWifiActivity(activity2)
|
||||
yield()
|
||||
assertThat(latest).isEqualTo(activity2)
|
||||
|
||||
val activity3 = WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
wifiRepository.setWifiActivity(activity3)
|
||||
yield()
|
||||
assertThat(latest).isEqualTo(activity3)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isForceHidden_repoHasWifiHidden_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
|
||||
@@ -270,10 +231,6 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val VALID_WIFI_NETWORK_MODEL = WifiNetworkModel.Active(networkId = 1, ssid = "AB")
|
||||
}
|
||||
}
|
||||
|
||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||
|
||||
@@ -29,11 +29,11 @@ import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
|
||||
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
|
||||
import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
|
||||
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel.Companion.NO_INTERNET
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -67,14 +67,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
connectivityRepository = FakeConnectivityRepository()
|
||||
wifiRepository = FakeWifiRepository()
|
||||
interactor = WifiInteractor(connectivityRepository, wifiRepository)
|
||||
|
||||
underTest = WifiViewModel(
|
||||
statusBarPipelineFlags,
|
||||
constants,
|
||||
context,
|
||||
logger,
|
||||
interactor
|
||||
)
|
||||
createAndSetViewModel()
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -219,68 +212,299 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activityInVisible_showActivityConfigFalse_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
fun activity_showActivityConfigFalse_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(false)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isActivityInVisible
|
||||
.onEach { latest = it }
|
||||
var activityIn: Boolean? = null
|
||||
val activityInJob = underTest
|
||||
.isActivityInViewVisible
|
||||
.onEach { activityIn = it }
|
||||
.launchIn(this)
|
||||
|
||||
// Verify that on launch, we receive a false.
|
||||
assertThat(latest).isFalse()
|
||||
var activityOut: Boolean? = null
|
||||
val activityOutJob = underTest
|
||||
.isActivityOutViewVisible
|
||||
.onEach { activityOut = it }
|
||||
.launchIn(this)
|
||||
|
||||
job.cancel()
|
||||
var activityContainer: Boolean? = null
|
||||
val activityContainerJob = underTest
|
||||
.isActivityContainerVisible
|
||||
.onEach { activityContainer = it }
|
||||
.launchIn(this)
|
||||
|
||||
// Verify that on launch, we receive false.
|
||||
assertThat(activityIn).isFalse()
|
||||
assertThat(activityOut).isFalse()
|
||||
assertThat(activityContainer).isFalse()
|
||||
|
||||
activityInJob.cancel()
|
||||
activityOutJob.cancel()
|
||||
activityContainerJob.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activityInVisible_showActivityConfigFalse_noUpdatesReceived() = runBlocking(IMMEDIATE) {
|
||||
fun activity_showActivityConfigFalse_noUpdatesReceived() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(false)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isActivityInVisible
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
var activityIn: Boolean? = null
|
||||
val activityInJob = underTest
|
||||
.isActivityInViewVisible
|
||||
.onEach { activityIn = it }
|
||||
.launchIn(this)
|
||||
|
||||
// Update the repo to have activityIn
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
)
|
||||
var activityOut: Boolean? = null
|
||||
val activityOutJob = underTest
|
||||
.isActivityOutViewVisible
|
||||
.onEach { activityOut = it }
|
||||
.launchIn(this)
|
||||
|
||||
var activityContainer: Boolean? = null
|
||||
val activityContainerJob = underTest
|
||||
.isActivityContainerVisible
|
||||
.onEach { activityContainer = it }
|
||||
.launchIn(this)
|
||||
|
||||
// WHEN we update the repo to have activity
|
||||
val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
wifiRepository.setWifiActivity(activity)
|
||||
yield()
|
||||
|
||||
// Verify that we didn't update to activityIn=true (because our config is false)
|
||||
assertThat(latest).isFalse()
|
||||
// THEN we didn't update to the new activity (because our config is false)
|
||||
assertThat(activityIn).isFalse()
|
||||
assertThat(activityOut).isFalse()
|
||||
assertThat(activityContainer).isFalse()
|
||||
|
||||
job.cancel()
|
||||
activityInJob.cancel()
|
||||
activityOutJob.cancel()
|
||||
activityContainerJob.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activityInVisible_showActivityConfigTrue_outputsUpdate() = runBlocking(IMMEDIATE) {
|
||||
fun activity_nullSsid_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, ssid = null))
|
||||
|
||||
var activityIn: Boolean? = null
|
||||
val activityInJob = underTest
|
||||
.isActivityInViewVisible
|
||||
.onEach { activityIn = it }
|
||||
.launchIn(this)
|
||||
|
||||
var activityOut: Boolean? = null
|
||||
val activityOutJob = underTest
|
||||
.isActivityOutViewVisible
|
||||
.onEach { activityOut = it }
|
||||
.launchIn(this)
|
||||
|
||||
var activityContainer: Boolean? = null
|
||||
val activityContainerJob = underTest
|
||||
.isActivityContainerVisible
|
||||
.onEach { activityContainer = it }
|
||||
.launchIn(this)
|
||||
|
||||
// WHEN we update the repo to have activity
|
||||
val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
wifiRepository.setWifiActivity(activity)
|
||||
yield()
|
||||
|
||||
// THEN we still output false because our network's SSID is null
|
||||
assertThat(activityIn).isFalse()
|
||||
assertThat(activityOut).isFalse()
|
||||
assertThat(activityContainer).isFalse()
|
||||
|
||||
activityInJob.cancel()
|
||||
activityOutJob.cancel()
|
||||
activityContainerJob.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activityIn_hasActivityInTrue_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isActivityInVisible
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
.isActivityInViewVisible
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
// Update the repo to have activityIn
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
)
|
||||
val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
wifiRepository.setWifiActivity(activity)
|
||||
yield()
|
||||
|
||||
// Verify that we updated to activityIn=true
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activityIn_hasActivityInFalse_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isActivityInViewVisible
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
val activity = WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
|
||||
wifiRepository.setWifiActivity(activity)
|
||||
yield()
|
||||
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activityOut_hasActivityOutTrue_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isActivityOutViewVisible
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
val activity = WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
|
||||
wifiRepository.setWifiActivity(activity)
|
||||
yield()
|
||||
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activityOut_hasActivityOutFalse_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isActivityOutViewVisible
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
wifiRepository.setWifiActivity(activity)
|
||||
yield()
|
||||
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activityContainer_hasActivityInTrue_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isActivityContainerVisible
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
wifiRepository.setWifiActivity(activity)
|
||||
yield()
|
||||
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activityContainer_hasActivityOutTrue_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isActivityContainerVisible
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
val activity = WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
|
||||
wifiRepository.setWifiActivity(activity)
|
||||
yield()
|
||||
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activityContainer_inAndOutTrue_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isActivityContainerVisible
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
wifiRepository.setWifiActivity(activity)
|
||||
yield()
|
||||
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activityContainer_inAndOutFalse_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
||||
createAndSetViewModel()
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isActivityContainerVisible
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
val activity = WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
|
||||
wifiRepository.setWifiActivity(activity)
|
||||
yield()
|
||||
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun createAndSetViewModel() {
|
||||
// [WifiViewModel] creates its flows as soon as it's instantiated, and some of those flow
|
||||
// creations rely on certain config values that we mock out in individual tests. This method
|
||||
// allows tests to create the view model only after those configs are correctly set up.
|
||||
underTest = WifiViewModel(
|
||||
constants,
|
||||
context,
|
||||
logger,
|
||||
interactor,
|
||||
statusBarPipelineFlags,
|
||||
)
|
||||
}
|
||||
|
||||
private fun ContentDescription.getAsString(): String? {
|
||||
return when (this) {
|
||||
is ContentDescription.Loaded -> this.description
|
||||
|
||||
Reference in New Issue
Block a user