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

Commit 0c312b88 authored by Julia Reynolds's avatar Julia Reynolds Committed by Ioana Alexandru
Browse files

Dual target modes tile

The secondary tap target can now toggle DND directly.

Updated ZenModeInteractor#dndMode to make it a StateFlow, so we can
reuse it both here and for the DND quick affordance.

Bug: 380908293
Test: ModesTileUserActionInteractorTest
Test: manually test that the toggle works
Flag: android.app.modes_ui
Flag: com.android.systemui.qs_ui_refactor_compose_fragment

Change-Id: I8f608203eb9f39da2fe2928362a629292e5a01d9
parent eb0a8e60
Loading
Loading
Loading
Loading
+3 −10
Original line number Diff line number Diff line
@@ -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)
+45 −4
Original line number Diff line number Diff line
@@ -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,14 +52,14 @@ 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 {
@@ -72,6 +81,38 @@ class ModesTileUserActionInteractorTest : SysuiTestCase() {
        verify(mockDialogDelegate).showDialog(eq(expandable))
    }

    @Test
    @EnableFlags(Flags.FLAG_QS_UI_REFACTOR_COMPOSE_FRAGMENT)
    fun handleToggleClick_dndActive() =
        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() =
        testScope.runTest {
            val dndMode by collectLastValue(zenModeInteractor.dndMode)

            zenModeRepository.addMode(TestModeBuilder.MANUAL_DND_INACTIVE)
            assertThat(dndMode?.isActive).isFalse()

            underTest.handleInput(
                QSTileInputTestKtx.toggleClick(data = modelOf(true, listOf("DND")))
            )

            assertThat(dndMode?.isActive).isTrue()
        }

    @Test
    fun handleLongClick_active() = runTest {
        underTest.handleInput(QSTileInputTestKtx.longClick(modelOf(true, listOf("DND"))))
+2 −12
Original line number Diff line number Diff line
@@ -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
+5 −0
Original line number Diff line number Diff line
@@ -109,6 +109,10 @@ constructor(
        userActionInteractor.handleClick(expandable)
    }

    override fun handleSecondaryClick(expandable: Expandable?) = runBlocking {
        userActionInteractor.handleToggleClick()
    }

    override fun getLongClickIntent(): Intent = userActionInteractor.longClickIntent

    @VisibleForTesting
@@ -125,6 +129,7 @@ constructor(
            secondaryLabel = tileState.secondaryLabel
            contentDescription = tileState.contentDescription
            expandedAccessibilityClassName = tileState.expandedAccessibilityClassName
            handlesSecondaryClick = true
        }
    }

+29 −2
Original line number Diff line number Diff line
@@ -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()
                }
                is QSTileUserAction.LongClick -> {
                    qsTileIntentUserInputHandler.handle(action.expandable, longClickIntent)
                }
@@ -56,4 +62,25 @@ constructor(
        // Show a dialog with the list of modes to configure.
        dialogDelegate.showDialog(expandable)
    }

    fun handleToggleClick() {
        if (QSComposeFragment.isUnexpectedlyInLegacyMode()) {
            return
        }

        val dnd = zenModeInteractor.dndMode.value
        if (dnd == null) {
            Log.wtf(TAG, "Triggered DND but it's null!?")
            return
        }
        if (dnd.isActive) {
            zenModeInteractor.deactivateMode(dnd)
        } else {
            zenModeInteractor.activateMode(dnd)
        }
    }

    companion object {
        const val TAG = "ModesTileUserActionInteractor"
    }
}
Loading