[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:
Caitlin Shkuratov
2022-09-14 21:22:18 +00:00
parent 8cfb8af91a
commit 4513768e3b
11 changed files with 473 additions and 223 deletions

View File

@@ -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() }

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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,

View File

@@ -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.
}
}

View File

@@ -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()) {

View File

@@ -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()
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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