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

Commit f25e3dfe authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[Action Corner] Handle QS and notification panel actions" into main

parents 60282158 424a84a4
Loading
Loading
Loading
Loading
+72 −7
Original line number Diff line number Diff line
@@ -21,19 +21,28 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.LauncherProxyService
import com.android.systemui.SysuiTestCase
import com.android.systemui.actioncorner.data.model.ActionCornerRegion
import com.android.systemui.actioncorner.data.model.ActionCornerRegion.BOTTOM_LEFT
import com.android.systemui.actioncorner.data.model.ActionCornerRegion.BOTTOM_RIGHT
import com.android.systemui.actioncorner.data.model.ActionCornerState
import com.android.systemui.actioncorner.data.model.ActionCornerState.ActiveActionCorner
import com.android.systemui.actioncorner.data.repository.FakeActionCornerRepository
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.shade.domain.interactor.enableDualShade
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.domain.interactor.shadeModeInteractor
import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.shared.system.actioncorner.ActionCornerConstants.HOME
import com.android.systemui.shared.system.actioncorner.ActionCornerConstants.OVERVIEW
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import org.junit.Before
import org.junit.runner.RunWith
@@ -41,35 +50,91 @@ import org.mockito.kotlin.mock
import org.mockito.kotlin.verify

@SmallTest
@EnableSceneContainer
@RunWith(AndroidJUnit4::class)
class ActionCornerInteractorTest : SysuiTestCase() {
    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
    private val Kosmos.actionCornerRepository by Fixture { FakeActionCornerRepository() }
    private val Kosmos.launcherProxyService by Fixture { mock<LauncherProxyService>() }
    private val Kosmos.underTest by Fixture {
        ActionCornerInteractor(kosmos.actionCornerRepository, kosmos.launcherProxyService)
        ActionCornerInteractor(
            testScope.coroutineContext,
            actionCornerRepository,
            launcherProxyService,
            shadeModeInteractor,
            shadeInteractor,
        )
    }

    @Before
    fun setUp() {
        kosmos.enableDualShade()
        kosmos.underTest.activateIn(kosmos.testScope)
    }

    @Test
    fun bottomLeftCornerActivated_notifyLauncherOfOverviewAction() =
        kosmos.runTest {
            actionCornerRepository.addState(
                ActionCornerState.ActiveActionCorner(BOTTOM_LEFT, DEFAULT_DISPLAY)
            )
            actionCornerRepository.addState(ActiveActionCorner(BOTTOM_LEFT, DEFAULT_DISPLAY))
            verify(launcherProxyService).onActionCornerActivated(OVERVIEW, DEFAULT_DISPLAY)
        }

    @Test
    fun bottomRightCornerActivated_notifyLauncherOfHomeAction() =
        kosmos.runTest {
            actionCornerRepository.addState(ActiveActionCorner(BOTTOM_RIGHT, DEFAULT_DISPLAY))
            verify(launcherProxyService).onActionCornerActivated(HOME, DEFAULT_DISPLAY)
        }

    @Test
    fun shadeCollapsed_topLeftCornerActivated_expandNotificationShade() =
        kosmos.runTest {
            shadeTestUtil.setShadeExpansion(0f)

            actionCornerRepository.addState(
                ActiveActionCorner(ActionCornerRegion.TOP_LEFT, DEFAULT_DISPLAY)
            )

            assertThat(sceneInteractor.currentOverlays.value)
                .containsExactly(Overlays.NotificationsShade)
        }

    @Test
    fun shadeExpanded_topLeftCornerActivated_collapseNotificationShade() =
        kosmos.runTest {
            shadeTestUtil.setShadeExpansion(1f)

            actionCornerRepository.addState(
                ActionCornerState.ActiveActionCorner(BOTTOM_RIGHT, DEFAULT_DISPLAY)
                ActiveActionCorner(ActionCornerRegion.TOP_LEFT, DEFAULT_DISPLAY)
            )
            verify(launcherProxyService).onActionCornerActivated(HOME, DEFAULT_DISPLAY)

            assertThat(sceneInteractor.currentOverlays.value)
                .doesNotContain(Overlays.NotificationsShade)
        }

    @Test
    fun qsCollapsed_topRightCornerActivated_expandQsPanel() =
        kosmos.runTest {
            shadeTestUtil.setQsExpansion(0f)

            actionCornerRepository.addState(
                ActiveActionCorner(ActionCornerRegion.TOP_RIGHT, DEFAULT_DISPLAY)
            )

            assertThat(sceneInteractor.currentOverlays.value)
                .containsExactly(Overlays.QuickSettingsShade)
        }

    @Test
    fun qsExpanded_topRightCornerActivated_collapseQsPanel() =
        kosmos.runTest {
            shadeTestUtil.setQsExpansion(1f)

            actionCornerRepository.addState(
                ActiveActionCorner(ActionCornerRegion.TOP_RIGHT, DEFAULT_DISPLAY)
            )

            assertThat(sceneInteractor.currentOverlays.value)
                .doesNotContain(Overlays.QuickSettingsShade)
        }
}
+42 −2
Original line number Diff line number Diff line
@@ -19,22 +19,34 @@ package com.android.systemui.actioncorner.domain.interactor
import com.android.systemui.LauncherProxyService
import com.android.systemui.actioncorner.data.model.ActionCornerRegion.BOTTOM_LEFT
import com.android.systemui.actioncorner.data.model.ActionCornerRegion.BOTTOM_RIGHT
import com.android.systemui.actioncorner.data.model.ActionCornerRegion.TOP_LEFT
import com.android.systemui.actioncorner.data.model.ActionCornerRegion.TOP_RIGHT
import com.android.systemui.actioncorner.data.model.ActionCornerState
import com.android.systemui.actioncorner.data.repository.ActionCornerRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import com.android.systemui.shade.shared.model.ShadeMode.Dual
import com.android.systemui.shared.system.actioncorner.ActionCornerConstants.HOME
import com.android.systemui.shared.system.actioncorner.ActionCornerConstants.OVERVIEW
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.withContext

@SysUISingleton
class ActionCornerInteractor
@Inject
constructor(
    @Main private val mainThreadContext: CoroutineContext,
    private val repository: ActionCornerRepository,
    private val launcherProxyService: LauncherProxyService,
    private val shadeModeInteractor: ShadeModeInteractor,
    private val shadeInteractor: ShadeInteractor,
) : ExclusiveActivatable() {

    override suspend fun onActivated(): Nothing {
@@ -43,13 +55,41 @@ constructor(
            .collect {
                // TODO(b/410791828): Read corresponding action from Action Corner Setting page
                when (it.region) {
                    TOP_LEFT -> {
                        if (isDualShadeEnabled()) {
                            withContext(mainThreadContext) {
                                if (shadeInteractor.isShadeAnyExpanded.value) {
                                    shadeInteractor.collapseNotificationsShade(LOGGING_REASON)
                                } else {
                                    shadeInteractor.expandNotificationsShade(LOGGING_REASON)
                                }
                            }
                        }
                    }
                    TOP_RIGHT -> {
                        if (isDualShadeEnabled()) {
                            withContext(mainThreadContext) {
                                if (shadeInteractor.isQsExpanded.value) {
                                    shadeInteractor.collapseQuickSettingsShade(LOGGING_REASON)
                                } else {
                                    shadeInteractor.expandQuickSettingsShade(LOGGING_REASON)
                                }
                            }
                        }
                    }
                    BOTTOM_LEFT ->
                        launcherProxyService.onActionCornerActivated(OVERVIEW, it.displayId)
                    BOTTOM_RIGHT -> launcherProxyService.onActionCornerActivated(HOME, it.displayId)
                    // TODO(b/411091884): Handle actions for notification shade and QS
                    else -> {}
                }
            }
        awaitCancellation()
    }

    private fun isDualShadeEnabled(): Boolean {
        return SceneContainerFlag.isEnabled && shadeModeInteractor.shadeMode.value == Dual
    }

    companion object {
        private const val LOGGING_REASON = "Active action corner"
    }
}