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

Commit 94ee2fcd authored by Fabian Kozynski's avatar Fabian Kozynski
Browse files

Prevent case of unreleased TaskView surface

When the ControlsActiviyt showing a TaskView is opened over the
lockscreen and subsequently opened from the QS tile, the TaskView ends
up in an inconsistent state, overlaying over launcher and impossible to
dismiss without resetting.

This CL prevents opening the ControlsActivity from the tile if it's
already showing, instead just closing the shade. If there's a different
device controls activity showing, we know that there's no TaskView
currently displaying so we can launch the activity.

This does not address the underlying cause (we need Activity Embedding
for that), but prevents entering into the bad state, serving as
mitigation until we can replace the TaskView.

Test: manual, reproduce steps in bug.
Test: atest DeviceControlsTileTest
Fixes: 351895427
Flag: EXEMPT BUG_FIX
Change-Id: I5c42d98c9182aa4394ac76594ded1e11ee29fae9
parent 46104d0b
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ import com.android.systemui.qs.QSHost
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.flags.QSComposeFragment
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.res.R
import com.android.systemui.util.mockito.any
@@ -75,6 +76,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.never
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters

@@ -98,6 +100,7 @@ class DeviceControlsTileTest(flags: FlagsParameterization) : SysuiTestCase() {
    @Mock private lateinit var controlsController: ControlsController
    @Mock private lateinit var serviceInfo: ControlsServiceInfo
    @Mock private lateinit var uiEventLogger: QsEventLogger
    @Mock private lateinit var panelInteractor: PanelInteractor
    @Captor
    private lateinit var listingCallbackCaptor:
        ArgumentCaptor<ControlsListingController.ControlsListingCallback>
@@ -320,6 +323,41 @@ class DeviceControlsTileTest(flags: FlagsParameterization) : SysuiTestCase() {
        verifyNoMoreInteractions(activityStarter)
    }

    @Test
    fun handleClick_alreadyVisible_noActivityStarted_panelCollapsed() {
        verify(controlsListingController)
            .observe(any(LifecycleOwner::class.java), capture(listingCallbackCaptor))
        `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
        `when`(controlsUiController.resolveActivity()).thenReturn(ControlsActivity::class.java)
        `when`(controlsController.getPreferredSelection())
            .thenReturn(
                SelectedItem.StructureItem(
                    StructureInfo(
                        ComponentName("pkg", "cls"),
                        "structure",
                        listOf(ControlInfo("id", "title", "subtitle", 1)),
                    )
                )
            )

        listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
        testableLooper.processAllMessages()

        `when`(controlsUiController.isShowing).thenReturn(true)

        tile.click(null)
        testableLooper.processAllMessages()

        verify(activityStarter, never())
            .startActivity(
                any(),
                anyBoolean(),
                nullable(ActivityTransitionAnimator.Controller::class.java),
                anyBoolean(),
            )
        verify(panelInteractor).collapsePanels()
    }

    @Test
    fun handleClick_available_shownOverLockscreenWhenLocked() {
        verify(controlsListingController)
@@ -441,6 +479,7 @@ class DeviceControlsTileTest(flags: FlagsParameterization) : SysuiTestCase() {
                activityStarter,
                qsLogger,
                controlsComponent,
                panelInteractor,
            )
            .also {
                it.initialize()
+12 −6
Original line number Diff line number Diff line
@@ -40,6 +40,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.logging.QSLogger
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.res.R
import java.util.concurrent.atomic.AtomicBoolean
@@ -58,6 +59,7 @@ constructor(
    activityStarter: ActivityStarter,
    qsLogger: QSLogger,
    private val controlsComponent: ControlsComponent,
    private val panelInteractor: PanelInteractor,
) :
    QSTileImpl<QSTile.State>(
        host,
@@ -125,6 +127,9 @@ constructor(

        mUiHandler.post {
            val showOverLockscreenWhenLocked = state.state == Tile.STATE_ACTIVE
            if (controlsComponent.getControlsUiController().get().isShowing) {
                panelInteractor.collapsePanels()
            } else {
                mActivityStarter.startActivity(
                    intent,
                    true /* dismissShade */,
@@ -133,6 +138,7 @@ constructor(
                )
            }
        }
    }

    override fun handleUpdateState(state: QSTile.State, arg: Any?) {
        state.label = tileLabel