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

Commit 536afb49 authored by Ioana Alexandru's avatar Ioana Alexandru
Browse files

Modes tile: open simple dialog

Test: ModesTileUserActionInteractorTest + manually opened the dialog
Bug: 346519570
Flag: android.app.modes_ui
Change-Id: I9d03d26aed7b46bba2009e0d20d874538c6f7e5f
parent 78fbaef0
Loading
Loading
Loading
Loading
+36 −1
Original line number Diff line number Diff line
@@ -21,14 +21,23 @@ import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
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.phone.SystemUIDialog
import com.android.systemui.statusbar.policy.ui.dialog.ModesDialogDelegate
import com.google.common.truth.Truth
import kotlin.coroutines.EmptyCoroutineContext
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever

@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -36,7 +45,33 @@ import org.junit.runner.RunWith
class ModesTileUserActionInteractorTest : SysuiTestCase() {
    private val inputHandler = FakeQSTileIntentUserInputHandler()

    val underTest = ModesTileUserActionInteractor(inputHandler)
    @Mock private lateinit var dialogTransitionAnimator: DialogTransitionAnimator
    @Mock private lateinit var dialogDelegate: ModesDialogDelegate
    @Mock private lateinit var mockDialog: SystemUIDialog

    private lateinit var underTest: ModesTileUserActionInteractor

    @Before
    fun setup() {
        MockitoAnnotations.initMocks(this)

        whenever(dialogDelegate.createDialog()).thenReturn(mockDialog)

        underTest =
            ModesTileUserActionInteractor(
                EmptyCoroutineContext,
                inputHandler,
                dialogTransitionAnimator,
                dialogDelegate,
            )
    }

    @Test
    fun handleClick() = runTest {
        underTest.handleInput(QSTileInputTestKtx.click(ModesTileModel(false)))

        verify(mockDialog).show()
    }

    @Test
    fun handleLongClick() = runTest {
+74 −0
Original line number Diff line number Diff line
/*
 * 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.tiles.impl.modes.ui

import android.graphics.drawable.TestStubDrawable
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
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
import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
import com.android.systemui.res.R
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class ModesTileMapperTest : SysuiTestCase() {
    val config =
        QSTileConfigTestBuilder.build {
            uiConfig =
                QSTileUIConfig.Resource(
                    iconRes = R.drawable.qs_dnd_icon_off,
                    labelRes = R.string.quick_settings_modes_label,
                )
        }

    val underTest =
        ModesTileMapper(
            context.orCreateTestableResources
                .apply {
                    addOverride(R.drawable.qs_dnd_icon_on, TestStubDrawable())
                    addOverride(R.drawable.qs_dnd_icon_off, TestStubDrawable())
                }
                .resources,
            context.theme,
        )

    @Test
    fun inactiveState() {
        val model = ModesTileModel(isActivated = false)

        val state = underTest.map(config, model)

        assertThat(state.activationState).isEqualTo(QSTileState.ActivationState.INACTIVE)
        assertThat(state.iconRes).isEqualTo(R.drawable.qs_dnd_icon_off)
    }

    @Test
    fun activeState() {
        val model = ModesTileModel(isActivated = true)

        val state = underTest.map(config, model)

        assertThat(state.activationState).isEqualTo(QSTileState.ActivationState.ACTIVE)
        assertThat(state.iconRes).isEqualTo(R.drawable.qs_dnd_icon_on)
    }
}
+9 −0
Original line number Diff line number Diff line
@@ -1084,6 +1084,15 @@
    <!-- QuickStep: Accessibility to toggle overview [CHAR LIMIT=40] -->
    <string name="quick_step_accessibility_toggle_overview">Toggle Overview</string>

    <!-- Priority modes dialog title [CHAR LIMIT=35] -->
    <string name="zen_modes_dialog_title">Priority modes</string>

    <!-- Priority modes dialog confirmation button [CHAR LIMIT=15] -->
    <string name="zen_modes_dialog_done">Done</string>

    <!-- Priority modes dialog settings shortcut button [CHAR LIMIT=15] -->
    <string name="zen_modes_dialog_settings">Settings</string>

    <!-- Zen mode: Priority only introduction message on first use -->
    <string name="zen_priority_introduction">You won\'t be disturbed by sounds and vibrations, except from alarms, reminders, events, and callers you specify. You\'ll still hear anything you choose to play including music, videos, and games.</string>

+4 −2
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import com.android.systemui.qs.tiles.viewmodel.QSTileState
import com.android.systemui.res.R
import javax.inject.Inject
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

class ModesTile
@Inject
@@ -91,8 +92,8 @@ constructor(

    override fun newTileState() = BooleanState()

    override fun handleClick(expandable: Expandable?) {
        // TODO(b/346519570) open dialog
    override fun handleClick(expandable: Expandable?) = runBlocking {
        userActionInteractor.handleClick(expandable)
    }

    override fun getLongClickIntent(): Intent = userActionInteractor.longClickIntent
@@ -107,6 +108,7 @@ constructor(
                label = tileLabel
                secondaryLabel = tileState.secondaryLabel
                contentDescription = tileState.contentDescription
                forceExpandIcon = true
            }
        }
    }
+33 −1
Original line number Diff line number Diff line
@@ -16,19 +16,31 @@

package com.android.systemui.qs.tiles.impl.modes.domain.interactor

//noinspection CleanArchitectureDependencyViolation: dialog needs to be opened on click
import android.content.Intent
import android.provider.Settings
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.animation.Expandable
import com.android.systemui.dagger.qualifiers.Main
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.ui.dialog.ModesDialogDelegate
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.withContext

class ModesTileUserActionInteractor
@Inject
constructor(
    @Main private val coroutineContext: CoroutineContext,
    private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
    private val dialogTransitionAnimator: DialogTransitionAnimator,
    private val dialogDelegate: ModesDialogDelegate,
) : QSTileUserActionInteractor<ModesTileModel> {
    val longClickIntent = Intent(Settings.ACTION_ZEN_MODE_SETTINGS)

@@ -36,7 +48,7 @@ constructor(
        with(input) {
            when (action) {
                is QSTileUserAction.Click -> {
                    // TODO(b/346519570) open dialog
                    handleClick(action.expandable)
                }
                is QSTileUserAction.LongClick -> {
                    qsTileIntentUserActionHandler.handle(action.expandable, longClickIntent)
@@ -44,4 +56,24 @@ constructor(
            }
        }
    }

    suspend fun handleClick(expandable: Expandable?) {
        // Show a dialog with the list of modes to configure. Dialogs shown by the
        // DialogTransitionAnimator must be created and shown on the main thread, so we post it to
        // the UI handler.
        withContext(coroutineContext) {
            val dialog = dialogDelegate.createDialog()

            expandable
                ?.dialogTransitionController(
                    DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG)
                )
                ?.let { controller -> dialogTransitionAnimator.show(dialog, controller) }
                ?: dialog.show()
        }
    }

    companion object {
        private const val INTERACTION_JANK_TAG = "configure_priority_modes"
    }
}
Loading