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

Commit f4bf234d authored by Kevin Chyn's avatar Kevin Chyn
Browse files

Ensure RDM dialog is shown after screen off/on

Turning off the display dismisses the RDM dialog. However, when the
device turns on again, the device is still in the RDM state. In this
case, we should re-show the RDM dialog once Keyguard is dismissed.

Fixes: 394228925
Flag: EXEMPT bugfix
Test: manual
Test: atest RearDisplayCoreStartableTest
Change-Id: Id9c80a870ed27099f2ce809c4b7ce452f108bfa7
parent fedfa791
Loading
Loading
Loading
Loading
+47 −20
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.content.Context
import android.hardware.devicestate.DeviceStateManager
import android.hardware.devicestate.feature.flags.Flags
import androidx.annotation.VisibleForTesting
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -28,8 +30,11 @@ import com.android.systemui.statusbar.phone.SystemUIDialog
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch

/**
 * Provides a {@link com.android.systemui.statusbar.phone.SystemUIDialog} to be shown on the inner
@@ -46,6 +51,7 @@ internal constructor(
    private val rearDisplayStateInteractor: RearDisplayStateInteractor,
    private val rearDisplayInnerDialogDelegateFactory: RearDisplayInnerDialogDelegate.Factory,
    @Application private val scope: CoroutineScope,
    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
) : CoreStartable, AutoCloseable {

    companion object {
@@ -53,6 +59,16 @@ internal constructor(
    }

    @VisibleForTesting var stateChangeListener: Job? = null
    private val keyguardVisible = MutableStateFlow(false)
    private val keyguardVisibleFlow = keyguardVisible.asStateFlow()

    @VisibleForTesting
    val keyguardCallback =
        object : KeyguardUpdateMonitorCallback() {
            override fun onKeyguardVisibilityChanged(visible: Boolean) {
                keyguardVisible.value = visible
            }
        }

    override fun close() {
        stateChangeListener?.cancel()
@@ -62,13 +78,23 @@ internal constructor(
        if (Flags.deviceStateRdmV2()) {
            var dialog: SystemUIDialog? = null

            keyguardUpdateMonitor.registerCallback(keyguardCallback)

            stateChangeListener =
                rearDisplayStateInteractor.state
                    .map {
                        when (it) {
                scope.launch {
                    combine(rearDisplayStateInteractor.state, keyguardVisibleFlow) {
                            rearDisplayState,
                            keyguardVisible ->
                            Pair(rearDisplayState, keyguardVisible)
                        }
                        .collectLatest { (rearDisplayState, keyguardVisible) ->
                            when (rearDisplayState) {
                                is RearDisplayStateInteractor.State.Enabled -> {
                                    if (!keyguardVisible) {
                                        val rearDisplayContext =
                                    context.createDisplayContext(it.innerDisplay)
                                            context.createDisplayContext(
                                                rearDisplayState.innerDisplay
                                            )
                                        val delegate =
                                            rearDisplayInnerDialogDelegateFactory.create(
                                                rearDisplayContext,
@@ -76,6 +102,7 @@ internal constructor(
                                            )
                                        dialog = delegate.createDialog().apply { show() }
                                    }
                                }

                                is RearDisplayStateInteractor.State.Disabled -> {
                                    dialog?.dismiss()
@@ -83,7 +110,7 @@ internal constructor(
                                }
                            }
                        }
                    .launchIn(scope)
                }
        }
    }
}
+23 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.view.Display
import androidx.test.filters.SmallTest
import com.android.keyguard.keyguardUpdateMonitor
import com.android.systemui.SysuiTestCase
import com.android.systemui.deviceStateManager
import com.android.systemui.display.domain.interactor.RearDisplayStateInteractor
@@ -37,6 +38,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito.times
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
@@ -59,6 +61,7 @@ class RearDisplayCoreStartableTest : SysuiTestCase() {
            fakeRearDisplayStateInteractor,
            kosmos.rearDisplayInnerDialogDelegateFactory,
            kosmos.testScope,
            kosmos.keyguardUpdateMonitor,
        )

    @Before
@@ -96,6 +99,26 @@ class RearDisplayCoreStartableTest : SysuiTestCase() {
            }
        }

    @Test
    @EnableFlags(FLAG_DEVICE_STATE_RDM_V2)
    fun testDialogResumesAfterKeyguardGone() =
        kosmos.runTest {
            impl.use {
                it.start()
                fakeRearDisplayStateInteractor.emitRearDisplay()

                verify(mockDialog).show()

                it.keyguardCallback.onKeyguardVisibilityChanged(true)
                // Do not need to check that the dialog is dismissed, since SystemUIDialog
                // implementation handles that. We just toggle keyguard here so that the flow
                // emits.

                it.keyguardCallback.onKeyguardVisibilityChanged(false)
                verify(mockDialog, times(2)).show()
            }
        }

    private class FakeRearDisplayStateInteractor(private val kosmos: Kosmos) :
        RearDisplayStateInteractor {
        private val stateFlow = MutableSharedFlow<RearDisplayStateInteractor.State>()