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

Commit 1adda683 authored by Caitlin Shkuratov's avatar Caitlin Shkuratov
Browse files

[Status Bar] Implement wifi activity in WifiRepositoryViaTrackerLib.

Bug: 292534484
Test: turn on config to show activity & turn on flag -> verify wifi
indicator shows activity and updates based on callbacks
Test: atest WifiRepositoryViaTrackerLibTest

Change-Id: I9e297db28be85505ce80e8e491be3e8853d7244d
parent cadad8e4
Loading
Loading
Loading
Loading
+80 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.wifi.data.repository.prod

import android.net.wifi.WifiManager
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel
import java.util.concurrent.Executor
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn

/**
 * Object to provide shared helper functions between [WifiRepositoryImpl] and
 * [WifiRepositoryViaTrackerLib].
 */
object WifiRepositoryHelper {
    /** Creates a flow that fetches the [DataActivityModel] from [WifiManager]. */
    fun createActivityFlow(
        wifiManager: WifiManager,
        @Main mainExecutor: Executor,
        scope: CoroutineScope,
        tableLogBuffer: TableLogBuffer,
        inputLogger: (String) -> Unit,
    ): StateFlow<DataActivityModel> {
        return conflatedCallbackFlow {
                val callback =
                    WifiManager.TrafficStateCallback { state ->
                        inputLogger.invoke(prettyPrintActivity(state))
                        trySend(state.toWifiDataActivityModel())
                    }
                wifiManager.registerTrafficStateCallback(mainExecutor, callback)
                awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
            }
            .logDiffsForTable(
                tableLogBuffer,
                columnPrefix = ACTIVITY_PREFIX,
                initialValue = ACTIVITY_DEFAULT,
            )
            .stateIn(
                scope,
                started = SharingStarted.WhileSubscribed(),
                initialValue = ACTIVITY_DEFAULT,
            )
    }

    // TODO(b/292534484): This print should only be done in [MessagePrinter] part of the log buffer.
    private fun prettyPrintActivity(activity: Int): String {
        return when (activity) {
            WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE -> "NONE"
            WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN -> "IN"
            WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT -> "OUT"
            WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT -> "INOUT"
            else -> "INVALID"
        }
    }

    private const val ACTIVITY_PREFIX = "wifiActivity"
    val ACTIVITY_DEFAULT = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
}
+7 −33
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.NetworkRequest
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
import android.net.wifi.WifiManager.TrafficStateCallback
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -40,7 +39,6 @@ import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.getMainOrUnderlyingWifiInfo
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
@@ -218,29 +216,15 @@ constructor(
            )

    override val wifiActivity: StateFlow<DataActivityModel> =
        conflatedCallbackFlow {
                val callback = TrafficStateCallback { state ->
                    logger.logActivity(prettyPrintActivity(state))
                    trySend(state.toWifiDataActivityModel())
                }
                wifiManager.registerTrafficStateCallback(mainExecutor, callback)
                awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
            }
            .logDiffsForTable(
                wifiTableLogBuffer,
                columnPrefix = ACTIVITY_PREFIX,
                initialValue = ACTIVITY_DEFAULT,
            )
            .stateIn(
        WifiRepositoryHelper.createActivityFlow(
            wifiManager,
            mainExecutor,
            scope,
                started = SharingStarted.WhileSubscribed(),
                initialValue = ACTIVITY_DEFAULT,
            wifiTableLogBuffer,
            logger::logActivity,
        )

    companion object {
        private const val ACTIVITY_PREFIX = "wifiActivity"

        val ACTIVITY_DEFAULT = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
        // Start out with no known wifi network.
        // Note: [WifiStatusTracker] (the old implementation of connectivity logic) does do an
        // initial fetch to get a starting wifi network. But, it uses a deprecated API
@@ -284,16 +268,6 @@ constructor(
            }
        }

        private fun prettyPrintActivity(activity: Int): String {
            return when (activity) {
                TrafficStateCallback.DATA_ACTIVITY_NONE -> "NONE"
                TrafficStateCallback.DATA_ACTIVITY_IN -> "IN"
                TrafficStateCallback.DATA_ACTIVITY_OUT -> "OUT"
                TrafficStateCallback.DATA_ACTIVITY_INOUT -> "INOUT"
                else -> "INVALID"
            }
        }

        private val WIFI_NETWORK_CALLBACK_REQUEST: NetworkRequest =
            NetworkRequest.Builder()
                .clearCapabilities()
+11 −4
Original line number Diff line number Diff line
@@ -44,7 +44,6 @@ import java.util.concurrent.Executor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
@@ -208,10 +207,14 @@ constructor(
            )
            .stateIn(scope, SharingStarted.WhileSubscribed(), false)

    // TODO(b/292534484): Re-use WifiRepositoryImpl code to implement wifi activity since
    // WifiTrackerLib doesn't expose activity details.
    override val wifiActivity: StateFlow<DataActivityModel> =
        MutableStateFlow(DataActivityModel(false, false))
        WifiRepositoryHelper.createActivityFlow(
            wifiManager,
            mainExecutor,
            scope,
            wifiTrackerLibTableLogBuffer,
            this::logActivity,
        )

    private fun logOnWifiEntriesChanged(connectedEntry: WifiEntry?) {
        inputLogger.log(
@@ -231,6 +234,10 @@ constructor(
        )
    }

    private fun logActivity(activity: String) {
        inputLogger.log(TAG, LogLevel.DEBUG, { str1 = activity }, { "onActivityChanged: $str1" })
    }

    /**
     * Data class storing all the information fetched from [WifiPickerTracker].
     *
+1 −1
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.pipeline.wifi.data.repository

import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryHelper.ACTIVITY_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
+57 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.util.concurrency.FakeExecutor
@@ -45,6 +46,7 @@ import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito.verify

/**
 * Note: Most of these tests are duplicates of [WifiRepositoryImplTest] tests.
@@ -643,11 +645,66 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
            assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
        }

    @Test
    fun wifiActivity_callbackGivesNone_activityFlowHasNone() =
        testScope.runTest {
            val latest by collectLastValue(underTest.wifiActivity)

            getTrafficStateCallback()
                .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE)

            assertThat(latest)
                .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
        }

    @Test
    fun wifiActivity_callbackGivesIn_activityFlowHasIn() =
        testScope.runTest {
            val latest by collectLastValue(underTest.wifiActivity)

            getTrafficStateCallback()
                .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN)

            assertThat(latest)
                .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = false))
        }

    @Test
    fun wifiActivity_callbackGivesOut_activityFlowHasOut() =
        testScope.runTest {
            val latest by collectLastValue(underTest.wifiActivity)

            getTrafficStateCallback()
                .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT)

            assertThat(latest)
                .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = true))
        }

    @Test
    fun wifiActivity_callbackGivesInout_activityFlowHasInAndOut() =
        testScope.runTest {
            val latest by collectLastValue(underTest.wifiActivity)

            getTrafficStateCallback()
                .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT)

            assertThat(latest)
                .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true))
        }

    private fun getCallback(): WifiPickerTracker.WifiPickerTrackerCallback {
        testScope.runCurrent()
        return callbackCaptor.value
    }

    private fun getTrafficStateCallback(): WifiManager.TrafficStateCallback {
        testScope.runCurrent()
        val callbackCaptor = argumentCaptor<WifiManager.TrafficStateCallback>()
        verify(wifiManager).registerTrafficStateCallback(any(), callbackCaptor.capture())
        return callbackCaptor.value!!
    }

    private fun createRepo(): WifiRepositoryViaTrackerLib {
        return WifiRepositoryViaTrackerLib(
            testScope.backgroundScope,