summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt120
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoModeWifiDataSource.kt74
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt105
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/model/FakeWifiEventModel.kt33
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt137
9 files changed, 523 insertions, 7 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
index 57add75ee38a..5f5418f5eeb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
@@ -1302,7 +1302,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
}
String wifi = args.getString("wifi");
- if (wifi != null) {
+ if (wifi != null && !mStatusBarPipelineFlags.runNewWifiIconBackend()) {
boolean show = wifi.equals("show");
String level = args.getString("level");
if (level != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 5569718f4a4a..c72eb054c62c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -42,6 +42,8 @@ import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconStat
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView;
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
+import com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView;
+import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel;
import java.util.ArrayList;
import java.util.List;
@@ -56,6 +58,7 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da
private final int mIconSize;
private StatusBarWifiView mWifiView;
+ private ModernStatusBarWifiView mModernWifiView;
private boolean mDemoMode;
private int mColor;
@@ -236,14 +239,14 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da
public void addDemoWifiView(WifiIconState state) {
Log.d(TAG, "addDemoWifiView: ");
- // TODO(b/238425913): Migrate this view to {@code ModernStatusBarWifiView}.
StatusBarWifiView view = StatusBarWifiView.fromContext(mContext, state.slot);
int viewIndex = getChildCount();
// If we have mobile views, put wifi before them
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
- if (child instanceof StatusBarMobileView) {
+ if (child instanceof StatusBarMobileView
+ || child instanceof ModernStatusBarMobileView) {
viewIndex = i;
break;
}
@@ -299,6 +302,30 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da
}
/**
+ * Add a {@link ModernStatusBarWifiView}
+ */
+ public void addModernWifiView(LocationBasedWifiViewModel viewModel) {
+ Log.d(TAG, "addModernDemoWifiView: ");
+ ModernStatusBarWifiView view = ModernStatusBarWifiView
+ .constructAndBind(mContext, "wifi", viewModel);
+
+ int viewIndex = getChildCount();
+ // If we have mobile views, put wifi before them
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ if (child instanceof StatusBarMobileView
+ || child instanceof ModernStatusBarMobileView) {
+ viewIndex = i;
+ break;
+ }
+ }
+
+ mModernWifiView = view;
+ mModernWifiView.setStaticDrawableColor(mColor);
+ addView(view, viewIndex, createLayoutParams());
+ }
+
+ /**
* Apply an update to a mobile icon view for the given {@link MobileIconState}. For
* compatibility with {@link MobileContextProvider}, we have to recreate the view every time we
* update it, since the context (and thus the {@link Configuration}) may have changed
@@ -320,8 +347,14 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da
public void onRemoveIcon(StatusIconDisplayable view) {
if (view.getSlot().equals("wifi")) {
- removeView(mWifiView);
- mWifiView = null;
+ if (view instanceof StatusBarWifiView) {
+ removeView(mWifiView);
+ mWifiView = null;
+ } else if (view instanceof ModernStatusBarWifiView) {
+ Log.d(TAG, "onRemoveIcon: removing modern wifi view");
+ removeView(mModernWifiView);
+ mModernWifiView = null;
+ }
} else if (view instanceof StatusBarMobileView) {
StatusBarMobileView mobileView = matchingMobileView(view);
if (mobileView != null) {
@@ -374,8 +407,14 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da
if (mWifiView != null) {
mWifiView.onDarkChanged(areas, darkIntensity, tint);
}
+ if (mModernWifiView != null) {
+ mModernWifiView.onDarkChanged(areas, darkIntensity, tint);
+ }
for (StatusBarMobileView view : mMobileViews) {
view.onDarkChanged(areas, darkIntensity, tint);
}
+ for (ModernStatusBarMobileView view : mModernMobileViews) {
+ view.onDarkChanged(areas, darkIntensity, tint);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 44e5cd9543ef..1a14a0363763 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -497,6 +497,11 @@ public interface StatusBarIconController {
ModernStatusBarWifiView view = onCreateModernStatusBarWifiView(slot);
mGroup.addView(view, index, onCreateLayoutParams());
+
+ if (mIsInDemoMode) {
+ mDemoStatusIcons.addModernWifiView(mWifiViewModel);
+ }
+
return view;
}
@@ -688,6 +693,9 @@ public interface StatusBarIconController {
mIsInDemoMode = true;
if (mDemoStatusIcons == null) {
mDemoStatusIcons = createDemoStatusIcons();
+ if (mStatusBarPipelineFlags.useNewWifiIcon()) {
+ mDemoStatusIcons.addModernWifiView(mWifiViewModel);
+ }
}
mDemoStatusIcons.onDemoModeStarted();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index c350c78913d3..0d01715715c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -36,7 +36,7 @@ import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxyIm
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 com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositorySwitcher
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl
import dagger.Binds
@@ -56,7 +56,7 @@ abstract class StatusBarPipelineModule {
@Binds
abstract fun connectivityRepository(impl: ConnectivityRepositoryImpl): ConnectivityRepository
- @Binds abstract fun wifiRepository(impl: WifiRepositoryImpl): WifiRepository
+ @Binds abstract fun wifiRepository(impl: WifiRepositorySwitcher): WifiRepository
@Binds
abstract fun wifiInteractor(impl: WifiInteractorImpl): WifiInteractor
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
new file mode 100644
index 000000000000..73bcdfd2b78e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt
@@ -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.wifi.data.repository
+
+import android.os.Bundle
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.demomode.DemoMode
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoWifiRepository
+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.flatMapLatest
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Provides the [WifiRepository] interface either through the [DemoWifiRepository] implementation,
+ * or the [WifiRepositoryImpl]'s prod implementation, based on the current demo mode value. In this
+ * way, downstream clients can all consist of real implementations and not care about which
+ * repository is responsible for the data. Graphically:
+ *
+ * ```
+ * RealRepository
+ * │
+ * ├──►RepositorySwitcher──►RealInteractor──►RealViewModel
+ * │
+ * DemoRepository
+ * ```
+ *
+ * When demo mode turns on, every flow will [flatMapLatest] to the current provider's version of
+ * that flow.
+ */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+class WifiRepositorySwitcher
+@Inject
+constructor(
+ private val realImpl: WifiRepositoryImpl,
+ private val demoImpl: DemoWifiRepository,
+ private val demoModeController: DemoModeController,
+ @Application scope: CoroutineScope,
+) : WifiRepository {
+ private val isDemoMode =
+ conflatedCallbackFlow {
+ val callback =
+ object : DemoMode {
+ override fun dispatchDemoCommand(command: String?, args: Bundle?) {
+ // Don't care
+ }
+
+ override fun onDemoModeStarted() {
+ demoImpl.startProcessingCommands()
+ trySend(true)
+ }
+
+ override fun onDemoModeFinished() {
+ demoImpl.stopProcessingCommands()
+ trySend(false)
+ }
+ }
+
+ demoModeController.addCallback(callback)
+ awaitClose { demoModeController.removeCallback(callback) }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), demoModeController.isInDemoMode)
+
+ @VisibleForTesting
+ val activeRepo =
+ isDemoMode
+ .mapLatest { isDemoMode ->
+ if (isDemoMode) {
+ demoImpl
+ } else {
+ realImpl
+ }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), realImpl)
+
+ override val isWifiEnabled: StateFlow<Boolean> =
+ activeRepo
+ .flatMapLatest { it.isWifiEnabled }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), realImpl.isWifiEnabled.value)
+
+ override val isWifiDefault: StateFlow<Boolean> =
+ activeRepo
+ .flatMapLatest { it.isWifiDefault }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), realImpl.isWifiDefault.value)
+
+ override val wifiNetwork: StateFlow<WifiNetworkModel> =
+ activeRepo
+ .flatMapLatest { it.wifiNetwork }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), realImpl.wifiNetwork.value)
+
+ override val wifiActivity: StateFlow<DataActivityModel> =
+ activeRepo
+ .flatMapLatest { it.wifiActivity }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), realImpl.wifiActivity.value)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoModeWifiDataSource.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoModeWifiDataSource.kt
new file mode 100644
index 000000000000..c588945fbd67
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoModeWifiDataSource.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.wifi.data.repository.demo
+
+import android.net.wifi.WifiManager
+import android.os.Bundle
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.demomode.DemoMode.COMMAND_NETWORK
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.shareIn
+
+/** Data source to map between demo mode commands and inputs into [DemoWifiRepository]'s flows */
+@SysUISingleton
+class DemoModeWifiDataSource
+@Inject
+constructor(
+ demoModeController: DemoModeController,
+ @Application scope: CoroutineScope,
+) {
+ private val demoCommandStream = demoModeController.demoFlowForCommand(COMMAND_NETWORK)
+ private val _wifiCommands = demoCommandStream.map { args -> args.toWifiEvent() }
+ val wifiEvents = _wifiCommands.shareIn(scope, SharingStarted.WhileSubscribed())
+
+ private fun Bundle.toWifiEvent(): FakeWifiEventModel? {
+ val wifi = getString("wifi") ?: return null
+ return if (wifi == "show") {
+ activeWifiEvent()
+ } else {
+ FakeWifiEventModel.WifiDisabled
+ }
+ }
+
+ private fun Bundle.activeWifiEvent(): FakeWifiEventModel.Wifi {
+ val level = getString("level")?.toInt()
+ val activity = getString("activity")?.toActivity()
+ val ssid = getString("ssid")
+ val validated = getString("fully").toBoolean()
+
+ return FakeWifiEventModel.Wifi(
+ level = level,
+ activity = activity,
+ ssid = ssid,
+ validated = validated,
+ )
+ }
+
+ private fun String.toActivity(): Int =
+ when (this) {
+ "inout" -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT
+ "in" -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN
+ "out" -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT
+ else -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE
+ }
+}
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
new file mode 100644
index 000000000000..7890074cf8a2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt
@@ -0,0 +1,105 @@
+/*
+ * 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.wifi.data.repository.demo
+
+import com.android.systemui.dagger.qualifiers.Application
+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.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.launch
+
+/** Demo-able wifi repository to support SystemUI demo mode commands. */
+class DemoWifiRepository
+@Inject
+constructor(
+ private val dataSource: DemoModeWifiDataSource,
+ @Application private val scope: CoroutineScope,
+) : WifiRepository {
+ private var demoCommandJob: Job? = null
+
+ private val _isWifiEnabled = MutableStateFlow(false)
+ override val isWifiEnabled: StateFlow<Boolean> = _isWifiEnabled
+
+ private val _isWifiDefault = MutableStateFlow(false)
+ override val isWifiDefault: StateFlow<Boolean> = _isWifiDefault
+
+ private val _wifiNetwork = MutableStateFlow<WifiNetworkModel>(WifiNetworkModel.Inactive)
+ override val wifiNetwork: StateFlow<WifiNetworkModel> = _wifiNetwork
+
+ private val _wifiActivity =
+ MutableStateFlow(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+ override val wifiActivity: StateFlow<DataActivityModel> = _wifiActivity
+
+ fun startProcessingCommands() {
+ demoCommandJob =
+ scope.launch {
+ dataSource.wifiEvents.filterNotNull().collect { event -> processEvent(event) }
+ }
+ }
+
+ fun stopProcessingCommands() {
+ demoCommandJob?.cancel()
+ }
+
+ private fun processEvent(event: FakeWifiEventModel) =
+ when (event) {
+ is FakeWifiEventModel.Wifi -> processEnabledWifiState(event)
+ is FakeWifiEventModel.WifiDisabled -> processDisabledWifiState()
+ }
+
+ private fun processDisabledWifiState() {
+ _isWifiEnabled.value = false
+ _isWifiDefault.value = false
+ _wifiActivity.value = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
+ _wifiNetwork.value = WifiNetworkModel.Inactive
+ }
+
+ private fun processEnabledWifiState(event: FakeWifiEventModel.Wifi) {
+ _isWifiEnabled.value = true
+ _isWifiDefault.value = true
+ _wifiActivity.value =
+ event.activity?.toWifiDataActivityModel()
+ ?: DataActivityModel(hasActivityIn = false, hasActivityOut = false)
+ _wifiNetwork.value = event.toWifiNetworkModel()
+ }
+
+ private fun FakeWifiEventModel.Wifi.toWifiNetworkModel(): WifiNetworkModel =
+ WifiNetworkModel.Active(
+ networkId = DEMO_NET_ID,
+ isValidated = validated ?: true,
+ level = level,
+ ssid = ssid,
+
+ // These fields below aren't supported in demo mode, since they aren't needed to satisfy
+ // the interface.
+ isPasspointAccessPoint = false,
+ isOnlineSignUpForPasspointAccessPoint = false,
+ passpointProviderFriendlyName = null,
+ )
+
+ companion object {
+ private const val DEMO_NET_ID = 1234
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/model/FakeWifiEventModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/model/FakeWifiEventModel.kt
new file mode 100644
index 000000000000..2353fb82f3b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/model/FakeWifiEventModel.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.wifi.data.repository.demo.model
+
+/**
+ * Model for demo wifi commands, ported from [NetworkControllerImpl]
+ *
+ * Nullable fields represent optional command line arguments
+ */
+sealed interface FakeWifiEventModel {
+ data class Wifi(
+ val level: Int?,
+ val activity: Int?,
+ val ssid: String?,
+ val validated: Boolean?,
+ ) : FakeWifiEventModel
+
+ object WifiDisabled : FakeWifiEventModel
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
new file mode 100644
index 000000000000..b935442fd73a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
@@ -0,0 +1,137 @@
+/*
+ * 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.wifi.data.repository
+
+import android.net.ConnectivityManager
+import android.net.wifi.WifiManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.demomode.DemoMode
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.kotlinArgumentCaptor
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class WifiRepositorySwitcherTest : SysuiTestCase() {
+ private lateinit var underTest: WifiRepositorySwitcher
+ private lateinit var realImpl: WifiRepositoryImpl
+ private lateinit var demoImpl: DemoWifiRepository
+
+ @Mock private lateinit var demoModeController: DemoModeController
+ @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var tableLogger: TableLogBuffer
+ @Mock private lateinit var connectivityManager: ConnectivityManager
+ @Mock private lateinit var wifiManager: WifiManager
+ @Mock private lateinit var demoModeWifiDataSource: DemoModeWifiDataSource
+ private val demoModelFlow = MutableStateFlow<FakeWifiEventModel?>(null)
+
+ private val mainExecutor = FakeExecutor(FakeSystemClock())
+
+ private val testDispatcher = UnconfinedTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ // Never start in demo mode
+ whenever(demoModeController.isInDemoMode).thenReturn(false)
+
+ realImpl =
+ WifiRepositoryImpl(
+ fakeBroadcastDispatcher,
+ connectivityManager,
+ logger,
+ tableLogger,
+ mainExecutor,
+ testScope.backgroundScope,
+ wifiManager,
+ )
+
+ whenever(demoModeWifiDataSource.wifiEvents).thenReturn(demoModelFlow)
+
+ demoImpl =
+ DemoWifiRepository(
+ demoModeWifiDataSource,
+ testScope.backgroundScope,
+ )
+
+ underTest =
+ WifiRepositorySwitcher(
+ realImpl,
+ demoImpl,
+ demoModeController,
+ testScope.backgroundScope,
+ )
+ }
+
+ @Test
+ fun `switcher active repo - updates when demo mode changes`() =
+ testScope.runTest {
+ assertThat(underTest.activeRepo.value).isSameInstanceAs(realImpl)
+
+ var latest: WifiRepository? = null
+ val job = underTest.activeRepo.onEach { latest = it }.launchIn(this)
+
+ startDemoMode()
+
+ assertThat(latest).isSameInstanceAs(demoImpl)
+
+ finishDemoMode()
+
+ assertThat(latest).isSameInstanceAs(realImpl)
+
+ job.cancel()
+ }
+
+ private fun startDemoMode() {
+ whenever(demoModeController.isInDemoMode).thenReturn(true)
+ getDemoModeCallback().onDemoModeStarted()
+ }
+
+ private fun finishDemoMode() {
+ whenever(demoModeController.isInDemoMode).thenReturn(false)
+ getDemoModeCallback().onDemoModeFinished()
+ }
+
+ private fun getDemoModeCallback(): DemoMode {
+ val captor = kotlinArgumentCaptor<DemoMode>()
+ Mockito.verify(demoModeController).addCallback(captor.capture())
+ return captor.value
+ }
+}