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

Commit 77d7df1c authored by Charles Chen's avatar Charles Chen Committed by Android (Google) Code Review
Browse files

Merge "Verify if bubble app is touchable" into main

parents 727358b4 0e2e99ac
Loading
Loading
Loading
Loading
+5 −65
Original line number Diff line number Diff line
@@ -17,14 +17,13 @@
package com.android.wm.shell.flicker.bubbles

import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import android.platform.test.annotations.RequiresFlagsEnabled
import android.tools.NavBar
import android.tools.traces.component.ComponentNameMatcher.Companion.BUBBLE
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.Flags
import com.android.wm.shell.Utils
import com.android.wm.shell.flicker.bubbles.testcase.BubbleAppBecomesNotExpandedTestCases
import com.android.wm.shell.flicker.bubbles.testcase.DismissExpandedBubbleTestCases
import com.android.wm.shell.flicker.bubbles.utils.ApplyPerParameterRule
import com.android.wm.shell.flicker.bubbles.utils.FlickerPropertyInitializer
import com.android.wm.shell.flicker.bubbles.utils.RecordTraceWithTransitionRule
@@ -55,18 +54,15 @@ import org.junit.runners.MethodSorters
 * ```
 * Verified tests:
 * - [BubbleFlickerTestBase]
 * - [BubbleAppBecomesNotExpandedTestCases]
 * - [BUBBLE] is visible and then disappear
 * - [DismissExpandedBubbleTestCases]
 */
@FlakyTest(bugId = 427850786)
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_CREATE_ANY_BUBBLE)
@RequiresDevice
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Presubmit
class DismissExpandedBubbleViaBubbleViewTest(navBar: NavBar) :
    BubbleFlickerTestBase(),
    BubbleAppBecomesNotExpandedTestCases
{
class DismissExpandedBubbleViaBubbleViewTest(navBar: NavBar) : BubbleFlickerTestBase(),
    DismissExpandedBubbleTestCases {
    companion object : FlickerPropertyInitializer() {
        private val recordTraceWithTransitionRule = RecordTraceWithTransitionRule(
            setUpBeforeTransition = {
@@ -94,62 +90,6 @@ class DismissExpandedBubbleViaBubbleViewTest(navBar: NavBar) :
        super.setUp()
    }

// region Bubble stack related tests

    /**
     * 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 disappear.
     */
    @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 disappear.
     */
    @Test
    fun bubbleLayerWasVisibleThenDisappear() {
        layersTraceSubject
            .isVisible(BUBBLE)
            .then()
            .isInvisible(BUBBLE)
            .forAllEntries()
    }

// endregion

// region bubble app related tests

    /**
     * Verifies bubble app window is gone at the end of the transition.
     */
    @Test
    fun appWindowIsGoneAtEnd() {
        wmStateSubjectAtEnd.notContains(testApp)
    }

    @FlakyTest(bugId = 396020056)
    @Test
    override fun appLayerBecomesInvisible() {
+96 −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.ScrollToFinishHelper
import com.android.wm.shell.Flags
import com.android.wm.shell.Utils
import com.android.wm.shell.flicker.bubbles.testcase.DismissExpandedBubbleTestCases
import com.android.wm.shell.flicker.bubbles.utils.ApplyPerParameterRule
import com.android.wm.shell.flicker.bubbles.utils.FlickerPropertyInitializer
import com.android.wm.shell.flicker.bubbles.utils.RecordTraceWithTransitionRule
import com.android.wm.shell.flicker.bubbles.utils.launchBubbleViaBubbleMenu
import com.android.wm.shell.flicker.bubbles.utils.waitAndVerifyBubbleGone
import org.junit.FixMethodOrder
import org.junit.Rule
import org.junit.runners.MethodSorters

/**
 * Verifies that the content within a bubble can be scrolled and that its UI elements can be clicked.
 *
 * This test validates user interaction by launching a bubble that displays an activity with a
 * [android.widget.ScrollView]. The scrollable content is intentionally long enough to not be
 * fully visible, with a "finish" button located at the very bottom.
 *
 * The test succeeds if it can programmatically scroll to the button and click it, which in
 * turn dismisses the bubble app. This confirms that both scrolling and touch events are
 * processed correctly within the bubble app.
 *
 * To run this test: `atest WMShellExplicitFlickerTestsBubbles:ScrollableBubbleAppTest`
 *
 * Pre-steps:
 * ```
 *     Launch [testApp] into bubble
 * ```
 *
 * Actions:
 * ```
 *     Scroll the [testApp] until find the finish button
 *     Click the finish button to finish the bubble app
 * ```
 * Verified tests:
 * - [BubbleFlickerTestBase]
 * - [DismissExpandedBubbleTestCases]
 */
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_CREATE_ANY_BUBBLE)
@RequiresDevice
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Presubmit
class ScrollableBubbleAppTest(navBar: NavBar) : BubbleFlickerTestBase(),
    DismissExpandedBubbleTestCases {

    companion object : FlickerPropertyInitializer() {
        private val recordTraceWithTransitionRule = RecordTraceWithTransitionRule(
            setUpBeforeTransition = { launchBubbleViaBubbleMenu(testApp, tapl, wmHelper) },
            transition = {
                testApp.scrollToFinish()
                waitAndVerifyBubbleGone(wmHelper)
            },
            tearDownAfterTransition = { testApp.exit() }
        )

        override val testApp
            get() = ScrollToFinishHelper(instrumentation)
    }

    @get:Rule
    val setUpRule = ApplyPerParameterRule(
        Utils.testSetupRule(navBar).around(recordTraceWithTransitionRule),
        params = arrayOf(navBar)
    )

    // This is necessary or the test will use the testApp from BubbleFlickerTestBase.
    override val testApp
        get() = ScrollableBubbleAppTest.testApp

    override val traceDataReader
        get() = recordTraceWithTransitionRule.reader
}
 No newline at end of file
+86 −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 org.junit.Test

/**
 * Verifies [testApp] is dismissed, and bubble window (represented as expanded bubble or bubble bar)
 * is also dismissed.
 *
 * - [BubbleAppBecomesNotExpandedTestCases]
 * - [BUBBLE] is visible and then disappear
 */
interface DismissExpandedBubbleTestCases : BubbleAppBecomesNotExpandedTestCases {

// region Bubble related tests

    /**
     * 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 disappear.
     */
    @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 disappear.
     */
    @Test
    fun bubbleLayerWasVisibleThenDisappear() {
        layersTraceSubject
            .isVisible(BUBBLE)
            .then()
            .isInvisible(BUBBLE)
            .forAllEntries()
    }

// endregion

// region bubble app related tests

    /**
     * Verifies bubble app window is gone at the end of the transition.
     */
    @Test
    fun appWindowIsGoneAtEnd() {
        wmStateSubjectAtEnd.notContains(testApp)
    }
}
 No newline at end of file
+5 −1
Original line number Diff line number Diff line
@@ -210,8 +210,12 @@ fun dismissBubbleAppViaBubbleView(uiDevice: UiDevice, wmHelper: WindowManagerSta
    uiDevice.bubbleIcon?.run {
        drag(Point(uiDevice.displayWidth / 2, uiDevice.displayHeight), 1000)
    }
}

    // Wait for bubble gone.
/**
 * Waits and verifies the bubble (represented as bubble icon or bubble bar) is gone.
 */
fun waitAndVerifyBubbleGone(wmHelper: WindowManagerStateHelper) {
    wmHelper
        .StateSyncBuilder()
        .add(ConditionsFactory.isWMStateComplete())
+59 −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.server.wm.flicker.helpers

import android.app.Instrumentation
import android.platform.uiautomatorhelpers.scrollUntilFound
import android.tools.device.apphelpers.StandardAppHelper
import android.tools.helpers.FIND_TIMEOUT
import android.tools.traces.component.ComponentNameMatcher
import android.tools.traces.parsers.toFlickerComponent
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.testapp.ActivityOptions

/**
 * The helper to interact with `ScrollToFinishActivity`
 */
class ScrollToFinishHelper
@JvmOverloads
constructor(
    instr: Instrumentation,
    launcherName: String = ActivityOptions.ScrollToFinish.LABEL,
    component: ComponentNameMatcher = ActivityOptions.ScrollToFinish.COMPONENT.toFlickerComponent()
) : StandardAppHelper(instr, launcherName, component) {

    /**
     * Scrolls until the finish button is found and clicks the button.
     */
    fun scrollToFinish() {
        val rootActivityLayout = uiDevice.wait(
            Until.findObject(By.res(packageName, RES_ID_ROOT_ACTIVITY_LAYOUT)),
            FIND_TIMEOUT
        ) ?: error("Unable to find $RES_ID_ROOT_ACTIVITY_LAYOUT.")

        val finishButton = rootActivityLayout.scrollUntilFound(
            By.res(packageName, RES_ID_FINISH_BUTTON)
        ) ?: error("Unable to find $RES_ID_FINISH_BUTTON")
        finishButton.click()
    }

    companion object {
        private const val RES_ID_ROOT_ACTIVITY_LAYOUT = "root_activity_layout"
        private const val RES_ID_FINISH_BUTTON = "finish_button"
    }
}
 No newline at end of file
Loading