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

Commit fe43c02c authored by Eric Lin's avatar Eric Lin
Browse files

Add flicker test for relaunching bubble into split screen.

This change adds a new flicker test, RelaunchBubbleIntoSplitScreenTest,
to verify the transition when a bubbled application is relaunched from a
secondary split-screen app. The test confirms that the existing bubble
is dismissed and its task correctly moves into the secondary
split-screen pane, replacing the previous app. This improves test
coverage for bubble and split-screen interactions.

The test infrastructure has been enhanced for greater flexibility. A
generic clickButtonAndWaitForSync extension function is introduced to
centralize the logic for clicking a button and waiting for a window
state change. Both TwoActivitiesAppHelper and NewTasksAppHelper are
updated to use this extension, simplifying their implementation.
NewTasksAppHelper is also extended with distinct methods (openNewTask
and openNewTaskWithRecycle) for different launch scenarios.

For improved test modularity, BubbleExitTestCases is extracted from
BubbleDismissesTestCases to provide a general set of verifications for
bubble exit transitions. A new SecondarySplitEnterTestCases is also
added to verify that an app correctly enters the secondary split-screen
area.

Finally, the LaunchNewTaskActivity test app is updated with a new button
that launches an activity using FLAG_ACTIVITY_CLEAR_TOP |
FLAG_ACTIVITY_NEW_TASK. This is crucial for triggering the desired
task-recycling behavior needed for this test scenario.

Bug: 438056383
Flag: EXEMPT TEST_ONLY
Test: atest WMShellExplicitFlickerTestsBubbles:RelaunchBubbleIntoSplitScreenTest
Change-Id: I12d273853e06b76a8a6b62e868c6af0768b2e3b5
parent df6b8da6
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ test_module_config {
        "com.android.wm.shell.flicker.bubbles.SwitchBetweenBubblesTest",
        "com.android.wm.shell.flicker.bubbles.ExpandedBubbleAppMoveTest",
        "com.android.wm.shell.flicker.bubbles.RelaunchSplitScreenToBubbleTest",
        "com.android.wm.shell.flicker.bubbles.RelaunchBubbleIntoSplitScreenTest",
    ],
}

@@ -232,3 +233,10 @@ test_module_config {
    test_suites: ["device-tests"],
    include_filters: ["com.android.wm.shell.flicker.bubbles.RelaunchSplitScreenToBubbleTest"],
}

test_module_config {
    name: "WMShellExplicitFlickerTestsBubbles-RelaunchBubbleIntoSplitScreenTest",
    base: "WMShellExplicitFlickerTestsBubbles",
    test_suites: ["device-tests"],
    include_filters: ["com.android.wm.shell.flicker.bubbles.RelaunchBubbleIntoSplitScreenTest"],
}
+3 −0
Original line number Diff line number Diff line
@@ -68,6 +68,9 @@
    },
    {
      "name": "WMShellExplicitFlickerTestsBubbles-RelaunchSplitScreenToBubbleTest"
    },
    {
      "name": "WMShellExplicitFlickerTestsBubbles-RelaunchBubbleIntoSplitScreenTest"
    }
  ]
}
+119 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.wm.shell.flicker.bubbles

import android.platform.test.annotations.Presubmit
import android.platform.test.annotations.RequiresFlagsEnabled
import android.tools.NavBar
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.NewTasksAppHelper
import com.android.wm.shell.Flags
import com.android.wm.shell.Utils.testSetupRule
import com.android.wm.shell.flicker.bubbles.RelaunchBubbleIntoSplitScreenTest.Companion.bubbleApp
import com.android.wm.shell.flicker.bubbles.testcase.BubbleExitTestCases
import com.android.wm.shell.flicker.bubbles.testcase.SecondarySplitEnterTestCases
import com.android.wm.shell.flicker.bubbles.utils.ApplyPerParameterRule
import com.android.wm.shell.flicker.bubbles.utils.BubbleFlickerTestHelper.collapseBubbleAppViaTouchOutside
import com.android.wm.shell.flicker.bubbles.utils.BubbleFlickerTestHelper.launchBubbleViaBubbleMenu
import com.android.wm.shell.flicker.bubbles.utils.BubbleFlickerTestHelper.withBubbleFullyDismissedAndGone
import com.android.wm.shell.flicker.bubbles.utils.RecordTraceWithTransitionRule
import com.android.wm.shell.flicker.utils.SplitScreenUtils
import com.android.wm.shell.flicker.utils.SplitScreenUtils.enterSplit
import com.android.wm.shell.flicker.utils.SplitScreenUtils.withSplitScreenComplete
import org.junit.FixMethodOrder
import org.junit.Rule
import org.junit.runners.MethodSorters

/**
 * Test relaunching a bubble from a secondary split-screen app.
 *
 * This test verifies that the existing bubble is dismissed and its app task is moved into the
 * secondary split-screen pane.
 *
 * To run this test:
 *     `atest WMShellExplicitFlickerTestsBubbles:RelaunchBubbleIntoSplitScreenTest`
 *
 * Pre-steps:
 * ```
 * 1. Launch [bubbleApp] into a collapsed bubble.
 * 2. Launch [primaryApp] and [secondaryApp] into split-screen.
 * ```
 *
 * Actions:
 * ```
 * From [secondaryApp], relaunch the [bubbleApp].
 * ```
 *
 * Verified tests:
 * - [BubbleFlickerTestBase]
 * - [BubbleExitTestCases]: Verifies the collapsed bubble is dismissed.
 * - [SecondarySplitEnterTestCases]: Verifies [bubbleApp] enters the secondary split.
 */
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_CREATE_ANY_BUBBLE)
@RequiresDevice
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Presubmit
// TODO: b/432604687 - Rename to ExpandBubbleByRelaunchingFromSplit once the expected behavior is
//  unblocked and the test logic is updated to verify it.
class RelaunchBubbleIntoSplitScreenTest : BubbleFlickerTestBase(),
    BubbleExitTestCases, SecondarySplitEnterTestCases {

    companion object {
        private val bubbleApp = testApp
        private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
        private val secondaryApp = NewTasksAppHelper(instrumentation)

        private val recordTraceWithTransitionRule =
            RecordTraceWithTransitionRule(
                setUpBeforeTransition = {
                    // Launch [bubbleApp] into collapsed bubble.
                    launchBubbleViaBubbleMenu(bubbleApp, tapl, wmHelper)
                    collapseBubbleAppViaTouchOutside(bubbleApp, wmHelper)

                    // Launch [primaryApp] and [secondaryApp] into split screen.
                    enterSplit(wmHelper, tapl, uiDevice, primaryApp, secondaryApp)
                },
                transition = {
                    // Relaunch bubble from secondary split.
                    secondaryApp.openNewTaskWithRecycle(uiDevice, wmHelper) {
                        // TODO: b/432604687 - Expected behavior is blocked by WM core reparent.
                        // Reopen the collapsed bubble.
                        // withBubbleAppInExpandedState(bubbleApp)

                        // Current behavior: Bubble task is converted into split.
                        withBubbleFullyDismissedAndGone()
                            .withSplitScreenComplete(primaryApp, secondaryApp = bubbleApp)
                    }
                },
                tearDownAfterTransition = {
                    bubbleApp.exit(wmHelper)
                    primaryApp.exit(wmHelper)
                    secondaryApp.exit(wmHelper)
                },
            )
    }

    @get:Rule
    val setUpRule = ApplyPerParameterRule(
        testSetupRule(NavBar.MODE_GESTURAL).around(recordTraceWithTransitionRule),
    )

    override val traceDataReader
        get() = recordTraceWithTransitionRule.reader

    override val previousSecondaryApp = secondaryApp
}
+5 −46
Original line number Diff line number Diff line
@@ -16,56 +16,15 @@

package com.android.wm.shell.flicker.bubbles.testcase

import android.tools.traces.component.ComponentNameMatcher.Companion.BUBBLE
import com.android.wm.shell.flicker.bubbles.utils.BubbleFlickerSubjects
import org.junit.Test

/**
 * Verifies bubble and its app are dismissed.
 */
interface BubbleDismissesTestCases : BubbleFlickerSubjects {

    /**
     * Verifies [BUBBLE] window is gone at the end of the transition.
     */
    @Test
    fun bubbleWindowIsGoneAtEnd() {
        wmStateSubjectAtEnd.notContains(BUBBLE)
    }

    /**
     * Verifies [BUBBLE] layer is gone at the end of the transition.
     */
    @Test
    fun bubbleLayerIsGoneAtEnd() {
        layerTraceEntrySubjectAtEnd.notContains(BUBBLE)
    }

    /**
     * Verifies [BUBBLE] window was visible then disappears.
     */
    @Test
    fun bubbleWindowWasVisibleThenDisappear() {
        wmTraceSubject
            .isAboveAppWindowVisible(BUBBLE)
            .then()
            // Use #isNonAppWindowInvisible here because the BUBBLE window may have been removed
            // from WM hierarchy.
            .isNonAppWindowInvisible(BUBBLE)
            .forAllEntries()
    }

    /**
     * Verifies [BUBBLE] layer was visible then disappears.
 * Verifies a bubble and its associated app window are fully dismissed.
 *
 * This test case builds upon [BubbleExitTestCases] by adding a verification
 * to ensure the application window itself is also gone at the end of the transition.
 */
    @Test
    fun bubbleLayerWasVisibleThenDisappear() {
        layersTraceSubject
            .isVisible(BUBBLE)
            .then()
            .isInvisible(BUBBLE)
            .forAllEntries()
    }
interface BubbleDismissesTestCases : BubbleExitTestCases {

    /**
     * Verifies bubble app window is gone at the end of the transition.
+72 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.wm.shell.flicker.bubbles.testcase

import android.tools.traces.component.ComponentNameMatcher.Companion.BUBBLE
import com.android.wm.shell.flicker.bubbles.utils.BubbleFlickerSubjects
import org.junit.Test

/**
 * Verifies the exit transition of a bubble.
 *
 * Verifies a bubble's window and layer correctly transition from a visible to an invisible state
 * at the end of a trace.
 */
interface BubbleExitTestCases : BubbleFlickerSubjects {

    /**
     * Verifies [BUBBLE] window is gone at the end of the transition.
     */
    @Test
    fun bubbleWindowIsGoneAtEnd() {
        wmStateSubjectAtEnd.notContains(BUBBLE)
    }

    /**
     * Verifies [BUBBLE] layer is gone at the end of the transition.
     */
    @Test
    fun bubbleLayerIsGoneAtEnd() {
        layerTraceEntrySubjectAtEnd.notContains(BUBBLE)
    }

    /**
     * Verifies [BUBBLE] window was visible then disappears.
     */
    @Test
    fun bubbleWindowWasVisibleThenDisappear() {
        wmTraceSubject
            .isAboveAppWindowVisible(BUBBLE)
            .then()
            // Use #isNonAppWindowInvisible here because the BUBBLE window may have been removed
            // from WM hierarchy.
            .isNonAppWindowInvisible(BUBBLE)
            .forAllEntries()
    }

    /**
     * Verifies [BUBBLE] layer was visible then disappears.
     */
    @Test
    fun bubbleLayerWasVisibleThenDisappear() {
        layersTraceSubject
            .isVisible(BUBBLE)
            .then()
            .isInvisible(BUBBLE)
            .forAllEntries()
    }
}
 No newline at end of file
Loading