Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 40ddf4b8 authored by Caitlin Shkuratov's avatar Caitlin Shkuratov
Browse files

[SB Refactor] Add tracking for wifi enabled state and pipe it through to

the UI.

Bug: 238425913
Test: manual: Turn on airplane mode and verify wifi icon disappears
(airplane mode => wifiEnabled = false)
Test: manual: Turn off airplane mode and verify icon reappears
Test: statusbar.pipeline tests

Change-Id: Idee192ffc6a26a180f2ff04213ffd3fd8a2f0ee4
parent e41d5cc7
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ 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.shared.ConnectivityPipelineLogger.Companion.logOutputChange
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
@@ -43,13 +44,21 @@ import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.stateIn

/** Provides data related to the wifi state. */
interface WifiRepository {
    /** Observable for the current wifi enabled status. */
    val isWifiEnabled: StateFlow<Boolean>

    /** Observable for the current wifi network. */
    val wifiNetwork: StateFlow<WifiNetworkModel>

@@ -68,6 +77,34 @@ class WifiRepositoryImpl @Inject constructor(
    @Application scope: CoroutineScope,
    wifiManager: WifiManager?,
) : WifiRepository {

    /**
     * A flow that emits [Unit] whenever the wifi state may have changed.
     *
     * Because [WifiManager] doesn't expose a wifi state change listener, we do it internally by
     * emitting to this flow whenever we think the state may have changed.
     *
     * TODO(b/238425913): We also need to emit to this flow whenever the WIFI_STATE_CHANGED_ACTION
     *   intent is triggered.
     */
    private val _wifiStateChangeEvents: MutableSharedFlow<Unit> =
        MutableSharedFlow(extraBufferCapacity = 1)

    override val isWifiEnabled: StateFlow<Boolean> =
        if (wifiManager == null) {
            MutableStateFlow(false).asStateFlow()
        } else {
            _wifiStateChangeEvents
                .mapLatest { wifiManager.isWifiEnabled }
                .distinctUntilChanged()
                .logOutputChange(logger, "enabled")
                .stateIn(
                    scope = scope,
                    started = SharingStarted.WhileSubscribed(),
                    initialValue = wifiManager.isWifiEnabled
                )
        }

    override val wifiNetwork: StateFlow<WifiNetworkModel> = conflatedCallbackFlow {
        var currentWifi: WifiNetworkModel = WIFI_NETWORK_DEFAULT

@@ -78,6 +115,8 @@ class WifiRepositoryImpl @Inject constructor(
            ) {
                logger.logOnCapabilitiesChanged(network, networkCapabilities)

                _wifiStateChangeEvents.tryEmit(Unit)

                val wifiInfo = networkCapabilitiesToWifiInfo(networkCapabilities)
                if (wifiInfo?.isPrimary == true) {
                    val wifiNetworkModel = createWifiNetworkModel(
@@ -98,6 +137,9 @@ class WifiRepositoryImpl @Inject constructor(

            override fun onLost(network: Network) {
                logger.logOnLost(network)

                _wifiStateChangeEvents.tryEmit(Unit)

                val wifi = currentWifi
                if (wifi is WifiNetworkModel.Active && wifi.networkId == network.getNetId()) {
                    val newNetworkModel = WifiNetworkModel.Inactive
+3 −0
Original line number Diff line number Diff line
@@ -56,6 +56,9 @@ class WifiInteractor @Inject constructor(
        }
    }

    /** Our current enabled status. */
    val isEnabled: Flow<Boolean> = wifiRepository.isWifiEnabled

    /** Our current wifi network. See [WifiNetworkModel]. */
    val wifiNetwork: Flow<WifiNetworkModel> = wifiRepository.wifiNetwork

+4 −2
Original line number Diff line number Diff line
@@ -122,11 +122,13 @@ constructor(
    /** The wifi icon that should be displayed. Null if we shouldn't display any icon. */
    private val wifiIcon: Flow<Icon?> =
        combine(
            interactor.isEnabled,
            interactor.isForceHidden,
            iconResId,
            contentDescription,
        ) { isForceHidden, iconResId, contentDescription ->
        ) { isEnabled, isForceHidden, iconResId, contentDescription ->
            when {
                !isEnabled ||
                    isForceHidden ||
                    iconResId == null ||
                    iconResId <= 0 -> null
+7 −0
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@ import kotlinx.coroutines.flow.StateFlow

/** Fake implementation of [WifiRepository] exposing set methods for all the flows. */
class FakeWifiRepository : WifiRepository {
    private val _isWifiEnabled: MutableStateFlow<Boolean> = MutableStateFlow(false)
    override val isWifiEnabled: StateFlow<Boolean> = _isWifiEnabled

    private val _wifiNetwork: MutableStateFlow<WifiNetworkModel> =
        MutableStateFlow(WifiNetworkModel.Inactive)
    override val wifiNetwork: StateFlow<WifiNetworkModel> = _wifiNetwork
@@ -31,6 +34,10 @@ class FakeWifiRepository : WifiRepository {
    private val _wifiActivity = MutableStateFlow(ACTIVITY_DEFAULT)
    override val wifiActivity: StateFlow<WifiActivityModel> = _wifiActivity

    fun setIsWifiEnabled(enabled: Boolean) {
        _isWifiEnabled.value = enabled
    }

    fun setWifiNetwork(wifiNetworkModel: WifiNetworkModel) {
        _wifiNetwork.value = wifiNetworkModel
    }
+72 −0
Original line number Diff line number Diff line
@@ -87,6 +87,78 @@ class WifiRepositoryImplTest : SysuiTestCase() {
        scope.cancel()
    }

    @Test
    fun isWifiEnabled_nullWifiManager_getsFalse() = runBlocking(IMMEDIATE) {
        underTest = WifiRepositoryImpl(
            connectivityManager,
            logger,
            executor,
            scope,
            wifiManager = null,
        )

        assertThat(underTest.isWifiEnabled.value).isFalse()
    }

    @Test
    fun isWifiEnabled_initiallyGetsWifiManagerValue() = runBlocking(IMMEDIATE) {
        whenever(wifiManager.isWifiEnabled).thenReturn(true)

        underTest = WifiRepositoryImpl(
            connectivityManager,
            logger,
            executor,
            scope,
            wifiManager
        )

        assertThat(underTest.isWifiEnabled.value).isTrue()
    }

    @Test
    fun isWifiEnabled_networkCapabilitiesChanged_valueUpdated() = runBlocking(IMMEDIATE) {
        // We need to call launch on the flows so that they start updating
        val networkJob = underTest.wifiNetwork.launchIn(this)
        val enabledJob = underTest.isWifiEnabled.launchIn(this)

        whenever(wifiManager.isWifiEnabled).thenReturn(true)
        getNetworkCallback().onCapabilitiesChanged(
            NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)
        )

        assertThat(underTest.isWifiEnabled.value).isTrue()

        whenever(wifiManager.isWifiEnabled).thenReturn(false)
        getNetworkCallback().onCapabilitiesChanged(
            NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)
        )

        assertThat(underTest.isWifiEnabled.value).isFalse()

        networkJob.cancel()
        enabledJob.cancel()
    }

    @Test
    fun isWifiEnabled_networkLost_valueUpdated() = runBlocking(IMMEDIATE) {
        // We need to call launch on the flows so that they start updating
        val networkJob = underTest.wifiNetwork.launchIn(this)
        val enabledJob = underTest.isWifiEnabled.launchIn(this)

        whenever(wifiManager.isWifiEnabled).thenReturn(true)
        getNetworkCallback().onLost(NETWORK)

        assertThat(underTest.isWifiEnabled.value).isTrue()

        whenever(wifiManager.isWifiEnabled).thenReturn(false)
        getNetworkCallback().onLost(NETWORK)

        assertThat(underTest.isWifiEnabled.value).isFalse()

        networkJob.cancel()
        enabledJob.cancel()
    }

    @Test
    fun wifiNetwork_initiallyGetsDefault() = runBlocking(IMMEDIATE) {
        var latest: WifiNetworkModel? = null
Loading