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

Commit e8d7cf37 authored by Massimo Carli's avatar Massimo Carli Committed by Android (Google) Code Review
Browse files

Merge "[10/n] Handle recents in Letterbox surfaces lifecycle" into main

parents f5a9dfdc 4300dbae
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.view.SurfaceControl
import android.window.TransitionInfo
import com.android.internal.protolog.ProtoLog
import com.android.window.flags.Flags.appCompatRefactoring
import com.android.wm.shell.common.transition.TransitionStateHolder
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT
import com.android.wm.shell.shared.TransitionUtil.isClosingType
import com.android.wm.shell.sysui.ShellInit
@@ -33,7 +34,8 @@ import com.android.wm.shell.transition.Transitions
class LetterboxTransitionObserver(
    shellInit: ShellInit,
    private val transitions: Transitions,
    private val letterboxController: LetterboxController
    private val letterboxController: LetterboxController,
    private val transitionStateHolder: TransitionStateHolder
) : Transitions.TransitionObserver {

    companion object {
@@ -71,11 +73,11 @@ class LetterboxTransitionObserver(
                    change.endAbsBounds.height()
                )
                with(letterboxController) {
                    if (isClosingType(change.mode)) {
                        destroyLetterboxSurface(
                            key,
                            startTransaction
                        )
                    // TODO(b/380274087) Handle return to home from a recents transition.
                    if (isClosingType(change.mode) &&
                        !transitionStateHolder.isRecentsTransitionRunning()) {
                        // For the other types of close we need to check the recents.
                        destroyLetterboxSurface(key, finishTransaction)
                    } else {
                        val isTopActivityLetterboxed = ti.appCompatTaskInfo.isTopActivityLetterboxed
                        if (isTopActivityLetterboxed) {
+5 −2
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ import com.android.wm.shell.common.MultiInstanceHelper;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.transition.TransitionStateHolder;
import com.android.wm.shell.compatui.letterbox.LetterboxCommandHandler;
import com.android.wm.shell.compatui.letterbox.LetterboxController;
import com.android.wm.shell.compatui.letterbox.LetterboxTransitionObserver;
@@ -1316,9 +1317,11 @@ public abstract class WMShellModule {
    static LetterboxTransitionObserver provideLetterboxTransitionObserver(
            @NonNull ShellInit shellInit,
            @NonNull Transitions transitions,
            @NonNull LetterboxController letterboxController
            @NonNull LetterboxController letterboxController,
            @NonNull TransitionStateHolder transitionStateHolder
    ) {
        return new LetterboxTransitionObserver(shellInit, transitions, letterboxController);
        return new LetterboxTransitionObserver(shellInit, transitions, letterboxController,
                transitionStateHolder);
    }

    @WMSingleton
+39 −5
Original line number Diff line number Diff line
@@ -25,9 +25,12 @@ import android.testing.AndroidTestingRunner
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_CLOSE
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
import com.android.window.flags.Flags
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.common.transition.TransitionStateHolder
import com.android.wm.shell.recents.RecentsTransitionHandler
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.util.TransitionObserverInputBuilder
@@ -37,6 +40,7 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
@@ -154,21 +158,38 @@ class LetterboxTransitionObserverTest : ShellTestCase() {
    }

    @Test
    fun `When closing change letterbox surface destroy is triggered`() {
    fun `When closing change with no recents running letterbox surfaces are destroyed`() {
        runTestScenario { r ->
            executeTransitionObserverTest(observerFactory = r.observerFactory) {
                r.invokeShellInit()

                inputBuilder {
                    buildTransitionInfo()
                    r.configureRecentsState(running = false)
                    r.createClosingChange(inputBuilder = this)
                }

                validateOutput {
                    r.destroyEventDetected(expected = true)
                    r.creationEventDetected(expected = false)
                    r.visibilityEventDetected(expected = false, visible = false)
                    r.updateSurfaceBoundsEventDetected(expected = false)
                }
            }
        }
    }

    @Test
    fun `When closing change and recents are running letterbox surfaces are not destroyed`() {
        runTestScenario { r ->
            executeTransitionObserverTest(observerFactory = r.observerFactory) {
                r.invokeShellInit()

                inputBuilder {
                    buildTransitionInfo()
                    r.createClosingChange(inputBuilder = this)
                    r.configureRecentsState(running = true)
                }

                validateOutput {
                    r.destroyEventDetected(expected = false)
                }
            }
        }
@@ -197,6 +218,7 @@ class LetterboxTransitionObserverTest : ShellTestCase() {
        private val transitions: Transitions
        private val letterboxController: LetterboxController
        private val letterboxObserver: LetterboxTransitionObserver
        private val transitionStateHolder: TransitionStateHolder

        val observerFactory: () -> LetterboxTransitionObserver

@@ -205,8 +227,16 @@ class LetterboxTransitionObserverTest : ShellTestCase() {
            shellInit = ShellInit(executor)
            transitions = mock<Transitions>()
            letterboxController = mock<LetterboxController>()
            transitionStateHolder =
                TransitionStateHolder(shellInit, mock<RecentsTransitionHandler>())
            spyOn(transitionStateHolder)
            letterboxObserver =
                LetterboxTransitionObserver(shellInit, transitions, letterboxController)
                LetterboxTransitionObserver(
                    shellInit,
                    transitions,
                    letterboxController,
                    transitionStateHolder
                )
            observerFactory = { letterboxObserver }
        }

@@ -218,6 +248,10 @@ class LetterboxTransitionObserverTest : ShellTestCase() {
            verify(transitions, expected.asMode()).registerObserver(observer())
        }

        fun configureRecentsState(running: Boolean) {
            doReturn(running).`when`(transitionStateHolder).isRecentsTransitionRunning()
        }

        fun creationEventDetected(
            expected: Boolean,
            displayId: Int = DISPLAY_ID,
+46 −0
Original line number Diff line number Diff line
@@ -77,6 +77,30 @@ class TransitionObserverTestContext : TransitionObserverTestStep {
        validateObj.validate()
    }

    fun validateOnMerged(
        validate:
        TransitionObserverOnTransitionMergedValidation.() -> Unit
    ) {
        val validateObj = TransitionObserverOnTransitionMergedValidation()
        transitionObserver.onTransitionMerged(
            validateObj.playing,
            validateObj.merged
        )
        validateObj.validate()
    }

    fun validateOnFinished(
        validate:
        TransitionObserverOnTransitionFinishedValidation.() -> Unit
    ) {
        val validateObj = TransitionObserverOnTransitionFinishedValidation()
        transitionObserver.onTransitionFinished(
            transitionReadyInput.transition,
            validateObj.aborted
        )
        validateObj.validate()
    }

    fun invokeObservable() {
        transitionObserver.onTransitionReady(
            transitionReadyInput.transition,
@@ -161,6 +185,28 @@ class TransitionObserverInputBuilder : TransitionObserverTestStep {
 */
class TransitionObserverResultValidation : TransitionObserverTestStep

/**
 * Phase responsible for the execution of validation methods after the
 * [TransitionObservable#onTransitionMerged] has been executed.
 */
class TransitionObserverOnTransitionMergedValidation : TransitionObserverTestStep {
    val merged = mock<IBinder>()
    val playing = mock<IBinder>()

    init {
        spyOn(merged)
        spyOn(playing)
    }
}

/**
 * Phase responsible for the execution of validation methods after the
 * [TransitionObservable#onTransitionFinished] has been executed.
 */
class TransitionObserverOnTransitionFinishedValidation : TransitionObserverTestStep {
    var aborted: Boolean = false
}

/**
 * Allows to run a test about a specific [TransitionObserver] passing the specific
 * implementation and input value as parameters for the [TransitionObserver#onTransitionReady]