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

Commit 0870068e authored by Luna Zhang's avatar Luna Zhang
Browse files

The volume dialog should not show up if the QS shade is expanded with volume slider in it

Bug: b/378513663
Test: VolumeDialogVisibilityInteractorTest
Flag: com.android.systemui.qs_tile_detailed_view

Change-Id: I654c8df8caedc9f945395a0b4a67c04cb6686ace
parent 3bf9f89b
Loading
Loading
Loading
Loading
+95 −5
Original line number Diff line number Diff line
@@ -17,14 +17,19 @@
package com.android.systemui.volume.dialog.domain.interactor

import android.app.ActivityManager
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_QS_TILE_DETAILED_VIEW
import com.android.systemui.SysuiTestCase
import com.android.systemui.accessibility.data.repository.accessibilityRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.fakeVolumeDialogController
import com.android.systemui.res.R
import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.testKosmos
import com.android.systemui.volume.Events
import com.android.systemui.volume.dialog.shared.model.VolumeDialogSafetyWarningModel
@@ -53,15 +58,16 @@ class VolumeDialogVisibilityInteractorTest : SysuiTestCase() {
            volumeDialogStateInteractor.setSafetyWarning(VolumeDialogSafetyWarningModel.Invisible)
        }

    private val underTest: VolumeDialogVisibilityInteractor =
    private val underTest: VolumeDialogVisibilityInteractor by lazy {
        kosmos.volumeDialogVisibilityInteractor
    }

    @Test
    fun testShowRequest_visible() =
        with(kosmos) {
            testScope.runTest {
                runCurrent()
                val visibilityModel by collectLastValue(underTest.dialogVisibility)
                runCurrent()
                fakeVolumeDialogController.onShowRequested(
                    Events.SHOW_REASON_VOLUME_CHANGED,
                    false,
@@ -84,8 +90,8 @@ class VolumeDialogVisibilityInteractorTest : SysuiTestCase() {
    fun testDismissRequest_dismissed() =
        with(kosmos) {
            testScope.runTest {
                runCurrent()
                val visibilityModel by collectLastValue(underTest.dialogVisibility)
                runCurrent()
                fakeVolumeDialogController.onShowRequested(
                    Events.SHOW_REASON_VOLUME_CHANGED,
                    false,
@@ -107,8 +113,8 @@ class VolumeDialogVisibilityInteractorTest : SysuiTestCase() {
    fun testTimeout_dismissed() =
        with(kosmos) {
            testScope.runTest {
                runCurrent()
                val visibilityModel by collectLastValue(underTest.dialogVisibility)
                runCurrent()
                fakeVolumeDialogController.onShowRequested(
                    Events.SHOW_REASON_VOLUME_CHANGED,
                    false,
@@ -127,8 +133,8 @@ class VolumeDialogVisibilityInteractorTest : SysuiTestCase() {
    fun testResetTimeoutInterruptsEvents() =
        with(kosmos) {
            testScope.runTest {
                runCurrent()
                val visibilityModel by collectLastValue(underTest.dialogVisibility)
                runCurrent()
                fakeVolumeDialogController.onShowRequested(
                    Events.SHOW_REASON_VOLUME_CHANGED,
                    false,
@@ -147,4 +153,88 @@ class VolumeDialogVisibilityInteractorTest : SysuiTestCase() {
                assertThat(fakeVolumeDialogController.hasUserActivity).isTrue()
            }
        }

    @Test
    @EnableSceneContainer
    @EnableFlags(FLAG_QS_TILE_DETAILED_VIEW)
    fun testShowRequest_whenQsSliderFeatureEnabledAndQsNotExpanded_dialogVisible() {
        with(kosmos) {
            testScope.runTest {
                overrideResource(R.bool.config_enableDesktopAudioTileDetailsView, true)
                val visibilityModel by collectLastValue(underTest.dialogVisibility)
                shadeTestUtil.setQsExpansion(0f)
                runCurrent()

                fakeVolumeDialogController.onShowRequested(
                    Events.SHOW_REASON_VOLUME_CHANGED,
                    false,
                    ActivityManager.LOCK_TASK_MODE_LOCKED,
                )
                runCurrent()

                assertThat(visibilityModel!!)
                    .isEqualTo(
                        VolumeDialogVisibilityModel.Visible(
                            Events.SHOW_REASON_VOLUME_CHANGED,
                            false,
                            ActivityManager.LOCK_TASK_MODE_LOCKED,
                        )
                    )
            }
        }
    }

    @Test
    @EnableSceneContainer
    @EnableFlags(FLAG_QS_TILE_DETAILED_VIEW)
    fun testShowRequest_whenQsSliderFeatureEnabledAndQsExpanded_dialogInvisible() {
        with(kosmos) {
            testScope.runTest {
                overrideResource(R.bool.config_enableDesktopAudioTileDetailsView, true)
                val visibilityModel by collectLastValue(underTest.dialogVisibility)
                shadeTestUtil.setQsExpansion(1f)
                runCurrent()

                fakeVolumeDialogController.onShowRequested(
                    Events.SHOW_REASON_VOLUME_CHANGED,
                    false,
                    ActivityManager.LOCK_TASK_MODE_LOCKED,
                )
                runCurrent()

                assertThat(visibilityModel!!).isEqualTo(VolumeDialogVisibilityModel.Invisible)
            }
        }
    }

    @Test
    @EnableSceneContainer
    @EnableFlags(FLAG_QS_TILE_DETAILED_VIEW)
    fun testShowRequest_whenQsSliderFeatureEnabledAndQsBecomesExpanded_dialogDismissed() {
        with(kosmos) {
            testScope.runTest {
                overrideResource(R.bool.config_enableDesktopAudioTileDetailsView, true)
                val visibilityModel by collectLastValue(underTest.dialogVisibility)
                shadeTestUtil.setQsExpansion(0f)
                runCurrent()

                fakeVolumeDialogController.onShowRequested(
                    Events.SHOW_REASON_VOLUME_CHANGED,
                    false,
                    ActivityManager.LOCK_TASK_MODE_LOCKED,
                )
                runCurrent()

                shadeTestUtil.setQsExpansion(1f)
                runCurrent()

                assertThat(visibilityModel!!)
                    .isEqualTo(
                        VolumeDialogVisibilityModel.Dismissed(
                            Events.DISMISS_REASON_QUICK_SETTINGS_EXPANDED
                        )
                    )
            }
        }
    }
}
+9 −2
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ public class Events {
    public static final int DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED = 9;
    public static final int DISMISS_REASON_CSD_WARNING_TIMEOUT = 10;
    public static final int DISMISS_REASON_POSTURE_CHANGED = 11;
    public static final int DISMISS_REASON_QUICK_SETTINGS_EXPANDED = 12;

    public static final String[] DISMISS_REASONS = {
            "unknown",
@@ -114,7 +115,8 @@ public class Events {
            "output_chooser",
            "usb_temperature_below_threshold",
            "csd_warning_timeout",
            "posture_changed"
            "posture_changed",
            "quick_settings_expanded"
    };

    public static final int SHOW_REASON_UNKNOWN = 0;
@@ -184,7 +186,10 @@ public class Events {
        // reserving 141 for DISMISS_REASON_OUTPUT_CHOOSER which is currently unused
        @UiEvent(doc = "The volume dialog was dismissed because the usb high temperature alarm "
                 + "changed")
        VOLUME_DIALOG_DISMISS_USB_TEMP_ALARM_CHANGED(142);
        VOLUME_DIALOG_DISMISS_USB_TEMP_ALARM_CHANGED(142),
        @UiEvent(doc = "The volume dialog was dismissed because the quick settings shade was "
                + "expanded")
        VOLUME_DIALOG_DISMISS_QUICK_SETTINGS(2345);

        private final int mId;
        VolumeDialogCloseEvent(int id) {
@@ -210,6 +215,8 @@ public class Events {
                    return VOLUME_DIALOG_DISMISS_STREAM_GONE;
                case DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED:
                    return VOLUME_DIALOG_DISMISS_USB_TEMP_ALARM_CHANGED;
                case DISMISS_REASON_QUICK_SETTINGS_EXPANDED:
                    return VOLUME_DIALOG_DISMISS_QUICK_SETTINGS;
            }
            return INVALID;
        }
+48 −2
Original line number Diff line number Diff line
@@ -17,10 +17,14 @@
package com.android.systemui.volume.dialog.domain.interactor

import android.annotation.SuppressLint
import android.content.Context
import android.provider.Settings
import android.view.accessibility.AccessibilityManager
import com.android.systemui.accessibility.data.repository.AccessibilityRepository
import com.android.systemui.plugins.VolumeDialogController
import com.android.systemui.qs.flags.QsDetailedView
import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository
import com.android.systemui.volume.Events
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPlugin
@@ -30,6 +34,7 @@ import com.android.systemui.volume.dialog.domain.model.VolumeDialogEventModel
import com.android.systemui.volume.dialog.shared.model.VolumeDialogSafetyWarningModel
import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel.Dismissed
import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel.Invisible
import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel.Visible
import com.android.systemui.volume.dialog.utils.VolumeTracer
import javax.inject.Inject
@@ -42,6 +47,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.mapLatest
@@ -60,6 +66,7 @@ import kotlinx.coroutines.flow.stateIn
class VolumeDialogVisibilityInteractor
@Inject
constructor(
    context: Context,
    @VolumeDialogPlugin coroutineScope: CoroutineScope,
    callbacksInteractor: VolumeDialogCallbacksInteractor,
    private val stateInteractor: VolumeDialogStateInteractor,
@@ -68,17 +75,22 @@ constructor(
    private val accessibilityRepository: AccessibilityRepository,
    private val controller: VolumeDialogController,
    private val secureSettingsRepository: SecureSettingsRepository,
    private val shadeInteractor: ShadeInteractor,
) {

    /** @see computeTimeout */
    private val defaultTimeout = 3.seconds

    private val showVolumeSliderInQsShade =
        QsDetailedView.isEnabled &&
            context.resources.getBoolean(R.bool.config_enableDesktopAudioTileDetailsView)

    @SuppressLint("SharedFlowCreation")
    private val mutableDismissDialogEvents = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
    val dialogVisibility: Flow<VolumeDialogVisibilityModel> =
        repository.dialogVisibility
            .onEach { controller.notifyVisible(it is Visible) }
            .stateIn(coroutineScope, SharingStarted.Eagerly, VolumeDialogVisibilityModel.Invisible)
            .stateIn(coroutineScope, SharingStarted.Eagerly, Invisible)

    init {
        merge(
@@ -88,7 +100,27 @@ constructor(
                },
                callbacksInteractor.event,
            )
            .mapNotNull { it.toVisibilityModel() }
            .mapNotNull { event ->
                val visibilityModel = event.toVisibilityModel()

                // If volume slider in QS is not supposed to be shown, or if the event doesn't map
                // to a Visible state, then we don't need to check for QS visibility.
                if (!showVolumeSliderInQsShade || visibilityModel !is Visible) {
                    return@mapNotNull visibilityModel
                }

                // At this point, showVolumeSliderInQsShade is true AND visibilityModel is Visible.
                // Now check if Quick Settings is expanded.
                val isQsExpanded = shadeInteractor.isQsExpanded.first()

                if (isQsExpanded) {
                    // Suppress volume dialog
                    null
                } else {
                    // Show volume dialog
                    visibilityModel
                }
            }
            .onEach { model ->
                updateVisibility { model }
                if (model is Visible) {
@@ -96,6 +128,20 @@ constructor(
                }
            }
            .launchIn(coroutineScope)

        if (showVolumeSliderInQsShade) {
            // Dismiss the volume dialog if QS becomes expanded while the dialog is visible
            combine(shadeInteractor.isQsExpanded, dialogVisibility) {
                    isQsExpandedNow,
                    currentDialogVisibility ->
                    when {
                        isQsExpandedNow && currentDialogVisibility is Visible -> {
                            dismissDialog(Events.DISMISS_REASON_QUICK_SETTINGS_EXPANDED)
                        }
                    }
                }
                .launchIn(coroutineScope)
        }
    }

    /**
+4 −0
Original line number Diff line number Diff line
@@ -16,10 +16,12 @@

package com.android.systemui.volume.dialog.domain.interactor

import android.content.applicationContext
import com.android.systemui.accessibility.data.repository.accessibilityRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.plugins.volumeDialogController
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shared.settings.data.repository.secureSettingsRepository
import com.android.systemui.volume.dialog.data.repository.volumeDialogVisibilityRepository
import com.android.systemui.volume.dialog.utils.volumeTracer
@@ -27,6 +29,7 @@ import com.android.systemui.volume.dialog.utils.volumeTracer
val Kosmos.volumeDialogVisibilityInteractor by
    Kosmos.Fixture {
        VolumeDialogVisibilityInteractor(
            applicationContext,
            applicationCoroutineScope,
            volumeDialogCallbacksInteractor,
            volumeDialogStateInteractor,
@@ -35,5 +38,6 @@ val Kosmos.volumeDialogVisibilityInteractor by
            accessibilityRepository,
            volumeDialogController,
            secureSettingsRepository,
            shadeInteractor,
        )
    }