diff options
| author | 2024-12-04 16:45:03 +0000 | |
|---|---|---|
| committer | 2024-12-04 16:45:03 +0000 | |
| commit | 74f35cb95d889e694182aa6a0de73ab32fac0af7 (patch) | |
| tree | 8a20aadc2b0f1f2f71b0e8ec9e249155aec673c2 | |
| parent | 9bccff3fadab712660752b6266ab2fb3d0d54228 (diff) | |
| parent | e5f1dc5996f6c0c8f038aa57b47b6a25164f9231 (diff) | |
Merge changes Iead9f8bc,I8f608203 into main
* changes:
Deactivate all modes from QS toggle
Dual target modes tile
11 files changed, 165 insertions, 38 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ModesTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ModesTileTest.kt index 848c8db4b99d..9173ac969324 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ModesTileTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ModesTileTest.kt @@ -94,11 +94,7 @@ class ModesTileTest : SysuiTestCase() { private val zenModeRepository = kosmos.zenModeRepository private val tileDataInteractor = ModesTileDataInteractor(context, kosmos.zenModeInteractor, testDispatcher) - private val mapper = - ModesTileMapper( - context.resources, - context.theme, - ) + private val mapper = ModesTileMapper(context.resources, context.theme) private lateinit var userActionInteractor: ModesTileUserActionInteractor private lateinit var secureSettings: SecureSettings @@ -127,10 +123,7 @@ class ModesTileTest : SysuiTestCase() { ) userActionInteractor = - ModesTileUserActionInteractor( - inputHandler, - dialogDelegate, - ) + ModesTileUserActionInteractor(inputHandler, dialogDelegate, kosmos.zenModeInteractor) underTest = ModesTile( @@ -185,7 +178,7 @@ class ModesTileTest : SysuiTestCase() { ModesTileModel( isActivated = true, activeModes = listOf("One", "Two"), - icon = TestStubDrawable().asIcon() + icon = TestStubDrawable().asIcon(), ) underTest.handleUpdateState(tileState, model) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorTest.kt index cd5812710292..88b00468573f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:OptIn(ExperimentalCoroutinesApi::class) + package com.android.systemui.qs.tiles.impl.modes.domain.interactor import android.graphics.drawable.TestStubDrawable @@ -21,16 +23,23 @@ import android.platform.test.annotations.EnableFlags import android.provider.Settings import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.settingslib.notification.modes.TestModeBuilder +import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.asIcon +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject import com.android.systemui.qs.tiles.base.actions.qsTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel +import com.android.systemui.statusbar.policy.data.repository.zenModeRepository +import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor import com.android.systemui.statusbar.policy.ui.dialog.mockModesDialogDelegate import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @@ -43,17 +52,17 @@ import org.mockito.kotlin.verify @EnableFlags(android.app.Flags.FLAG_MODES_UI) class ModesTileUserActionInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() + private val testScope = kosmos.testScope private val inputHandler = kosmos.qsTileIntentUserInputHandler private val mockDialogDelegate = kosmos.mockModesDialogDelegate + private val zenModeRepository = kosmos.zenModeRepository + private val zenModeInteractor = kosmos.zenModeInteractor private val underTest = - ModesTileUserActionInteractor( - inputHandler, - mockDialogDelegate, - ) + ModesTileUserActionInteractor(inputHandler, mockDialogDelegate, zenModeInteractor) @Test - fun handleClick_active() = runTest { + fun handleClick_active_showsDialog() = runTest { val expandable = mock<Expandable>() underTest.handleInput( QSTileInputTestKtx.click(data = modelOf(true, listOf("DND")), expandable = expandable) @@ -63,7 +72,7 @@ class ModesTileUserActionInteractorTest : SysuiTestCase() { } @Test - fun handleClick_inactive() = runTest { + fun handleClick_inactive_showsDialog() = runTest { val expandable = mock<Expandable>() underTest.handleInput( QSTileInputTestKtx.click(data = modelOf(false, emptyList()), expandable = expandable) @@ -73,7 +82,63 @@ class ModesTileUserActionInteractorTest : SysuiTestCase() { } @Test - fun handleLongClick_active() = runTest { + @EnableFlags(Flags.FLAG_QS_UI_REFACTOR_COMPOSE_FRAGMENT) + fun handleToggleClick_multipleModesActive_deactivatesAll() = + testScope.runTest { + val activeModes by collectLastValue(zenModeInteractor.activeModes) + + zenModeRepository.addModes( + listOf( + TestModeBuilder.MANUAL_DND_ACTIVE, + TestModeBuilder().setName("Mode 1").setActive(true).build(), + TestModeBuilder().setName("Mode 2").setActive(true).build(), + ) + ) + assertThat(activeModes?.modeNames?.count()).isEqualTo(3) + + underTest.handleInput( + QSTileInputTestKtx.toggleClick( + data = modelOf(true, listOf("DND", "Mode 1", "Mode 2")) + ) + ) + + assertThat(activeModes?.isAnyActive()).isFalse() + } + + @Test + @EnableFlags(Flags.FLAG_QS_UI_REFACTOR_COMPOSE_FRAGMENT) + fun handleToggleClick_dndActive_deactivatesDnd() = + testScope.runTest { + val dndMode by collectLastValue(zenModeInteractor.dndMode) + + zenModeRepository.addMode(TestModeBuilder.MANUAL_DND_ACTIVE) + assertThat(dndMode?.isActive).isTrue() + + underTest.handleInput( + QSTileInputTestKtx.toggleClick(data = modelOf(true, listOf("DND"))) + ) + + assertThat(dndMode?.isActive).isFalse() + } + + @Test + @EnableFlags(Flags.FLAG_QS_UI_REFACTOR_COMPOSE_FRAGMENT) + fun handleToggleClick_dndInactive_activatesDnd() = + testScope.runTest { + val dndMode by collectLastValue(zenModeInteractor.dndMode) + + zenModeRepository.addMode(TestModeBuilder.MANUAL_DND_INACTIVE) + assertThat(dndMode?.isActive).isFalse() + + underTest.handleInput( + QSTileInputTestKtx.toggleClick(data = modelOf(false, emptyList())) + ) + + assertThat(dndMode?.isActive).isTrue() + } + + @Test + fun handleLongClick_active_opensSettings() = runTest { underTest.handleInput(QSTileInputTestKtx.longClick(modelOf(true, listOf("DND")))) QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { @@ -82,7 +147,7 @@ class ModesTileUserActionInteractorTest : SysuiTestCase() { } @Test - fun handleLongClick_inactive() = runTest { + fun handleLongClick_inactive_opensSettings() = runTest { underTest.handleInput(QSTileInputTestKtx.longClick(modelOf(false, emptyList()))) QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt index 4e33a5958a1a..3d6882c3fdaf 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt @@ -251,6 +251,22 @@ class ZenModeInteractorTest : SysuiTestCase() { } @Test + fun deactivateAllModes_updatesCorrectModes() = + testScope.runTest { + zenModeRepository.addModes( + listOf( + TestModeBuilder.MANUAL_DND_ACTIVE, + TestModeBuilder().setName("Inactive").setActive(false).build(), + TestModeBuilder().setName("Active").setActive(true).build(), + ) + ) + + underTest.deactivateAllModes() + + assertThat(zenModeRepository.getModes().filter { it.isActive }).isEmpty() + } + + @Test fun activeModes_computesMainActiveMode() = testScope.runTest { val activeModes by collectLastValue(underTest.activeModes) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt index d1f9fa259c6b..e8d3bfac6361 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt @@ -27,7 +27,6 @@ import android.provider.Settings.Secure.ZEN_DURATION_PROMPT import android.service.notification.ZenModeConfig import android.util.Log import com.android.settingslib.notification.modes.EnableZenModeDialog -import com.android.settingslib.notification.modes.ZenMode import com.android.settingslib.notification.modes.ZenModeDialogMetricsLogger import com.android.systemui.animation.Expandable import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging @@ -99,15 +98,6 @@ constructor( private var oldIsAvailable = false private var settingsValue: Int = 0 - private val dndMode: StateFlow<ZenMode?> by lazy { - ModesUi.assertInNewMode() - interactor.dndMode.stateIn( - scope = backgroundScope, - started = SharingStarted.Eagerly, - initialValue = null, - ) - } - private val isAvailable: StateFlow<Boolean> by lazy { ModesUi.assertInNewMode() interactor.isZenAvailable.stateIn( @@ -146,7 +136,7 @@ constructor( override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> = if (ModesUi.isEnabled) { - combine(isAvailable, dndMode) { isAvailable, dndMode -> + combine(isAvailable, interactor.dndMode) { isAvailable, dndMode -> if (!isAvailable) { KeyguardQuickAffordanceConfig.LockScreenState.Hidden } else if (dndMode?.isActive == true) { @@ -222,7 +212,7 @@ constructor( if (!isAvailable.value) { KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled } else { - val dnd = dndMode.value + val dnd = interactor.dndMode.value if (dnd == null) { Log.wtf(TAG, "Triggered DND but it's null!?") return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt index 9c6345666403..0051bf5de7f2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt @@ -109,6 +109,11 @@ constructor( userActionInteractor.handleClick(expandable) } + override fun handleSecondaryClick(expandable: Expandable?) = runBlocking { + val model = dataInteractor.getCurrentTileModel() + userActionInteractor.handleToggleClick(model) + } + override fun getLongClickIntent(): Intent = userActionInteractor.longClickIntent @VisibleForTesting @@ -125,6 +130,7 @@ constructor( secondaryLabel = tileState.secondaryLabel contentDescription = tileState.contentDescription expandedAccessibilityClassName = tileState.expandedAccessibilityClassName + handlesSecondaryClick = true } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractor.kt index eb8b23c2505a..594394f68d48 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractor.kt @@ -18,13 +18,16 @@ package com.android.systemui.qs.tiles.impl.modes.domain.interactor import android.content.Intent import android.provider.Settings +import android.util.Log import com.android.systemui.animation.Expandable import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.interactor.QSTileInput import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction +import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor import com.android.systemui.statusbar.policy.ui.dialog.ModesDialogDelegate import javax.inject.Inject @@ -35,16 +38,19 @@ constructor( private val qsTileIntentUserInputHandler: QSTileIntentUserInputHandler, // TODO(b/353896370): The domain layer should not have to depend on the UI layer. private val dialogDelegate: ModesDialogDelegate, + private val zenModeInteractor: ZenModeInteractor, ) : QSTileUserActionInteractor<ModesTileModel> { val longClickIntent = Intent(Settings.ACTION_ZEN_MODE_SETTINGS) override suspend fun handleInput(input: QSTileInput<ModesTileModel>) { with(input) { when (action) { - is QSTileUserAction.Click, - is QSTileUserAction.ToggleClick -> { + is QSTileUserAction.Click -> { handleClick(action.expandable) } + is QSTileUserAction.ToggleClick -> { + handleToggleClick(input.data) + } is QSTileUserAction.LongClick -> { qsTileIntentUserInputHandler.handle(action.expandable, longClickIntent) } @@ -56,4 +62,29 @@ constructor( // Show a dialog with the list of modes to configure. dialogDelegate.showDialog(expandable) } + + fun handleToggleClick(modesTileModel: ModesTileModel) { + if (QSComposeFragment.isUnexpectedlyInLegacyMode()) { + return + } + + // If no modes are on, turn on DND since it's the highest-priority mode. Otherwise, turn + // them all off. + // We want this toggle to work as a shortcut to DND in most cases, but it should still + // correctly toggle the tile state to "off" as the user would expect when more modes are on. + if (modesTileModel.activeModes.isEmpty()) { + val dnd = zenModeInteractor.dndMode.value + if (dnd == null) { + Log.wtf(TAG, "Triggered DND but it's null!?") + return + } + zenModeInteractor.activateMode(dnd) + } else { + zenModeInteractor.deactivateAllModes() + } + } + + companion object { + const val TAG = "ModesTileUserActionInteractor" + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt index bac048f1786a..1507ef4b3b58 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt @@ -45,7 +45,11 @@ constructor(@ShadeDisplayAware private val resources: Resources, val theme: Reso secondaryLabel = getModesStatus(data, resources) contentDescription = "$label. $secondaryLabel" supportedActions = - setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK) + setOf( + QSTileState.UserAction.CLICK, + QSTileState.UserAction.LONG_CLICK, + QSTileState.UserAction.TOGGLE_CLICK, + ) sideViewIcon = QSTileState.SideViewIcon.Chevron expandedAccessibilityClass = Button::class } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt index 9839f9d76537..12ed647fdee7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt @@ -40,12 +40,16 @@ import com.android.systemui.statusbar.policy.domain.model.ZenModeInfo import java.time.Duration import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn /** * An interactor that performs business logic related to the status and configuration of Zen Mode @@ -58,6 +62,7 @@ constructor( private val zenModeRepository: ZenModeRepository, private val notificationSettingsRepository: NotificationSettingsRepository, @Background private val bgDispatcher: CoroutineDispatcher, + @Background private val backgroundScope: CoroutineScope, private val iconLoader: ZenIconLoader, deviceProvisioningRepository: DeviceProvisioningRepository, userSetupRepository: UserSetupRepository, @@ -101,13 +106,16 @@ constructor( /** * Returns the special "manual DND" mode. * - * This is only meant as a temporary solution for "legacy" UI pieces that handle DND - * specifically; any new or migrated features should use modes more generally, through [modes] - * or [activeModes]. + * This should only be used when there is a strong reason to handle DND specifically (such as + * legacy UI pieces that haven't been updated to use modes more generally, or if the user + * explicitly wants a shortcut to DND). Please prefer using [modes] or [activeModes] in all + * other scenarios. */ - val dndMode: Flow<ZenMode?> by lazy { + val dndMode: StateFlow<ZenMode?> by lazy { ModesUi.assertInNewMode() - zenModeRepository.modes.map { modes -> modes.singleOrNull { it.isManualDnd } } + zenModeRepository.modes + .map { modes -> modes.singleOrNull { it.isManualDnd } } + .stateIn(scope = backgroundScope, started = SharingStarted.Eagerly, initialValue = null) } /** Flow returning the currently active mode(s), if any. */ @@ -201,6 +209,14 @@ constructor( zenModeRepository.deactivateMode(zenMode) } + fun deactivateAllModes() { + for (mode in zenModeRepository.getModes()) { + if (mode.isActive) { + deactivateMode(mode) + } + } + } + private val zenDuration get() = notificationSettingsRepository.zenDuration.value diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt index ae9454498089..f347d48c49cf 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt @@ -90,6 +90,7 @@ import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.junit.MockitoJUnit +import org.mockito.kotlin.clearInvocations @RunWith(AndroidJUnit4::class) @SmallTest @@ -536,6 +537,7 @@ class ClockEventControllerTest : SysuiTestCase() { .onZenDataChanged( eq(ZenData(ZenMode.IMPORTANT_INTERRUPTIONS, R.string::dnd_is_on.name)) ) + clearInvocations(events) zenModeRepository.deactivateMode(dndModeId) runCurrent() diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorKosmos.kt index 2ecfb454a6f0..3c37101cfe66 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorKosmos.kt @@ -18,6 +18,7 @@ package com.android.systemui.qs.tiles.impl.modes.domain.interactor import com.android.systemui.kosmos.Kosmos import com.android.systemui.qs.tiles.base.actions.qsTileIntentUserInputHandler +import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor import com.android.systemui.statusbar.policy.ui.dialog.modesDialogDelegate import javax.inject.Provider @@ -26,5 +27,6 @@ val Kosmos.modesTileUserActionInteractor: ModesTileUserActionInteractor by ModesTileUserActionInteractor( qsTileIntentUserInputHandler, Provider { modesDialogDelegate }.get(), + zenModeInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt index 68d08e285c53..bbccbb10923a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt @@ -20,6 +20,7 @@ import android.content.applicationContext import com.android.settingslib.notification.modes.zenIconLoader import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.kosmos.backgroundScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.shared.notifications.data.repository.notificationSettingsRepository import com.android.systemui.statusbar.policy.data.repository.deviceProvisioningRepository @@ -32,6 +33,7 @@ val Kosmos.zenModeInteractor by Fixture { zenModeRepository = zenModeRepository, notificationSettingsRepository = notificationSettingsRepository, bgDispatcher = testDispatcher, + backgroundScope = backgroundScope, iconLoader = zenIconLoader, deviceProvisioningRepository = deviceProvisioningRepository, userSetupRepository = userSetupRepository, |