diff options
| author | 2023-08-15 15:50:19 -0400 | |
|---|---|---|
| committer | 2023-08-24 16:44:05 -0400 | |
| commit | fef3c333050e974bcb265de9c6ed63eb866d067c (patch) | |
| tree | 890426e5dfb8461aecba0d62362aa1eb15b35431 | |
| parent | e2b3d6dc375058720c79e335145b864a3de5d4a0 (diff) | |
[Sb refactor] Add network scan results to wifi repo
Adds the `WifiManager.registerScanResultsCallback` information to
`WifiRepository`, and `areNetworksAvailable` to the `WifiInteractor`.
This allows us to fund the QS tile with information about any other
networks being available.
This logic should match exactly the information that comes from the old
data pipeline.
Test: tests in statusbar/pipeline
Bug: 291321279
Change-Id: Ic8a632ecb19b74d99896fd0aef038f3c147a0290
19 files changed, 356 insertions, 14 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt index b5b99a76ded8..b22e09e9ba40 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.wifi.data.repository import com.android.systemui.CoreStartable import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import kotlinx.coroutines.flow.StateFlow /** Provides data related to the wifi state. */ @@ -45,6 +46,12 @@ interface WifiRepository { val wifiActivity: StateFlow<DataActivityModel> /** + * The list of known wifi networks, per [WifiManager.scanResults]. This list is passively + * updated and does not trigger a scan. + */ + val wifiScanResults: StateFlow<List<WifiScanEntry>> + + /** * Returns true if the device is currently connected to a wifi network with a valid SSID and * false otherwise. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt index 80091ac7bdba..ca042e26b20b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt @@ -27,6 +27,7 @@ import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityMod import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoWifiRepository import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -124,4 +125,9 @@ constructor( activeRepo .flatMapLatest { it.wifiActivity } .stateIn(scope, SharingStarted.WhileSubscribed(), realImpl.wifiActivity.value) + + override val wifiScanResults: StateFlow<List<WifiScanEntry>> = + activeRepo + .flatMapLatest { it.wifiScanResults } + .stateIn(scope, SharingStarted.WhileSubscribed(), realImpl.wifiScanResults.value) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt index 4b19c3a153ed..152d181bfc16 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt @@ -22,6 +22,7 @@ import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActiv import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job @@ -55,6 +56,10 @@ constructor( MutableStateFlow(DataActivityModel(hasActivityIn = false, hasActivityOut = false)) override val wifiActivity: StateFlow<DataActivityModel> = _wifiActivity + private val _wifiScanResults: MutableStateFlow<List<WifiScanEntry>> = + MutableStateFlow(emptyList()) + override val wifiScanResults: StateFlow<List<WifiScanEntry>> = _wifiScanResults + fun startProcessingCommands() { demoCommandJob = scope.launch { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt index 36c46a90c731..cfdbe4a9bb6e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt @@ -21,6 +21,7 @@ import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityMod import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryDagger import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryViaTrackerLibDagger import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -49,6 +50,9 @@ class DisabledWifiRepository @Inject constructor() : override val wifiActivity: StateFlow<DataActivityModel> = MutableStateFlow(ACTIVITY).asStateFlow() + override val wifiScanResults: StateFlow<List<WifiScanEntry>> = + MutableStateFlow<List<WifiScanEntry>>(emptyList()).asStateFlow() + companion object { private val NETWORK = WifiNetworkModel.Unavailable private val ACTIVITY = DataActivityModel(hasActivityIn = false, hasActivityOut = false) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt index f1b98b3972e1..67dd32f473e0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt @@ -16,15 +16,21 @@ package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod +import android.annotation.SuppressLint +import android.net.wifi.ScanResult import android.net.wifi.WifiManager import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.dagger.qualifiers.Background 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 com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import java.util.concurrent.Executor +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.asExecutor import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -64,6 +70,34 @@ object WifiRepositoryHelper { ) } + /** + * Creates a flow that listens for new [ScanResult]s from [WifiManager]. Does not request a scan + */ + fun createNetworkScanFlow( + wifiManager: WifiManager, + scope: CoroutineScope, + @Background dispatcher: CoroutineDispatcher, + inputLogger: () -> Unit, + ): StateFlow<List<WifiScanEntry>> { + return conflatedCallbackFlow { + val callback = + object : WifiManager.ScanResultsCallback() { + @SuppressLint("MissingPermission") + override fun onScanResultsAvailable() { + inputLogger.invoke() + trySend(wifiManager.scanResults.toModel()) + } + } + + wifiManager.registerScanResultsCallback(dispatcher.asExecutor(), callback) + + awaitClose { wifiManager.unregisterScanResultsCallback(callback) } + } + .stateIn(scope, SharingStarted.Eagerly, emptyList()) + } + + private fun List<ScanResult>.toModel(): List<WifiScanEntry> = map { WifiScanEntry(it.SSID) } + // 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) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt index 7c7b58d00e3b..59ef8846e281 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt @@ -48,6 +48,7 @@ import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiReposito import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryDagger import com.android.systemui.statusbar.pipeline.wifi.shared.WifiInputLogger import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import java.util.concurrent.Executor import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher @@ -231,6 +232,14 @@ constructor( logger::logActivity, ) + override val wifiScanResults: StateFlow<List<WifiScanEntry>> = + WifiRepositoryHelper.createNetworkScanFlow( + wifiManager, + scope, + bgDispatcher, + logger::logScanResults + ) + companion object { // Start out with no known wifi network. // Note: [WifiStatusTracker] (the old implementation of connectivity logic) does do an diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt index d4f40dd03a32..9b404f187c88 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt @@ -23,6 +23,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleRegistry import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags @@ -42,6 +43,7 @@ import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRep import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_STATE_DEFAULT import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel.Inactive.toHotspotDeviceType +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import com.android.wifitrackerlib.HotspotNetworkEntry import com.android.wifitrackerlib.MergedCarrierEntry import com.android.wifitrackerlib.WifiEntry @@ -51,6 +53,7 @@ import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE import com.android.wifitrackerlib.WifiPickerTracker import java.util.concurrent.Executor import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.SharingStarted @@ -73,6 +76,7 @@ constructor( featureFlags: FeatureFlags, @Application private val scope: CoroutineScope, @Main private val mainExecutor: Executor, + @Background private val bgDispatcher: CoroutineDispatcher, private val wifiPickerTrackerFactory: WifiPickerTrackerFactory, private val wifiManager: WifiManager, @WifiTrackerLibInputLog private val inputLogger: LogBuffer, @@ -300,6 +304,14 @@ constructor( this::logActivity, ) + override val wifiScanResults: StateFlow<List<WifiScanEntry>> = + WifiRepositoryHelper.createNetworkScanFlow( + wifiManager, + scope, + bgDispatcher, + this::logScanResults, + ) + private fun logOnWifiEntriesChanged(connectedEntry: WifiEntry?) { inputLogger.log( TAG, @@ -322,6 +334,9 @@ constructor( inputLogger.log(TAG, LogLevel.DEBUG, { str1 = activity }, { "onActivityChanged: $str1" }) } + private fun logScanResults() = + inputLogger.log(TAG, LogLevel.DEBUG, {}, { "onScanResultsAvailable" }) + /** * Data class storing all the information fetched from [WifiPickerTracker]. * @@ -345,6 +360,7 @@ constructor( private val featureFlags: FeatureFlags, @Application private val scope: CoroutineScope, @Main private val mainExecutor: Executor, + @Background private val bgDispatcher: CoroutineDispatcher, private val wifiPickerTrackerFactory: WifiPickerTrackerFactory, @WifiTrackerLibInputLog private val inputLogger: LogBuffer, @WifiTrackerLibTableLog private val wifiTrackerLibTableLogBuffer: TableLogBuffer, @@ -354,6 +370,7 @@ constructor( featureFlags, scope, mainExecutor, + bgDispatcher, wifiPickerTrackerFactory, wifiManager, inputLogger, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt index 2bce0d1834b6..110e3390e722 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt @@ -17,16 +17,21 @@ package com.android.systemui.statusbar.pipeline.wifi.domain.interactor import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn /** * The business logic layer for the wifi icon. @@ -66,6 +71,7 @@ class WifiInteractorImpl constructor( connectivityRepository: ConnectivityRepository, wifiRepository: WifiRepository, + @Application scope: CoroutineScope, ) : WifiInteractor { override val ssid: Flow<String?> = @@ -96,5 +102,25 @@ constructor( override val isForceHidden: Flow<Boolean> = connectivityRepository.forceHiddenSlots.map { it.contains(ConnectivitySlot.WIFI) } - override val areNetworksAvailable: StateFlow<Boolean> = MutableStateFlow(false) + override val areNetworksAvailable: StateFlow<Boolean> = + combine( + wifiNetwork, + wifiRepository.wifiScanResults, + ) { currentNetwork, scanResults -> + // We consider networks to be available if the scan results list contains networks + // other than the one that is currently connected + if (scanResults.isEmpty()) { + false + } else if (currentNetwork !is WifiNetworkModel.Active) { + true + } else { + anyNonMatchingNetworkExists(currentNetwork, scanResults) + } + } + .stateIn(scope, SharingStarted.WhileSubscribed(), false) + + private fun anyNonMatchingNetworkExists( + currentNetwork: WifiNetworkModel.Active, + availableNetworks: List<WifiScanEntry> + ): Boolean = availableNetworks.firstOrNull { it.ssid != currentNetwork.ssid } != null } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt index f244376f5a5a..b76bb51bfcb8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt @@ -59,6 +59,8 @@ constructor( fun logActivity(activity: String) { buffer.log(TAG, LogLevel.DEBUG, { str1 = activity }, { "Activity: $str1" }) } + + fun logScanResults() = buffer.log(TAG, LogLevel.DEBUG, {}, { "onScanResultsAvailable" }) } private const val TAG = "WifiInputLog" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiScanEntry.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiScanEntry.kt new file mode 100644 index 000000000000..d4a5a0e5cca9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiScanEntry.kt @@ -0,0 +1,23 @@ +/* + * 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.shared.model + +/** + * Represents a single entry in the scan results callback. Use the [ssid] field to check against + * other networks + */ +data class WifiScanEntry(val ssid: String) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java index c658eb43ce10..e537131bad01 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java @@ -39,6 +39,7 @@ import androidx.lifecycle.LifecycleOwner; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; +import com.android.keyguard.TestScopeProvider; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.classifier.FalsingManagerFake; @@ -74,6 +75,8 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; +import kotlinx.coroutines.test.TestScope; + @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest @@ -110,6 +113,7 @@ public class CastTileTest extends SysuiTestCase { private final TileJavaAdapter mJavaAdapter = new TileJavaAdapter(); private final FakeWifiRepository mWifiRepository = new FakeWifiRepository(); private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); + private final TestScope mTestScope = TestScopeProvider.getTestScope(); private TestableLooper mTestableLooper; private CastTile mCastTile; @@ -123,7 +127,8 @@ public class CastTileTest extends SysuiTestCase { mWifiInteractor = new WifiInteractorImpl( new FakeConnectivityRepository(), - mWifiRepository + mWifiRepository, + mTestScope ); } @@ -141,7 +146,7 @@ public class CastTileTest extends SysuiTestCase { IconState qsIcon = new IconState(false, 0, ""); WifiIndicators indicators = new WifiIndicators( false, mock(IconState.class), - qsIcon, false,false, "", + qsIcon, false, false, "", false, ""); mSignalCallback.setWifiIndicators(indicators); mTestableLooper.processAllMessages(); @@ -155,7 +160,7 @@ public class CastTileTest extends SysuiTestCase { IconState qsIcon = new IconState(false, 0, ""); WifiIndicators indicators = new WifiIndicators( true, mock(IconState.class), - qsIcon, false,false, "", + qsIcon, false, false, "", false, ""); mSignalCallback.setWifiIndicators(indicators); mTestableLooper.processAllMessages(); @@ -167,7 +172,7 @@ public class CastTileTest extends SysuiTestCase { IconState qsIcon = new IconState(true, 0, ""); WifiIndicators indicators = new WifiIndicators( true, mock(IconState.class), - qsIcon, false,false, "", + qsIcon, false, false, "", false, ""); mSignalCallback.setWifiIndicators(indicators); mTestableLooper.processAllMessages(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt index 6fdca5f95e57..8150a313abe6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt @@ -40,6 +40,7 @@ import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.InternetTileV import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon import com.android.systemui.util.CarrierConfigTracker import com.android.systemui.util.mockito.mock @@ -58,9 +59,10 @@ class InternetTileViewModelTest : SysuiTestCase() { private val connectivityRepository = FakeConnectivityRepository() private val ethernetInteractor = EthernetInteractor(connectivityRepository) private val wifiRepository = FakeWifiRepository() - private val wifiInteractor = WifiInteractorImpl(connectivityRepository, wifiRepository) private val userSetupRepo = FakeUserSetupRepository() private val testScope = TestScope() + private val wifiInteractor = + WifiInteractorImpl(connectivityRepository, wifiRepository, testScope.backgroundScope) private val tableLogBuffer: TableLogBuffer = mock() private val carrierConfigTracker: CarrierConfigTracker = mock() @@ -162,6 +164,7 @@ class InternetTileViewModelTest : SysuiTestCase() { connectivityRepository.setWifiConnected(validated = false) wifiRepository.setIsWifiDefault(true) wifiRepository.setWifiNetwork(networkModel) + wifiRepository.wifiScanResults.value = emptyList() assertThat(latest).isEqualTo(NOT_CONNECTED_NETWORKS_UNAVAILABLE) } @@ -176,15 +179,13 @@ class InternetTileViewModelTest : SysuiTestCase() { connectivityRepository.setWifiConnected(validated = false) wifiRepository.setIsWifiDefault(true) wifiRepository.setWifiNetwork(networkModel) + wifiRepository.wifiScanResults.value = listOf(WifiScanEntry("test 1")) - /* - TODO: enable this once we support areNetworksAvailable assertThat(latest?.secondaryLabel).isNull() assertThat(latest?.secondaryTitle) .isEqualTo(context.getString(R.string.quick_settings_networks_available)) assertThat(latest?.icon).isNull() assertThat(latest?.iconId).isEqualTo(R.drawable.ic_qs_no_internet_available) - */ } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt index 4f7bb724aae3..106b54891948 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt @@ -19,6 +19,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.WifiRepositoryHelper.ACTIVITY_DEFAULT import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -39,6 +40,9 @@ class FakeWifiRepository : WifiRepository { private val _wifiActivity = MutableStateFlow(ACTIVITY_DEFAULT) override val wifiActivity: StateFlow<DataActivityModel> = _wifiActivity + override val wifiScanResults: MutableStateFlow<List<WifiScanEntry>> = + MutableStateFlow(emptyList()) + fun setIsWifiEnabled(enabled: Boolean) { _isWifiEnabled.value = enabled } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt index bea1154eeb34..c2e75aa85fcb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt @@ -27,6 +27,7 @@ import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.TransportInfo import android.net.VpnTransportInfo import android.net.vcn.VcnTransportInfo +import android.net.wifi.ScanResult import android.net.wifi.WifiInfo import android.net.wifi.WifiManager import android.net.wifi.WifiManager.TrafficStateCallback @@ -45,6 +46,7 @@ import com.android.systemui.statusbar.pipeline.shared.data.repository.Connectivi import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT import com.android.systemui.statusbar.pipeline.wifi.shared.WifiInputLogger import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor @@ -1205,6 +1207,58 @@ class WifiRepositoryImplTest : SysuiTestCase() { .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true)) } + @Test + fun wifiScanResults_containsSsidList() = + testScope.runTest { + val latest by collectLastValue(underTest.wifiScanResults) + + val scanResults = + listOf( + ScanResult().also { it.SSID = "ssid 1" }, + ScanResult().also { it.SSID = "ssid 2" }, + ScanResult().also { it.SSID = "ssid 3" }, + ScanResult().also { it.SSID = "ssid 4" }, + ScanResult().also { it.SSID = "ssid 5" }, + ) + whenever(wifiManager.scanResults).thenReturn(scanResults) + getScanResultsCallback().onScanResultsAvailable() + + val expected = + listOf( + WifiScanEntry(ssid = "ssid 1"), + WifiScanEntry(ssid = "ssid 2"), + WifiScanEntry(ssid = "ssid 3"), + WifiScanEntry(ssid = "ssid 4"), + WifiScanEntry(ssid = "ssid 5"), + ) + + assertThat(latest).isEqualTo(expected) + } + + @Test + fun wifiScanResults_updates() = + testScope.runTest { + val latest by collectLastValue(underTest.wifiScanResults) + + var scanResults = + listOf( + ScanResult().also { it.SSID = "ssid 1" }, + ScanResult().also { it.SSID = "ssid 2" }, + ScanResult().also { it.SSID = "ssid 3" }, + ScanResult().also { it.SSID = "ssid 4" }, + ScanResult().also { it.SSID = "ssid 5" }, + ) + whenever(wifiManager.scanResults).thenReturn(scanResults) + getScanResultsCallback().onScanResultsAvailable() + + // New scan representing no results + scanResults = emptyList() + whenever(wifiManager.scanResults).thenReturn(scanResults) + getScanResultsCallback().onScanResultsAvailable() + + assertThat(latest).isEmpty() + } + private fun createRepo(): WifiRepositoryImpl { return WifiRepositoryImpl( fakeBroadcastDispatcher, @@ -1240,6 +1294,13 @@ class WifiRepositoryImplTest : SysuiTestCase() { return callbackCaptor.value!! } + private fun getScanResultsCallback(): WifiManager.ScanResultsCallback { + testScope.runCurrent() + val callbackCaptor = argumentCaptor<WifiManager.ScanResultsCallback>() + verify(wifiManager).registerScanResultsCallback(any(), callbackCaptor.capture()) + return callbackCaptor.value!! + } + private fun createWifiNetworkCapabilities( transportInfo: TransportInfo, isValidated: Boolean = true, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt index 662e36a55b9b..afab6230df5b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod +import android.net.wifi.ScanResult import android.net.wifi.WifiManager import android.net.wifi.WifiManager.UNKNOWN_SSID import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo @@ -32,6 +33,7 @@ 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.statusbar.pipeline.wifi.shared.model.WifiScanEntry import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor @@ -77,6 +79,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() { featureFlags, testScope.backgroundScope, executor, + dispatcher, wifiPickerTrackerFactory, wifiManager, logger, @@ -1137,6 +1140,58 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() { .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true)) } + @Test + fun wifiScanResults_containsSsidList() = + testScope.runTest { + val latest by collectLastValue(underTest.wifiScanResults) + + val scanResults = + listOf( + ScanResult().also { it.SSID = "ssid 1" }, + ScanResult().also { it.SSID = "ssid 2" }, + ScanResult().also { it.SSID = "ssid 3" }, + ScanResult().also { it.SSID = "ssid 4" }, + ScanResult().also { it.SSID = "ssid 5" }, + ) + whenever(wifiManager.scanResults).thenReturn(scanResults) + getScanResultsCallback().onScanResultsAvailable() + + val expected = + listOf( + WifiScanEntry(ssid = "ssid 1"), + WifiScanEntry(ssid = "ssid 2"), + WifiScanEntry(ssid = "ssid 3"), + WifiScanEntry(ssid = "ssid 4"), + WifiScanEntry(ssid = "ssid 5"), + ) + + assertThat(latest).isEqualTo(expected) + } + + @Test + fun wifiScanResults_updates() = + testScope.runTest { + val latest by collectLastValue(underTest.wifiScanResults) + + var scanResults = + listOf( + ScanResult().also { it.SSID = "ssid 1" }, + ScanResult().also { it.SSID = "ssid 2" }, + ScanResult().also { it.SSID = "ssid 3" }, + ScanResult().also { it.SSID = "ssid 4" }, + ScanResult().also { it.SSID = "ssid 5" }, + ) + whenever(wifiManager.scanResults).thenReturn(scanResults) + getScanResultsCallback().onScanResultsAvailable() + + // New scan representing no results + scanResults = listOf() + whenever(wifiManager.scanResults).thenReturn(scanResults) + getScanResultsCallback().onScanResultsAvailable() + + assertThat(latest).isEmpty() + } + private fun getCallback(): WifiPickerTracker.WifiPickerTrackerCallback { testScope.runCurrent() return callbackCaptor.value @@ -1156,6 +1211,13 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() { } } + private fun getScanResultsCallback(): WifiManager.ScanResultsCallback { + testScope.runCurrent() + val callbackCaptor = argumentCaptor<WifiManager.ScanResultsCallback>() + verify(wifiManager).registerScanResultsCallback(any(), callbackCaptor.capture()) + return callbackCaptor.value!! + } + private companion object { const val TITLE = "AB" } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt index 6fe88c100fdc..1db80651bf9b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt @@ -21,11 +21,13 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.RoboPilotTest import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.launchIn @@ -56,7 +58,8 @@ class WifiInteractorImplTest : SysuiTestCase() { fun setUp() { connectivityRepository = FakeConnectivityRepository() wifiRepository = FakeWifiRepository() - underTest = WifiInteractorImpl(connectivityRepository, wifiRepository) + underTest = + WifiInteractorImpl(connectivityRepository, wifiRepository, testScope.backgroundScope) } @Test @@ -300,4 +303,76 @@ class WifiInteractorImplTest : SysuiTestCase() { job.cancel() } + + @Test + fun areNetworksAvailable_noneActive_noResults() = + testScope.runTest { + val latest by collectLastValue(underTest.areNetworksAvailable) + + wifiRepository.wifiScanResults.value = emptyList() + wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive) + + assertThat(latest).isFalse() + } + + @Test + fun areNetworksAvailable_noneActive_nonEmptyResults() = + testScope.runTest { + val latest by collectLastValue(underTest.areNetworksAvailable) + + wifiRepository.wifiScanResults.value = + listOf( + WifiScanEntry(ssid = "ssid 1"), + WifiScanEntry(ssid = "ssid 2"), + WifiScanEntry(ssid = "ssid 3"), + ) + + wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive) + + assertThat(latest).isTrue() + } + + @Test + fun areNetworksAvailable_activeNetwork_resultsIncludeOtherNetworks() = + testScope.runTest { + val latest by collectLastValue(underTest.areNetworksAvailable) + + wifiRepository.wifiScanResults.value = + listOf( + WifiScanEntry(ssid = "ssid 1"), + WifiScanEntry(ssid = "ssid 2"), + WifiScanEntry(ssid = "ssid 3"), + ) + + wifiRepository.setWifiNetwork( + WifiNetworkModel.Active( + ssid = "ssid 2", + networkId = 1, + level = 2, + ) + ) + + assertThat(latest).isTrue() + } + + @Test + fun areNetworksAvailable_activeNetwork_onlyResultIsTheActiveNetwork() = + testScope.runTest { + val latest by collectLastValue(underTest.areNetworksAvailable) + + wifiRepository.wifiScanResults.value = + listOf( + WifiScanEntry(ssid = "ssid 2"), + ) + + wifiRepository.setWifiNetwork( + WifiNetworkModel.Active( + ssid = "ssid 2", + networkId = 1, + level = 2, + ) + ) + + assertThat(latest).isFalse() + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt index 3f499359cc6a..a0d4d1390b2c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt @@ -82,8 +82,8 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() { connectivityRepository = FakeConnectivityRepository() wifiRepository = FakeWifiRepository() wifiRepository.setIsWifiEnabled(true) - interactor = WifiInteractorImpl(connectivityRepository, wifiRepository) scope = CoroutineScope(Dispatchers.Unconfined) + interactor = WifiInteractorImpl(connectivityRepository, wifiRepository, scope) airplaneModeViewModel = AirplaneModeViewModelImpl( AirplaneModeInteractor( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt index c8bb28325065..1d1b84c04d71 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt @@ -83,8 +83,8 @@ internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase connectivityRepository = FakeConnectivityRepository() wifiRepository = FakeWifiRepository() wifiRepository.setIsWifiEnabled(true) - interactor = WifiInteractorImpl(connectivityRepository, wifiRepository) scope = CoroutineScope(IMMEDIATE) + interactor = WifiInteractorImpl(connectivityRepository, wifiRepository, scope) airplaneModeViewModel = AirplaneModeViewModelImpl( AirplaneModeInteractor( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt index bdeba2a2f4c8..5aacc6626eb7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt @@ -74,7 +74,8 @@ class WifiViewModelTest : SysuiTestCase() { connectivityRepository = FakeConnectivityRepository() wifiRepository = FakeWifiRepository() wifiRepository.setIsWifiEnabled(true) - interactor = WifiInteractorImpl(connectivityRepository, wifiRepository) + interactor = + WifiInteractorImpl(connectivityRepository, wifiRepository, testScope.backgroundScope) airplaneModeViewModel = AirplaneModeViewModelImpl( AirplaneModeInteractor( |