Merge "[SB Refactor] Implement the TunerService callback for the icon hide list and pipe it through to the wifi icon." into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
e04e312e98
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.pipeline.dagger
|
||||
|
||||
import com.android.systemui.CoreStartable
|
||||
import com.android.systemui.statusbar.pipeline.ConnectivityInfoProcessor
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl
|
||||
import dagger.Binds
|
||||
@@ -33,6 +35,9 @@ abstract class StatusBarPipelineModule {
|
||||
@ClassKey(ConnectivityInfoProcessor::class)
|
||||
abstract fun bindConnectivityInfoProcessor(cip: ConnectivityInfoProcessor): CoreStartable
|
||||
|
||||
@Binds
|
||||
abstract fun connectivityRepository(impl: ConnectivityRepositoryImpl): ConnectivityRepository
|
||||
|
||||
@Binds
|
||||
abstract fun wifiRepository(impl: WifiRepositoryImpl): WifiRepository
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class ConnectivityPipelineLogger @Inject constructor(
|
||||
/**
|
||||
* Logs a change in one of the **raw inputs** to the connectivity pipeline.
|
||||
*/
|
||||
fun logInputChange(callbackName: String, changeInfo: String) {
|
||||
fun logInputChange(callbackName: String, changeInfo: String?) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.shared.data.model
|
||||
|
||||
import android.content.Context
|
||||
import com.android.internal.R
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* A container for all the different types of connectivity slots: wifi, mobile, etc.
|
||||
*/
|
||||
@SysUISingleton
|
||||
class ConnectivitySlots @Inject constructor(context: Context) {
|
||||
private val airplaneSlot: String = context.getString(R.string.status_bar_airplane)
|
||||
private val mobileSlot: String = context.getString(R.string.status_bar_mobile)
|
||||
private val wifiSlot: String = context.getString(R.string.status_bar_wifi)
|
||||
private val ethernetSlot: String = context.getString(R.string.status_bar_ethernet)
|
||||
|
||||
private val slotByName: Map<String, ConnectivitySlot> = mapOf(
|
||||
airplaneSlot to ConnectivitySlot.AIRPLANE,
|
||||
mobileSlot to ConnectivitySlot.MOBILE,
|
||||
wifiSlot to ConnectivitySlot.WIFI,
|
||||
ethernetSlot to ConnectivitySlot.ETHERNET
|
||||
)
|
||||
|
||||
/**
|
||||
* Given a string name of a slot, returns the instance of [ConnectivitySlot] that it corresponds
|
||||
* to, or null if we couldn't find that slot name.
|
||||
*/
|
||||
fun getSlotFromName(slotName: String): ConnectivitySlot? {
|
||||
return slotByName[slotName]
|
||||
}
|
||||
}
|
||||
|
||||
/** The different types of connectivity slots. */
|
||||
enum class ConnectivitySlot {
|
||||
AIRPLANE,
|
||||
ETHERNET,
|
||||
MOBILE,
|
||||
WIFI,
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.shared.data.repository
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.ArrayRes
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.systemui.Dumpable
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.statusbar.phone.StatusBarIconController
|
||||
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.data.model.ConnectivitySlot
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
|
||||
import com.android.systemui.tuner.TunerService
|
||||
import java.io.PrintWriter
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
/**
|
||||
* Provides data related to the connectivity state that needs to be shared across multiple different
|
||||
* types of connectivity (wifi, mobile, ethernet, etc.)
|
||||
*/
|
||||
interface ConnectivityRepository {
|
||||
/**
|
||||
* Observable for the current set of connectivity icons that should be force-hidden.
|
||||
*/
|
||||
val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>>
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SysUISingleton
|
||||
class ConnectivityRepositoryImpl @Inject constructor(
|
||||
private val connectivitySlots: ConnectivitySlots,
|
||||
context: Context,
|
||||
dumpManager: DumpManager,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
@Application scope: CoroutineScope,
|
||||
tunerService: TunerService,
|
||||
) : ConnectivityRepository, Dumpable {
|
||||
init {
|
||||
dumpManager.registerDumpable("$SB_LOGGING_TAG:ConnectivityRepository", this)
|
||||
}
|
||||
|
||||
// The default set of hidden icons to use if we don't get any from [TunerService].
|
||||
private val defaultHiddenIcons: Set<ConnectivitySlot> =
|
||||
context.resources.getStringArray(DEFAULT_HIDDEN_ICONS_RESOURCE)
|
||||
.asList()
|
||||
.toSlotSet(connectivitySlots)
|
||||
|
||||
override val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>> = conflatedCallbackFlow {
|
||||
val callback = object : TunerService.Tunable {
|
||||
override fun onTuningChanged(key: String, newHideList: String?) {
|
||||
if (key != HIDDEN_ICONS_TUNABLE_KEY) {
|
||||
return
|
||||
}
|
||||
logger.logInputChange("onTuningChanged", newHideList)
|
||||
|
||||
val outputList = newHideList?.split(",")?.toSlotSet(connectivitySlots)
|
||||
?: defaultHiddenIcons
|
||||
trySend(outputList)
|
||||
}
|
||||
}
|
||||
tunerService.addTunable(callback, HIDDEN_ICONS_TUNABLE_KEY)
|
||||
|
||||
awaitClose { tunerService.removeTunable(callback) }
|
||||
}
|
||||
.stateIn(
|
||||
scope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue = defaultHiddenIcons
|
||||
)
|
||||
|
||||
override fun dump(pw: PrintWriter, args: Array<out String>) {
|
||||
pw.apply {
|
||||
println("defaultHiddenIcons=$defaultHiddenIcons")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@VisibleForTesting
|
||||
internal const val HIDDEN_ICONS_TUNABLE_KEY = StatusBarIconController.ICON_HIDE_LIST
|
||||
@VisibleForTesting
|
||||
@ArrayRes
|
||||
internal val DEFAULT_HIDDEN_ICONS_RESOURCE = R.array.config_statusBarIconsToExclude
|
||||
|
||||
/** Converts a list of string slot names to a set of [ConnectivitySlot] instances. */
|
||||
private fun List<String>.toSlotSet(
|
||||
connectivitySlots: ConnectivitySlots
|
||||
): Set<ConnectivitySlot> {
|
||||
return this
|
||||
.filter { it.isNotBlank() }
|
||||
.mapNotNull { connectivitySlots.getSlotFromName(it) }
|
||||
.toSet()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.pipeline.wifi.domain.interactor
|
||||
|
||||
import android.net.wifi.WifiManager
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
|
||||
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 javax.inject.Inject
|
||||
@@ -33,9 +35,10 @@ import kotlinx.coroutines.flow.map
|
||||
*/
|
||||
@SysUISingleton
|
||||
class WifiInteractor @Inject constructor(
|
||||
repository: WifiRepository,
|
||||
connectivityRepository: ConnectivityRepository,
|
||||
wifiRepository: WifiRepository,
|
||||
) {
|
||||
private val ssid: Flow<String?> = repository.wifiNetwork.map { info ->
|
||||
private val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
|
||||
when (info) {
|
||||
is WifiNetworkModel.Inactive -> null
|
||||
is WifiNetworkModel.CarrierMerged -> null
|
||||
@@ -49,10 +52,16 @@ class WifiInteractor @Inject constructor(
|
||||
}
|
||||
|
||||
/** Our current wifi network. See [WifiNetworkModel]. */
|
||||
val wifiNetwork: Flow<WifiNetworkModel> = repository.wifiNetwork
|
||||
val wifiNetwork: Flow<WifiNetworkModel> = wifiRepository.wifiNetwork
|
||||
|
||||
/** 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(repository.wifiActivity, ssid) { activity, ssid ->
|
||||
val hasActivityIn: Flow<Boolean> =
|
||||
combine(wifiRepository.wifiActivity, ssid) { activity, ssid ->
|
||||
activity.hasActivityIn && ssid != null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.common.ui.binder.IconViewBinder
|
||||
import com.android.systemui.lifecycle.repeatWhenAttached
|
||||
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
@@ -54,14 +55,15 @@ object WifiViewBinder {
|
||||
view.repeatWhenAttached {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
launch {
|
||||
viewModel.wifiIconResId.distinctUntilChanged().collect { iconResId ->
|
||||
iconView.setImageDrawable(
|
||||
if (iconResId != null && iconResId > 0) {
|
||||
iconView.context.getDrawable(iconResId)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
)
|
||||
viewModel.wifiIcon.distinctUntilChanged().collect { wifiIcon ->
|
||||
// TODO(b/238425913): Right now, if !isVisible, there's just an empty space
|
||||
// where the wifi icon would be. We need to pipe isVisible through to
|
||||
// [ModernStatusBarWifiView.isIconVisible], which is what actually makes
|
||||
// the view GONE.
|
||||
view.isVisible = wifiIcon != null
|
||||
wifiIcon?.let {
|
||||
IconViewBinder.bind(wifiIcon, iconView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
|
||||
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.android.systemui.common.shared.model.Icon
|
||||
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
|
||||
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS
|
||||
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_NETWORK
|
||||
@@ -29,6 +30,7 @@ import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiIntera
|
||||
import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
@@ -46,7 +48,7 @@ class WifiViewModel @Inject constructor(
|
||||
* The drawable resource ID to use for the wifi icon. Null if we shouldn't display any icon.
|
||||
*/
|
||||
@DrawableRes
|
||||
val wifiIconResId: Flow<Int?> = interactor.wifiNetwork.map {
|
||||
private val iconResId: Flow<Int?> = interactor.wifiNetwork.map {
|
||||
when (it) {
|
||||
is WifiNetworkModel.CarrierMerged -> null
|
||||
is WifiNetworkModel.Inactive -> WIFI_NO_NETWORK
|
||||
@@ -59,6 +61,24 @@ class WifiViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The wifi icon that should be displayed. Null if we shouldn't display any icon.
|
||||
*/
|
||||
val wifiIcon: Flow<Icon?> = combine(
|
||||
interactor.isForceHidden,
|
||||
iconResId
|
||||
) { isForceHidden, iconResId ->
|
||||
when {
|
||||
isForceHidden ||
|
||||
iconResId == null ||
|
||||
iconResId <= 0 -> null
|
||||
else -> Icon.Resource(iconResId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the activity in icon should be displayed and false otherwise.
|
||||
*/
|
||||
val isActivityInVisible: Flow<Boolean>
|
||||
get() =
|
||||
if (!constants.shouldShowActivityConfig) {
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.shared.data.repository
|
||||
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.dump.DumpManager
|
||||
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.model.ConnectivitySlots
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.DEFAULT_HIDDEN_ICONS_RESOURCE
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.HIDDEN_ICONS_TUNABLE_KEY
|
||||
import com.android.systemui.tuner.TunerService
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.yield
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
class ConnectivityRepositoryImplTest : SysuiTestCase() {
|
||||
|
||||
private lateinit var underTest: ConnectivityRepositoryImpl
|
||||
|
||||
@Mock private lateinit var connectivitySlots: ConnectivitySlots
|
||||
@Mock private lateinit var dumpManager: DumpManager
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
private lateinit var scope: CoroutineScope
|
||||
@Mock private lateinit var tunerService: TunerService
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
scope = CoroutineScope(IMMEDIATE)
|
||||
|
||||
underTest = ConnectivityRepositoryImpl(
|
||||
connectivitySlots,
|
||||
context,
|
||||
dumpManager,
|
||||
logger,
|
||||
scope,
|
||||
tunerService,
|
||||
)
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
scope.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun forceHiddenSlots_initiallyGetsDefault() = runBlocking(IMMEDIATE) {
|
||||
setUpEthernetWifiMobileSlotNames()
|
||||
context.getOrCreateTestableResources().addOverride(
|
||||
DEFAULT_HIDDEN_ICONS_RESOURCE,
|
||||
arrayOf(SLOT_WIFI, SLOT_ETHERNET)
|
||||
)
|
||||
// Re-create our [ConnectivityRepositoryImpl], since it fetches
|
||||
// config_statusBarIconsToExclude when it's first constructed
|
||||
underTest = ConnectivityRepositoryImpl(
|
||||
connectivitySlots,
|
||||
context,
|
||||
dumpManager,
|
||||
logger,
|
||||
scope,
|
||||
tunerService,
|
||||
)
|
||||
|
||||
var latest: Set<ConnectivitySlot>? = null
|
||||
val job = underTest
|
||||
.forceHiddenSlots
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun forceHiddenSlots_slotNamesAdded_flowHasSlots() = runBlocking(IMMEDIATE) {
|
||||
setUpEthernetWifiMobileSlotNames()
|
||||
|
||||
var latest: Set<ConnectivitySlot>? = null
|
||||
val job = underTest
|
||||
.forceHiddenSlots
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
|
||||
|
||||
assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun forceHiddenSlots_wrongKey_doesNotUpdate() = runBlocking(IMMEDIATE) {
|
||||
setUpEthernetWifiMobileSlotNames()
|
||||
|
||||
var latest: Set<ConnectivitySlot>? = null
|
||||
val job = underTest
|
||||
.forceHiddenSlots
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
|
||||
|
||||
// WHEN onTuningChanged with the wrong key
|
||||
getTunable().onTuningChanged("wrongKey", SLOT_WIFI)
|
||||
yield()
|
||||
|
||||
// THEN we didn't update our value and still have the old one
|
||||
assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun forceHiddenSlots_slotNamesAddedThenNull_flowHasDefault() = runBlocking(IMMEDIATE) {
|
||||
setUpEthernetWifiMobileSlotNames()
|
||||
context.getOrCreateTestableResources().addOverride(
|
||||
DEFAULT_HIDDEN_ICONS_RESOURCE,
|
||||
arrayOf(SLOT_WIFI, SLOT_ETHERNET)
|
||||
)
|
||||
// Re-create our [ConnectivityRepositoryImpl], since it fetches
|
||||
// config_statusBarIconsToExclude when it's first constructed
|
||||
underTest = ConnectivityRepositoryImpl(
|
||||
connectivitySlots,
|
||||
context,
|
||||
dumpManager,
|
||||
logger,
|
||||
scope,
|
||||
tunerService,
|
||||
)
|
||||
|
||||
var latest: Set<ConnectivitySlot>? = null
|
||||
val job = underTest
|
||||
.forceHiddenSlots
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
// First, update the slots
|
||||
getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
|
||||
assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
|
||||
|
||||
// WHEN we update to a null value
|
||||
getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, null)
|
||||
yield()
|
||||
|
||||
// THEN we go back to our default value
|
||||
assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun forceHiddenSlots_someInvalidSlotNames_flowHasValidSlotsOnly() = runBlocking(IMMEDIATE) {
|
||||
var latest: Set<ConnectivitySlot>? = null
|
||||
val job = underTest
|
||||
.forceHiddenSlots
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
whenever(connectivitySlots.getSlotFromName(SLOT_WIFI))
|
||||
.thenReturn(ConnectivitySlot.WIFI)
|
||||
whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
|
||||
|
||||
getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_MOBILE")
|
||||
|
||||
assertThat(latest).containsExactly(ConnectivitySlot.WIFI)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun forceHiddenSlots_someEmptySlotNames_flowHasValidSlotsOnly() = runBlocking(IMMEDIATE) {
|
||||
setUpEthernetWifiMobileSlotNames()
|
||||
|
||||
var latest: Set<ConnectivitySlot>? = null
|
||||
val job = underTest
|
||||
.forceHiddenSlots
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
// WHEN there's empty and blank slot names
|
||||
getTunable().onTuningChanged(
|
||||
HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_MOBILE, ,,$SLOT_WIFI"
|
||||
)
|
||||
|
||||
// THEN we skip that slot but still process the other ones
|
||||
assertThat(latest).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.MOBILE)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun forceHiddenSlots_allInvalidOrEmptySlotNames_flowHasEmpty() = runBlocking(IMMEDIATE) {
|
||||
var latest: Set<ConnectivitySlot>? = null
|
||||
val job = underTest
|
||||
.forceHiddenSlots
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(null)
|
||||
whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET)).thenReturn(null)
|
||||
whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
|
||||
|
||||
getTunable().onTuningChanged(
|
||||
HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_MOBILE,,$SLOT_WIFI,$SLOT_ETHERNET,,,"
|
||||
)
|
||||
|
||||
assertThat(latest).isEmpty()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun forceHiddenSlots_newSubscriberGetsCurrentValue() = runBlocking(IMMEDIATE) {
|
||||
setUpEthernetWifiMobileSlotNames()
|
||||
|
||||
var latest1: Set<ConnectivitySlot>? = null
|
||||
val job1 = underTest
|
||||
.forceHiddenSlots
|
||||
.onEach { latest1 = it }
|
||||
.launchIn(this)
|
||||
|
||||
getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_ETHERNET")
|
||||
|
||||
assertThat(latest1).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
|
||||
|
||||
// WHEN we add a second subscriber after having already emitted a value
|
||||
var latest2: Set<ConnectivitySlot>? = null
|
||||
val job2 = underTest
|
||||
.forceHiddenSlots
|
||||
.onEach { latest2 = it }
|
||||
.launchIn(this)
|
||||
|
||||
// THEN the second subscribe receives the already-emitted value
|
||||
assertThat(latest2).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
|
||||
|
||||
job1.cancel()
|
||||
job2.cancel()
|
||||
}
|
||||
|
||||
private fun getTunable(): TunerService.Tunable {
|
||||
val callbackCaptor = argumentCaptor<TunerService.Tunable>()
|
||||
Mockito.verify(tunerService).addTunable(callbackCaptor.capture(), any())
|
||||
return callbackCaptor.value!!
|
||||
}
|
||||
|
||||
private fun setUpEthernetWifiMobileSlotNames() {
|
||||
whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET))
|
||||
.thenReturn(ConnectivitySlot.ETHERNET)
|
||||
whenever(connectivitySlots.getSlotFromName(SLOT_WIFI))
|
||||
.thenReturn(ConnectivitySlot.WIFI)
|
||||
whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE))
|
||||
.thenReturn(ConnectivitySlot.MOBILE)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SLOT_ETHERNET = "ethernet"
|
||||
private const val SLOT_WIFI = "wifi"
|
||||
private const val SLOT_MOBILE = "mobile"
|
||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.shared.data.repository
|
||||
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/** Fake implementation of [ConnectivityRepository] exposing set methods for all the flows. */
|
||||
class FakeConnectivityRepository : ConnectivityRepository {
|
||||
private val _forceHiddenIcons: MutableStateFlow<Set<ConnectivitySlot>> =
|
||||
MutableStateFlow(emptySet())
|
||||
override val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>> = _forceHiddenIcons
|
||||
|
||||
fun setForceHiddenIcons(hiddenIcons: Set<ConnectivitySlot>) {
|
||||
_forceHiddenIcons.value = hiddenIcons
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.pipeline.wifi.domain.interactor
|
||||
|
||||
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
|
||||
@@ -37,18 +39,22 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
|
||||
private lateinit var underTest: WifiInteractor
|
||||
|
||||
private lateinit var repository: FakeWifiRepository
|
||||
private lateinit var connectivityRepository: FakeConnectivityRepository
|
||||
private lateinit var wifiRepository: FakeWifiRepository
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
repository = FakeWifiRepository()
|
||||
underTest = WifiInteractor(repository)
|
||||
connectivityRepository = FakeConnectivityRepository()
|
||||
wifiRepository = FakeWifiRepository()
|
||||
underTest = WifiInteractor(connectivityRepository, wifiRepository)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_noInOrOut_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = false))
|
||||
wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
|
||||
)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
@@ -63,8 +69,10 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_onlyOut_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = true))
|
||||
wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
|
||||
)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
@@ -79,8 +87,10 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_onlyIn_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
|
||||
wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
@@ -95,8 +105,10 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_inAndOut_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
|
||||
wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
@@ -111,8 +123,10 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_ssidNull_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiNetwork(WifiNetworkModel.Active(networkId = 1, ssid = null))
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = 1, ssid = null))
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
@@ -127,8 +141,10 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_inactiveNetwork_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiNetwork(WifiNetworkModel.Inactive)
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
@@ -143,8 +159,10 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_carrierMergedNetwork_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
@@ -159,7 +177,7 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_multipleChanges_multipleOutputChanges() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
@@ -168,23 +186,33 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
.launchIn(this)
|
||||
|
||||
// Conduct a series of changes and verify we catch each of them in succession
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
)
|
||||
yield()
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = true))
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
|
||||
)
|
||||
yield()
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
)
|
||||
yield()
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
)
|
||||
yield()
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = false))
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
|
||||
)
|
||||
yield()
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
@@ -200,7 +228,7 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
ssid = "AB",
|
||||
passpointProviderFriendlyName = "friendly"
|
||||
)
|
||||
repository.setWifiNetwork(wifiNetwork)
|
||||
wifiRepository.setWifiNetwork(wifiNetwork)
|
||||
|
||||
var latest: WifiNetworkModel? = null
|
||||
val job = underTest
|
||||
@@ -213,6 +241,36 @@ class WifiInteractorTest : SysuiTestCase() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isForceHidden_repoHasWifiHidden_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isForceHidden
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isForceHidden_repoDoesNotHaveWifiHidden_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
connectivityRepository.setForceHiddenIcons(setOf())
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isForceHidden
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val VALID_WIFI_NETWORK_MODEL = WifiNetworkModel.Active(networkId = 1, ssid = "AB")
|
||||
}
|
||||
|
||||
@@ -18,11 +18,14 @@ package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
|
||||
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.common.shared.model.Icon
|
||||
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
|
||||
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS
|
||||
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_NETWORK
|
||||
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
|
||||
@@ -50,14 +53,16 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var constants: WifiConstants
|
||||
private lateinit var repository: FakeWifiRepository
|
||||
private lateinit var connectivityRepository: FakeConnectivityRepository
|
||||
private lateinit var wifiRepository: FakeWifiRepository
|
||||
private lateinit var interactor: WifiInteractor
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
repository = FakeWifiRepository()
|
||||
interactor = WifiInteractor(repository)
|
||||
connectivityRepository = FakeConnectivityRepository()
|
||||
wifiRepository = FakeWifiRepository()
|
||||
interactor = WifiInteractor(connectivityRepository, wifiRepository)
|
||||
|
||||
underTest = WifiViewModel(
|
||||
statusBarPipelineFlags,
|
||||
@@ -68,42 +73,13 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiIconResId_inactiveNetwork_outputsNoNetworkIcon() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiNetwork(WifiNetworkModel.Inactive)
|
||||
fun wifiIcon_forceHidden_outputsNull() = runBlocking(IMMEDIATE) {
|
||||
connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = 2))
|
||||
|
||||
var latest: Int? = null
|
||||
var latest: Icon? = null
|
||||
val job = underTest
|
||||
.wifiIconResId
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isEqualTo(WIFI_NO_NETWORK)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiIconResId_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
|
||||
|
||||
var latest: Int? = null
|
||||
val job = underTest
|
||||
.wifiIconResId
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isNull()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiIconResId_isActiveNullLevel_outputsNull() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = null))
|
||||
|
||||
var latest: Int? = null
|
||||
val job = underTest
|
||||
.wifiIconResId
|
||||
.wifiIcon
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
@@ -113,10 +89,72 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiIconResId_isActiveAndValidated_level1_outputsFull1Icon() = runBlocking(IMMEDIATE) {
|
||||
fun wifiIcon_notForceHidden_outputsVisible() = runBlocking(IMMEDIATE) {
|
||||
connectivityRepository.setForceHiddenIcons(setOf())
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = 2))
|
||||
|
||||
var latest: Icon? = null
|
||||
val job = underTest
|
||||
.wifiIcon
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isInstanceOf(Icon.Resource::class.java)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiIcon_inactiveNetwork_outputsNoNetworkIcon() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
|
||||
|
||||
var latest: Icon? = null
|
||||
val job = underTest
|
||||
.wifiIcon
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isInstanceOf(Icon.Resource::class.java)
|
||||
assertThat((latest as Icon.Resource).res).isEqualTo(WIFI_NO_NETWORK)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiIcon_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
|
||||
|
||||
var latest: Icon? = null
|
||||
val job = underTest
|
||||
.wifiIcon
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isNull()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiIcon_isActiveNullLevel_outputsNull() = runBlocking(IMMEDIATE) {
|
||||
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = null))
|
||||
|
||||
var latest: Icon? = null
|
||||
val job = underTest
|
||||
.wifiIcon
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isNull()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiIcon_isActiveAndValidated_level1_outputsFull1Icon() = runBlocking(IMMEDIATE) {
|
||||
val level = 1
|
||||
|
||||
repository.setWifiNetwork(
|
||||
wifiRepository.setWifiNetwork(
|
||||
WifiNetworkModel.Active(
|
||||
NETWORK_ID,
|
||||
isValidated = true,
|
||||
@@ -124,22 +162,23 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
)
|
||||
)
|
||||
|
||||
var latest: Int? = null
|
||||
var latest: Icon? = null
|
||||
val job = underTest
|
||||
.wifiIconResId
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
.wifiIcon
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isEqualTo(WIFI_FULL_ICONS[level])
|
||||
assertThat(latest).isInstanceOf(Icon.Resource::class.java)
|
||||
assertThat((latest as Icon.Resource).res).isEqualTo(WIFI_FULL_ICONS[level])
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiIconResId_isActiveAndNotValidated_level4_outputsEmpty4Icon() = runBlocking(IMMEDIATE) {
|
||||
fun wifiIcon_isActiveAndNotValidated_level4_outputsEmpty4Icon() = runBlocking(IMMEDIATE) {
|
||||
val level = 4
|
||||
|
||||
repository.setWifiNetwork(
|
||||
wifiRepository.setWifiNetwork(
|
||||
WifiNetworkModel.Active(
|
||||
NETWORK_ID,
|
||||
isValidated = false,
|
||||
@@ -147,13 +186,14 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
)
|
||||
)
|
||||
|
||||
var latest: Int? = null
|
||||
var latest: Icon? = null
|
||||
val job = underTest
|
||||
.wifiIconResId
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
.wifiIcon
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isEqualTo(WIFI_NO_INTERNET_ICONS[level])
|
||||
assertThat(latest).isInstanceOf(Icon.Resource::class.java)
|
||||
assertThat((latest as Icon.Resource).res).isEqualTo(WIFI_NO_INTERNET_ICONS[level])
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
@@ -161,7 +201,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun activityInVisible_showActivityConfigFalse_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(false)
|
||||
repository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
@@ -178,7 +218,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun activityInVisible_showActivityConfigFalse_noUpdatesReceived() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(false)
|
||||
repository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
@@ -187,7 +227,9 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
.launchIn(this)
|
||||
|
||||
// Update the repo to have activityIn
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
)
|
||||
yield()
|
||||
|
||||
// Verify that we didn't update to activityIn=true (because our config is false)
|
||||
@@ -199,7 +241,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun activityInVisible_showActivityConfigTrue_outputsUpdate() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
||||
repository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
@@ -208,7 +250,9 @@ class WifiViewModelTest : SysuiTestCase() {
|
||||
.launchIn(this)
|
||||
|
||||
// Update the repo to have activityIn
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
|
||||
wifiRepository.setWifiActivity(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
)
|
||||
yield()
|
||||
|
||||
// Verify that we updated to activityIn=true
|
||||
|
||||
Reference in New Issue
Block a user