mirror of
https://github.com/bitwarden/android.git
synced 2026-03-18 20:24:33 -05:00
PM-20516: Update NetworkConnectionManager (#5085)
This commit is contained in:
@@ -6,6 +6,7 @@ import com.x8bit.bitwarden.data.auth.manager.AuthRequestNotificationManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.LogsManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.network.NetworkConfigManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.network.NetworkConnectionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.restriction.RestrictionManager
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import javax.inject.Inject
|
||||
@@ -21,6 +22,9 @@ class BitwardenApplication : Application() {
|
||||
@Inject
|
||||
lateinit var logsManager: LogsManager
|
||||
|
||||
@Inject
|
||||
lateinit var networkConnectionManager: NetworkConnectionManager
|
||||
|
||||
@Inject
|
||||
lateinit var networkConfigManager: NetworkConfigManager
|
||||
|
||||
|
||||
@@ -259,8 +259,10 @@ object PlatformManagerModule {
|
||||
@Singleton
|
||||
fun provideNetworkConnectionManager(
|
||||
application: Application,
|
||||
dispatcherManager: DispatcherManager,
|
||||
): NetworkConnectionManager = NetworkConnectionManagerImpl(
|
||||
context = application.applicationContext,
|
||||
dispatcherManager = dispatcherManager,
|
||||
)
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.x8bit.bitwarden.data.platform.manager.model
|
||||
|
||||
/**
|
||||
* A representation of the current network connection.
|
||||
*/
|
||||
sealed class NetworkConnection {
|
||||
/**
|
||||
* Currently not connected to the internet.
|
||||
*/
|
||||
data object None : NetworkConnection()
|
||||
|
||||
/**
|
||||
* Currently connected to the internet via WiFi with a signal [strength] indication.
|
||||
*/
|
||||
data class Wifi(
|
||||
val strength: NetworkSignalStrength,
|
||||
) : NetworkConnection()
|
||||
|
||||
/**
|
||||
* Currently connected to the internet via cellular connection.
|
||||
*/
|
||||
data object Cellular : NetworkConnection()
|
||||
|
||||
/**
|
||||
* Currently connected to the internet via an unknown connection.
|
||||
*/
|
||||
data object Other : NetworkConnection()
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.x8bit.bitwarden.data.platform.manager.model
|
||||
|
||||
/**
|
||||
* An indicator of the signal strength for a network connection.
|
||||
*/
|
||||
enum class NetworkSignalStrength {
|
||||
EXCELLENT,
|
||||
GOOD,
|
||||
FAIR,
|
||||
WEAK,
|
||||
NONE,
|
||||
UNKNOWN,
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.x8bit.bitwarden.data.platform.manager.network
|
||||
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.NetworkConnection
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
* Manager to detect and handle changes to network connectivity.
|
||||
*/
|
||||
@@ -9,4 +12,21 @@ interface NetworkConnectionManager {
|
||||
* available.
|
||||
*/
|
||||
val isNetworkConnected: Boolean
|
||||
|
||||
/**
|
||||
* Emits `true` when the application has a network connection and access to the Internet is
|
||||
* available.
|
||||
*/
|
||||
val isNetworkConnectedFlow: StateFlow<Boolean>
|
||||
|
||||
/**
|
||||
* Returns the current network connection.
|
||||
*/
|
||||
val networkConnection: NetworkConnection
|
||||
|
||||
/**
|
||||
* Emits the current [NetworkConnection] indicating what type of network the app is currently
|
||||
* using to connect to the internet.
|
||||
*/
|
||||
val networkConnectionFlow: StateFlow<NetworkConnection>
|
||||
}
|
||||
|
||||
@@ -2,21 +2,153 @@ package com.x8bit.bitwarden.data.platform.manager.network
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.LinkProperties
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED
|
||||
import android.net.NetworkRequest
|
||||
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
||||
import com.bitwarden.data.manager.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.NetworkConnection
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.NetworkSignalStrength
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
/**
|
||||
* Primary implementation of [NetworkConnectionManager].
|
||||
*/
|
||||
class NetworkConnectionManagerImpl(
|
||||
context: Context,
|
||||
dispatcherManager: DispatcherManager,
|
||||
) : NetworkConnectionManager {
|
||||
private val unconfinedScope = CoroutineScope(context = dispatcherManager.unconfined)
|
||||
private val networkChangeCallback = ConnectionChangeCallback()
|
||||
|
||||
private val connectivityManager: ConnectivityManager = context
|
||||
.applicationContext
|
||||
.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
|
||||
init {
|
||||
connectivityManager.registerNetworkCallback(
|
||||
NetworkRequest.Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.build(),
|
||||
networkChangeCallback,
|
||||
)
|
||||
}
|
||||
|
||||
override val isNetworkConnected: Boolean
|
||||
get() = connectivityManager
|
||||
.getNetworkCapabilities(connectivityManager.activeNetwork)
|
||||
?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
?: false
|
||||
|
||||
override val isNetworkConnectedFlow: StateFlow<Boolean> =
|
||||
networkChangeCallback
|
||||
.connectionChangeFlow
|
||||
.map { isNetworkConnected }
|
||||
.distinctUntilChanged()
|
||||
.stateIn(
|
||||
scope = unconfinedScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = isNetworkConnected,
|
||||
)
|
||||
|
||||
override val networkConnection: NetworkConnection
|
||||
get() = connectivityManager
|
||||
.getNetworkCapabilities(connectivityManager.activeNetwork)
|
||||
.networkConnection
|
||||
|
||||
override val networkConnectionFlow: StateFlow<NetworkConnection> = networkChangeCallback
|
||||
.connectionChangeFlow
|
||||
.map { _ -> networkConnection }
|
||||
.distinctUntilChanged()
|
||||
.stateIn(
|
||||
scope = unconfinedScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = networkConnection,
|
||||
)
|
||||
|
||||
/**
|
||||
* A callback used to monitor the connection of a [Network].
|
||||
*/
|
||||
private class ConnectionChangeCallback : ConnectivityManager.NetworkCallback() {
|
||||
private val mutableConnectionState: MutableSharedFlow<Unit> = bufferedMutableSharedFlow()
|
||||
|
||||
/**
|
||||
* A [StateFlow] that emits when the connection state to a network changes.
|
||||
*/
|
||||
val connectionChangeFlow: SharedFlow<Unit> = mutableConnectionState.asSharedFlow()
|
||||
|
||||
override fun onCapabilitiesChanged(
|
||||
network: Network,
|
||||
networkCapabilities: NetworkCapabilities,
|
||||
) {
|
||||
super.onCapabilitiesChanged(network, networkCapabilities)
|
||||
mutableConnectionState.tryEmit(Unit)
|
||||
}
|
||||
|
||||
override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
|
||||
super.onLinkPropertiesChanged(network, linkProperties)
|
||||
mutableConnectionState.tryEmit(Unit)
|
||||
}
|
||||
|
||||
override fun onAvailable(network: Network) {
|
||||
super.onAvailable(network)
|
||||
mutableConnectionState.tryEmit(Unit)
|
||||
}
|
||||
|
||||
override fun onLost(network: Network) {
|
||||
super.onLost(network)
|
||||
mutableConnectionState.tryEmit(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the [NetworkCapabilities] to a [NetworkConnection].
|
||||
*/
|
||||
private val NetworkCapabilities?.networkConnection: NetworkConnection
|
||||
get() = this
|
||||
?.let {
|
||||
if (it.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
|
||||
NetworkConnection.Wifi(it.networkStrength)
|
||||
} else if (it.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
|
||||
NetworkConnection.Cellular
|
||||
} else {
|
||||
NetworkConnection.Other
|
||||
}
|
||||
}
|
||||
?: NetworkConnection.None
|
||||
|
||||
/**
|
||||
* Converts an integer value to an enum signal strength based on the RSSI standard.
|
||||
*
|
||||
* * -50 dBm: Excellent signal
|
||||
* * -60 to -75 dBm: Good signal
|
||||
* * -76 to -90 dBm: Fair signal
|
||||
* * -91 to -110 dBm: Weak signal
|
||||
* * -110 dBm and below: No signal
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
private val NetworkCapabilities.networkStrength: NetworkSignalStrength
|
||||
get() {
|
||||
val strength = this.signalStrength
|
||||
return when {
|
||||
(strength <= SIGNAL_STRENGTH_UNSPECIFIED) -> NetworkSignalStrength.UNKNOWN
|
||||
(strength <= -110) -> NetworkSignalStrength.NONE
|
||||
(strength <= -91) -> NetworkSignalStrength.WEAK
|
||||
(strength <= -76) -> NetworkSignalStrength.FAIR
|
||||
(strength <= -60) -> NetworkSignalStrength.GOOD
|
||||
else -> NetworkSignalStrength.EXCELLENT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,20 +4,67 @@ import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkRequest
|
||||
import app.cash.turbine.test
|
||||
import com.bitwarden.data.datasource.disk.base.FakeDispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.NetworkConnection
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.NetworkSignalStrength
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import org.junit.Test
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import io.mockk.mockkConstructor
|
||||
import io.mockk.runs
|
||||
import io.mockk.slot
|
||||
import io.mockk.unmockkConstructor
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class NetworkConnectionManagerTest {
|
||||
private val networkCallback = slot<ConnectivityManager.NetworkCallback>()
|
||||
private val connectivityManager = mockk<ConnectivityManager> {
|
||||
every {
|
||||
registerNetworkCallback(any<NetworkRequest>(), capture(networkCallback))
|
||||
} just runs
|
||||
every { activeNetwork } returns null
|
||||
every { getNetworkCapabilities(any()) } returns null
|
||||
}
|
||||
private val context = mockk<Context> {
|
||||
every { applicationContext } returns this
|
||||
every { getSystemService(Context.CONNECTIVITY_SERVICE) } returns connectivityManager
|
||||
}
|
||||
private val fakeDispatcherManager = FakeDispatcherManager()
|
||||
|
||||
private lateinit var networkConnectionManager: NetworkConnectionManagerImpl
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
mockkConstructor(NetworkRequest.Builder::class)
|
||||
val builder = mockk<NetworkRequest.Builder> {
|
||||
every { addTransportType(any()) } returns this
|
||||
every { build() } returns mockk()
|
||||
}
|
||||
every { anyConstructed<NetworkRequest.Builder>().addCapability(any()) } returns builder
|
||||
networkConnectionManager = NetworkConnectionManagerImpl(
|
||||
context = context,
|
||||
dispatcherManager = fakeDispatcherManager,
|
||||
)
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
unmockkConstructor(NetworkRequest.Builder::class)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isNetworkConnected should return false if no active network`() {
|
||||
val connectivityManager: ConnectivityManager = mockk {
|
||||
every { activeNetwork } returns null
|
||||
every { getNetworkCapabilities(any()) } returns null
|
||||
}
|
||||
val networkConnectionManager = createNetworkConnectionManager(connectivityManager)
|
||||
Assertions.assertFalse(networkConnectionManager.isNetworkConnected)
|
||||
every { connectivityManager.activeNetwork } returns null
|
||||
every { connectivityManager.getNetworkCapabilities(any()) } returns null
|
||||
assertFalse(networkConnectionManager.isNetworkConnected)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -26,12 +73,9 @@ class NetworkConnectionManagerTest {
|
||||
val networkCapabilities: NetworkCapabilities = mockk {
|
||||
every { hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) } returns false
|
||||
}
|
||||
val connectivityManager: ConnectivityManager = mockk {
|
||||
every { activeNetwork } returns network
|
||||
every { getNetworkCapabilities(network) } returns networkCapabilities
|
||||
}
|
||||
val networkConnectionManager = createNetworkConnectionManager(connectivityManager)
|
||||
Assertions.assertFalse(networkConnectionManager.isNetworkConnected)
|
||||
every { connectivityManager.activeNetwork } returns network
|
||||
every { connectivityManager.getNetworkCapabilities(network) } returns networkCapabilities
|
||||
assertFalse(networkConnectionManager.isNetworkConnected)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -40,24 +84,164 @@ class NetworkConnectionManagerTest {
|
||||
val networkCapabilities: NetworkCapabilities = mockk {
|
||||
every { hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) } returns true
|
||||
}
|
||||
val connectivityManager: ConnectivityManager = mockk {
|
||||
every { activeNetwork } returns network
|
||||
every { getNetworkCapabilities(network) } returns networkCapabilities
|
||||
}
|
||||
val networkConnectionManager = createNetworkConnectionManager(connectivityManager)
|
||||
Assertions.assertTrue(networkConnectionManager.isNetworkConnected)
|
||||
every { connectivityManager.activeNetwork } returns network
|
||||
every { connectivityManager.getNetworkCapabilities(network) } returns networkCapabilities
|
||||
assertTrue(networkConnectionManager.isNetworkConnected)
|
||||
}
|
||||
|
||||
private fun createNetworkConnectionManager(
|
||||
connectivityManager: ConnectivityManager,
|
||||
): NetworkConnectionManager {
|
||||
val appContext: Context = mockk {
|
||||
every { getSystemService(Context.CONNECTIVITY_SERVICE) } returns connectivityManager
|
||||
}
|
||||
val context: Context = mockk {
|
||||
every { applicationContext } returns appContext
|
||||
@Test
|
||||
fun `isNetworkConnectedFlow should emit changes to the network state`() = runTest {
|
||||
val network = mockk<Network>()
|
||||
val capabilities = mockk<NetworkCapabilities> {
|
||||
every { signalStrength } returns -75
|
||||
every { hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) } returns true
|
||||
every { hasTransport(NetworkCapabilities.TRANSPORT_WIFI) } returns false
|
||||
every { hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) } returns true
|
||||
}
|
||||
every { connectivityManager.activeNetwork } returns network
|
||||
|
||||
return NetworkConnectionManagerImpl(context)
|
||||
networkConnectionManager
|
||||
.isNetworkConnectedFlow
|
||||
.test {
|
||||
assertFalse(awaitItem())
|
||||
|
||||
every { connectivityManager.getNetworkCapabilities(network) } returns capabilities
|
||||
networkCallback.captured.onLost(mockk())
|
||||
assertTrue(awaitItem())
|
||||
|
||||
every {
|
||||
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
} returns false
|
||||
networkCallback.captured.onLinkPropertiesChanged(mockk(), mockk())
|
||||
assertFalse(awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `networkConnection should return None if no active network`() {
|
||||
every { connectivityManager.activeNetwork } returns null
|
||||
every { connectivityManager.getNetworkCapabilities(any()) } returns null
|
||||
assertEquals(NetworkConnection.None, networkConnectionManager.networkConnection)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `networkConnection should return none Wifi if active network has wifi transport`() {
|
||||
val network = mockk<Network>()
|
||||
val capabilities = mockk<NetworkCapabilities> {
|
||||
every { hasTransport(NetworkCapabilities.TRANSPORT_WIFI) } returns true
|
||||
every { signalStrength } returns -120
|
||||
}
|
||||
every { connectivityManager.activeNetwork } returns network
|
||||
every { connectivityManager.getNetworkCapabilities(network) } returns capabilities
|
||||
assertEquals(
|
||||
NetworkConnection.Wifi(strength = NetworkSignalStrength.NONE),
|
||||
networkConnectionManager.networkConnection,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `networkConnection should return weak Wifi if active network has wifi transport`() {
|
||||
val network = mockk<Network>()
|
||||
val capabilities = mockk<NetworkCapabilities> {
|
||||
every { hasTransport(NetworkCapabilities.TRANSPORT_WIFI) } returns true
|
||||
every { signalStrength } returns -100
|
||||
}
|
||||
every { connectivityManager.activeNetwork } returns network
|
||||
every { connectivityManager.getNetworkCapabilities(network) } returns capabilities
|
||||
assertEquals(
|
||||
NetworkConnection.Wifi(strength = NetworkSignalStrength.WEAK),
|
||||
networkConnectionManager.networkConnection,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `networkConnection should return fair Wifi if active network has wifi transport`() {
|
||||
val network = mockk<Network>()
|
||||
val capabilities = mockk<NetworkCapabilities> {
|
||||
every { hasTransport(NetworkCapabilities.TRANSPORT_WIFI) } returns true
|
||||
every { signalStrength } returns -90
|
||||
}
|
||||
every { connectivityManager.activeNetwork } returns network
|
||||
every { connectivityManager.getNetworkCapabilities(network) } returns capabilities
|
||||
assertEquals(
|
||||
NetworkConnection.Wifi(strength = NetworkSignalStrength.FAIR),
|
||||
networkConnectionManager.networkConnection,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `networkConnection should return good Wifi if active network has wifi transport`() {
|
||||
val network = mockk<Network>()
|
||||
val capabilities = mockk<NetworkCapabilities> {
|
||||
every { hasTransport(NetworkCapabilities.TRANSPORT_WIFI) } returns true
|
||||
every { signalStrength } returns -75
|
||||
}
|
||||
every { connectivityManager.activeNetwork } returns network
|
||||
every { connectivityManager.getNetworkCapabilities(network) } returns capabilities
|
||||
assertEquals(
|
||||
NetworkConnection.Wifi(strength = NetworkSignalStrength.GOOD),
|
||||
networkConnectionManager.networkConnection,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `networkConnection should return excellent Wifi if active network has wifi transport`() {
|
||||
val network = mockk<Network>()
|
||||
val capabilities = mockk<NetworkCapabilities> {
|
||||
every { hasTransport(NetworkCapabilities.TRANSPORT_WIFI) } returns true
|
||||
every { signalStrength } returns -50
|
||||
}
|
||||
every { connectivityManager.activeNetwork } returns network
|
||||
every { connectivityManager.getNetworkCapabilities(network) } returns capabilities
|
||||
assertEquals(
|
||||
NetworkConnection.Wifi(strength = NetworkSignalStrength.EXCELLENT),
|
||||
networkConnectionManager.networkConnection,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `networkConnection should return Cellular if active network has cellular transport`() {
|
||||
val network = mockk<Network>()
|
||||
val capabilities = mockk<NetworkCapabilities> {
|
||||
every { hasTransport(NetworkCapabilities.TRANSPORT_WIFI) } returns false
|
||||
every { hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) } returns true
|
||||
}
|
||||
every { connectivityManager.activeNetwork } returns network
|
||||
every { connectivityManager.getNetworkCapabilities(network) } returns capabilities
|
||||
assertEquals(NetworkConnection.Cellular, networkConnectionManager.networkConnection)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `networkConnectionFlow should emit changes to the network state`() = runTest {
|
||||
val network = mockk<Network>()
|
||||
val capabilities = mockk<NetworkCapabilities> {
|
||||
every { signalStrength } returns -75
|
||||
every { hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) } returns true
|
||||
every { hasTransport(NetworkCapabilities.TRANSPORT_WIFI) } returns false
|
||||
every { hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) } returns true
|
||||
}
|
||||
every { connectivityManager.activeNetwork } returns network
|
||||
|
||||
networkConnectionManager
|
||||
.networkConnectionFlow
|
||||
.test {
|
||||
assertEquals(NetworkConnection.None, awaitItem())
|
||||
|
||||
every { connectivityManager.getNetworkCapabilities(network) } returns capabilities
|
||||
networkCallback.captured.onCapabilitiesChanged(mockk(), mockk())
|
||||
assertEquals(NetworkConnection.Cellular, awaitItem())
|
||||
|
||||
every {
|
||||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
} returns true
|
||||
every {
|
||||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
} returns false
|
||||
networkCallback.captured.onAvailable(mockk())
|
||||
assertEquals(
|
||||
NetworkConnection.Wifi(strength = NetworkSignalStrength.GOOD),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,37 @@
|
||||
package com.x8bit.bitwarden.data.platform.manager.util
|
||||
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.NetworkConnection
|
||||
import com.x8bit.bitwarden.data.platform.manager.network.NetworkConnectionManager
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
class FakeNetworkConnectionManager(
|
||||
override val isNetworkConnected: Boolean,
|
||||
) : NetworkConnectionManager
|
||||
isNetworkConnected: Boolean,
|
||||
networkConnection: NetworkConnection,
|
||||
) : NetworkConnectionManager {
|
||||
private val mutableIsNetworkConnectedStateFlow = MutableStateFlow<Boolean>(isNetworkConnected)
|
||||
private val mutableNetworkConnectionStateFlow = MutableStateFlow(networkConnection)
|
||||
|
||||
var fakeIsNetworkConnected: Boolean
|
||||
get() = mutableIsNetworkConnectedStateFlow.value
|
||||
set(value) {
|
||||
mutableIsNetworkConnectedStateFlow.value = value
|
||||
}
|
||||
|
||||
var fakeNetworkConnection: NetworkConnection
|
||||
get() = mutableNetworkConnectionStateFlow.value
|
||||
set(value) {
|
||||
mutableNetworkConnectionStateFlow.value = value
|
||||
}
|
||||
|
||||
override val isNetworkConnected: Boolean get() = fakeIsNetworkConnected
|
||||
|
||||
override val isNetworkConnectedFlow: StateFlow<Boolean> =
|
||||
mutableIsNetworkConnectedStateFlow.asStateFlow()
|
||||
|
||||
override val networkConnection: NetworkConnection get() = fakeNetworkConnection
|
||||
|
||||
override val networkConnectionFlow: StateFlow<NetworkConnection> =
|
||||
mutableNetworkConnectionStateFlow.asStateFlow()
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.x8bit.bitwarden.data.auth.repository.util.generateUriForCaptcha
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.generateUriForSso
|
||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.NetworkConnection
|
||||
import com.x8bit.bitwarden.data.platform.manager.util.FakeNetworkConnectionManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
|
||||
@@ -1186,7 +1187,10 @@ class EnterpriseSignOnViewModelTest : BaseViewModelTest() {
|
||||
environmentRepository = environmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
generatorRepository = generatorRepository,
|
||||
networkConnectionManager = FakeNetworkConnectionManager(isNetworkConnected),
|
||||
networkConnectionManager = FakeNetworkConnectionManager(
|
||||
isNetworkConnected = isNetworkConnected,
|
||||
networkConnection = NetworkConnection.Cellular,
|
||||
),
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
.also {
|
||||
|
||||
Reference in New Issue
Block a user