Merge "Show the icon of the active mode in the Modes Tile" into main
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index f05c24f..606ca33 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -21,6 +21,16 @@
 }
 
 flag {
+  name: "modes_ui_icons"
+  namespace: "systemui"
+  description: "Shows current Priority Mode icon in lockscreen, status bar, and QS; dependent on flags modes_api and modes_ui"
+  bug: "360399800"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
   name: "modes_ui_test"
   namespace: "systemui"
   description: "Guards new CTS tests for Modes; dependent on flags modes_api and modes_ui"
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
index e5d79a1..4371f05 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
@@ -16,6 +16,7 @@
 
 package com.android.settingslib.notification.data.repository
 
+import android.app.AutomaticZenRule
 import android.app.NotificationManager
 import android.provider.Settings
 import com.android.settingslib.notification.modes.TestModeBuilder
@@ -58,8 +59,9 @@
         mutableModesFlow.value += zenModes
     }
 
-    fun addMode(id: String, active: Boolean = false) {
-        mutableModesFlow.value += newMode(id, active)
+    fun addMode(id: String, @AutomaticZenRule.Type type: Int = AutomaticZenRule.TYPE_UNKNOWN,
+        active: Boolean = false) {
+        mutableModesFlow.value += newMode(id, type, active)
     }
 
     fun removeMode(id: String) {
@@ -128,6 +130,6 @@
         )
     )
 
-private fun newMode(id: String, active: Boolean = false): ZenMode {
-    return TestModeBuilder().setId(id).setName("Mode $id").setActive(active).build()
+private fun newMode(id: String, @AutomaticZenRule.Type type: Int, active: Boolean): ZenMode {
+    return TestModeBuilder().setId(id).setName("Mode $id").setType(type).setActive(active).build()
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
index c13b261..d36b55f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
@@ -112,7 +112,7 @@
     };
 
     // Manual DND first, Bedtime/Driving, then alphabetically.
-    static final Comparator<ZenMode> PRIORITIZING_COMPARATOR = Comparator
+    public static final Comparator<ZenMode> PRIORITIZING_COMPARATOR = Comparator
             .comparing(ZenMode::isManualDnd).reversed()
             .thenComparing(ZenMode::getType, PRIORITIZED_TYPE_COMPARATOR)
             .thenComparing(ZenMode::getName);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
index 69b8ee1..94fa9b9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
@@ -16,19 +16,24 @@
 
 package com.android.systemui.qs.tiles.impl.modes.domain.interactor
 
+import android.app.AutomaticZenRule
 import android.app.Flags
+import android.graphics.drawable.TestStubDrawable
 import android.os.UserHandle
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.asIcon
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
 import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel
+import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
 import com.android.systemui.statusbar.policy.data.repository.fakeZenModeRepository
+import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -36,8 +41,10 @@
 import kotlinx.coroutines.flow.toCollection
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
@@ -48,7 +55,20 @@
     private val dispatcher = kosmos.testDispatcher
     private val zenModeRepository = kosmos.fakeZenModeRepository
 
-    private val underTest = ModesTileDataInteractor(zenModeRepository, dispatcher)
+    private val underTest =
+        ModesTileDataInteractor(
+            context,
+            ZenModeInteractor(zenModeRepository, mock<NotificationSettingsRepository>()),
+            dispatcher
+        )
+
+    @Before
+    fun setUp() {
+        context.orCreateTestableResources.apply {
+            addOverride(com.android.internal.R.drawable.ic_zen_mode_type_bedtime, BEDTIME_DRAWABLE)
+            addOverride(com.android.internal.R.drawable.ic_zen_mode_type_driving, DRIVING_DRAWABLE)
+        }
+    }
 
     @EnableFlags(Flags.FLAG_MODES_UI)
     @Test
@@ -110,8 +130,62 @@
             assertThat(dataList.map { it.activeModes }.last()).isEmpty()
         }
 
-    private companion object {
+    @Test
+    @EnableFlags(Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_ICONS)
+    fun changesIconWhenActiveModesChange() =
+        testScope.runTest {
+            val dataList: List<ModesTileModel> by
+                collectValues(
+                    underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))
+                )
+            runCurrent()
+            assertThat(dataList.map { it.icon }).containsExactly(null).inOrder()
 
+            // Add an inactive mode: state hasn't changed, so this shouldn't cause another emission
+            zenModeRepository.addMode(id = "Mode", active = false)
+            runCurrent()
+            assertThat(dataList.map { it.icon }).containsExactly(null).inOrder()
+
+            // Add an active mode: icon should be the mode icon
+            zenModeRepository.addMode(
+                id = "Bedtime",
+                type = AutomaticZenRule.TYPE_BEDTIME,
+                active = true
+            )
+            runCurrent()
+            assertThat(dataList.map { it.icon }).containsExactly(null, BEDTIME_ICON).inOrder()
+
+            // Add another, less-prioritized mode: icon should remain the first mode icon
+            zenModeRepository.addMode(
+                id = "Driving",
+                type = AutomaticZenRule.TYPE_DRIVING,
+                active = true
+            )
+            runCurrent()
+            assertThat(dataList.map { it.icon })
+                .containsExactly(null, BEDTIME_ICON, BEDTIME_ICON)
+                .inOrder()
+
+            // Deactivate more important mode: icon should be the less important, still active mode.
+            zenModeRepository.deactivateMode("Bedtime")
+            runCurrent()
+            assertThat(dataList.map { it.icon })
+                .containsExactly(null, BEDTIME_ICON, BEDTIME_ICON, DRIVING_ICON)
+                .inOrder()
+
+            // Deactivate remaining mode: no icon
+            zenModeRepository.deactivateMode("Driving")
+            runCurrent()
+            assertThat(dataList.map { it.icon })
+                .containsExactly(null, BEDTIME_ICON, BEDTIME_ICON, DRIVING_ICON, null)
+                .inOrder()
+        }
+
+    private companion object {
         val TEST_USER = UserHandle.of(1)!!
+        val BEDTIME_DRAWABLE = TestStubDrawable("bedtime")
+        val DRIVING_DRAWABLE = TestStubDrawable("driving")
+        val BEDTIME_ICON = BEDTIME_DRAWABLE.asIcon()
+        val DRIVING_ICON = DRIVING_DRAWABLE.asIcon()
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt
index dd9711e..a41f15d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt
@@ -16,10 +16,13 @@
 
 package com.android.systemui.qs.tiles.impl.modes.ui
 
+import android.app.Flags
 import android.graphics.drawable.TestStubDrawable
+import android.platform.test.annotations.EnableFlags
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel
 import com.android.systemui.qs.tiles.viewmodel.QSTileConfigTestBuilder
 import com.android.systemui.qs.tiles.viewmodel.QSTileState
@@ -31,6 +34,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
+@EnableFlags(Flags.FLAG_MODES_UI)
 class ModesTileMapperTest : SysuiTestCase() {
     val config =
         QSTileConfigTestBuilder.build {
@@ -85,4 +89,16 @@
         assertThat(state.iconRes).isEqualTo(R.drawable.qs_dnd_icon_on)
         assertThat(state.secondaryLabel).isEqualTo("3 modes are active")
     }
+
+    @Test
+    @EnableFlags(Flags.FLAG_MODES_UI_ICONS)
+    fun activeState_withIcon() {
+        val icon = Icon.Resource(1234, contentDescription = null)
+        val model = ModesTileModel(isActivated = true, activeModes = listOf("DND"), icon = icon)
+
+        val state = underTest.map(config, model)
+
+        assertThat(state.iconRes).isNull()
+        assertThat(state.icon()).isEqualTo(icon)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileIcon.kt b/packages/SystemUI/src/com/android/systemui/qs/QSTileIcon.kt
new file mode 100644
index 0000000..ef7e7eb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileIcon.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 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.qs
+
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.tileimpl.QSTileImpl
+
+/**
+ * Creates a [QSTile.Icon] from an [Icon].
+ * * [Icon.Loaded] -> [QSTileImpl.DrawableIcon]
+ * * [Icon.Resource] -> [QSTileImpl.ResourceIcon]
+ */
+fun Icon.asQSTileIcon(): QSTile.Icon {
+    return when (this) {
+        is Icon.Loaded -> {
+            QSTileImpl.DrawableIcon(this.drawable)
+        }
+        is Icon.Resource -> {
+            QSTileImpl.ResourceIcon.get(this.res)
+        }
+    }
+}
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 5f10b38..6d63d26 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt
@@ -24,7 +24,6 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.coroutineScope
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.internal.R.attr.contentDescription
 import com.android.internal.logging.MetricsLogger
 import com.android.systemui.animation.Expandable
 import com.android.systemui.dagger.qualifiers.Background
@@ -36,6 +35,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.qs.QSHost
 import com.android.systemui.qs.QsEventLogger
+import com.android.systemui.qs.asQSTileIcon
 import com.android.systemui.qs.logging.QSLogger
 import com.android.systemui.qs.tileimpl.QSTileImpl
 import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesTileDataInteractor
@@ -115,7 +115,8 @@
 
             state?.apply {
                 this.state = tileState.activationState.legacyState
-                icon = ResourceIcon.get(tileState.iconRes ?: R.drawable.qs_dnd_icon_off)
+                val tileStateIcon = tileState.icon()
+                icon = tileStateIcon?.asQSTileIcon() ?: ResourceIcon.get(R.drawable.qs_dnd_icon_off)
                 label = tileLabel
                 secondaryLabel = tileState.secondaryLabel
                 contentDescription = tileState.contentDescription
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
index 92efa40..5f5b265 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
@@ -17,30 +17,28 @@
 package com.android.systemui.qs.tiles.impl.modes.domain.interactor
 
 import android.app.Flags
+import android.content.Context
 import android.os.UserHandle
-import com.android.settingslib.notification.data.repository.ZenModeRepository
+import com.android.app.tracing.coroutines.flow.map
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
 import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
 import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel
+import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.flow.map
 
 class ModesTileDataInteractor
 @Inject
 constructor(
-    val zenModeRepository: ZenModeRepository,
+    val context: Context,
+    val zenModeInteractor: ZenModeInteractor,
     @Background val bgDispatcher: CoroutineDispatcher,
 ) : QSTileDataInteractor<ModesTileModel> {
-    private val activeModes =
-        zenModeRepository.modes
-            .map { modes -> modes.filter { mode -> mode.isActive }.map { it.name } }
-            .distinctUntilChanged()
 
     override fun tileData(
         user: UserHandle,
@@ -53,9 +51,19 @@
      * TODO(b/299909989): Remove after the transition.
      */
     fun tileData() =
-        activeModes
-            .map { ModesTileModel(isActivated = it.isNotEmpty(), activeModes = it) }
+        zenModeInteractor.activeModes
+            .map { modes ->
+                ModesTileModel(
+                    isActivated = modes.isNotEmpty(),
+                    icon =
+                        if (Flags.modesApi() && Flags.modesUi() && Flags.modesUiIcons())
+                            zenModeInteractor.getActiveModeIcon(context, modes)
+                        else null,
+                    activeModes = modes.map { it.name }
+                )
+            }
             .flowOn(bgDispatcher)
+            .distinctUntilChanged()
 
     override fun availability(user: UserHandle): Flow<Boolean> = flowOf(Flags.modesUi())
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt
index cc509ea..904ff3a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt
@@ -15,4 +15,11 @@
  */
 
 package com.android.systemui.qs.tiles.impl.modes.domain.model
-data class ModesTileModel(val isActivated: Boolean, val activeModes: List<String>)
+
+import com.android.systemui.common.shared.model.Icon
+
+data class ModesTileModel(
+    val isActivated: Boolean,
+    val activeModes: List<String>,
+    val icon: Icon? = null
+)
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 7afdb75..0e127e3 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
@@ -16,10 +16,11 @@
 
 package com.android.systemui.qs.tiles.impl.modes.ui
 
+import android.app.Flags
 import android.content.res.Resources
 import android.icu.text.MessageFormat
 import android.widget.Button
-import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.common.shared.model.asIcon
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
 import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel
@@ -37,18 +38,14 @@
 ) : QSTileDataToStateMapper<ModesTileModel> {
     override fun map(config: QSTileConfig, data: ModesTileModel): QSTileState =
         QSTileState.build(resources, theme, config.uiConfig) {
-            iconRes =
-                if (data.isActivated) {
-                    R.drawable.qs_dnd_icon_on
-                } else {
-                    R.drawable.qs_dnd_icon_off
-                }
-            val icon =
-                Icon.Loaded(
-                    resources.getDrawable(iconRes!!, theme),
-                    contentDescription = null,
-                )
-            this.icon = { icon }
+            if (Flags.modesApi() && Flags.modesUi() && Flags.modesUiIcons() && data.icon != null) {
+                icon = { data.icon }
+            } else {
+                val defaultIconRes =
+                    if (data.isActivated) R.drawable.qs_dnd_icon_on else R.drawable.qs_dnd_icon_off
+                iconRes = defaultIconRes
+                icon = { resources.getDrawable(defaultIconRes, theme).asIcon() }
+            }
             activationState =
                 if (data.isActivated) {
                     QSTileState.ActivationState.ACTIVE
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 efd60f6..7586133 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
@@ -26,6 +26,7 @@
 import com.android.settingslib.notification.modes.ZenIconLoader
 import com.android.settingslib.notification.modes.ZenMode
 import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.common.shared.model.asIcon
 import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
 import java.time.Duration
 import javax.inject.Inject
@@ -74,8 +75,27 @@
 
     val modes: Flow<List<ZenMode>> = zenModeRepository.modes
 
-    suspend fun getModeIcon(mode: ZenMode, context: Context): Icon {
-        return Icon.Loaded(mode.getIcon(context, iconLoader).await(), contentDescription = null)
+    val activeModes: Flow<List<ZenMode>> =
+        modes.map { modes -> modes.filter { mode -> mode.isActive } }.distinctUntilChanged()
+
+    /**
+     * Given the list of modes (which may include zero or more currently active modes), returns an
+     * icon representing the active mode, if any (or, if multiple modes are active, to the most
+     * prioritized one). This icon is suitable for use in the status bar or lockscreen (uses the
+     * standard DND icon for implicit modes, instead of the launcher icon of the associated
+     * package).
+     */
+    suspend fun getActiveModeIcon(context: Context, modes: List<ZenMode>): Icon? {
+        return modes
+            .sortedWith(ZenMode.PRIORITIZING_COMPARATOR)
+            .firstOrNull { it.isActive }
+            ?.getLockscreenIcon(context, iconLoader)
+            ?.await()
+            ?.asIcon()
+    }
+
+    suspend fun getModeIcon(context: Context, mode: ZenMode): Icon {
+        return mode.getIcon(context, iconLoader).await().asIcon()
     }
 
     fun activateMode(zenMode: ZenMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
index 16c18dd8c..02b5e49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
@@ -88,8 +88,8 @@
                 modesList.map { mode ->
                     ModeTileViewModel(
                         id = mode.id,
-                        icon = zenModeInteractor.getModeIcon(mode, context),
-                        text = mode.rule.name,
+                        icon = zenModeInteractor.getModeIcon(context, mode),
+                        text = mode.name,
                         subtext = getTileSubtext(mode),
                         enabled = mode.isActive,
                         onClick = {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ModesTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ModesTileTest.kt
index a5de7cd..c2f035f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ModesTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ModesTileTest.kt
@@ -41,6 +41,8 @@
 import com.android.systemui.qs.tiles.viewmodel.QSTileConfigTestBuilder
 import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
 import com.android.systemui.res.R
+import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
+import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
 import com.android.systemui.statusbar.policy.ui.dialog.ModesDialogDelegate
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.settings.FakeSettings
@@ -57,6 +59,7 @@
 import org.junit.runner.RunWith
 import org.mockito.Mock
 import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.mock
 import org.mockito.kotlin.whenever
 
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -87,7 +90,12 @@
 
     private val inputHandler = FakeQSTileIntentUserInputHandler()
     private val zenModeRepository = FakeZenModeRepository()
-    private val tileDataInteractor = ModesTileDataInteractor(zenModeRepository, testDispatcher)
+    private val tileDataInteractor =
+        ModesTileDataInteractor(
+            context,
+            ZenModeInteractor(zenModeRepository, mock<NotificationSettingsRepository>()),
+            testDispatcher
+        )
     private val mapper =
         ModesTileMapper(
             context.orCreateTestableResources