Loading libs/WindowManager/Shell/tests/e2e/bubbles/flicker-explicit/src/com/android/wm/shell/flicker/bubbles/DismissExpandedBubbleViaBubbleViewTest.kt +5 −65 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 = { Loading Loading @@ -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() { Loading libs/WindowManager/Shell/tests/e2e/bubbles/flicker-explicit/src/com/android/wm/shell/flicker/bubbles/ScrollableBubbleAppTest.kt 0 → 100644 +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 libs/WindowManager/Shell/tests/e2e/bubbles/flicker-explicit/src/com/android/wm/shell/flicker/bubbles/testcase/DismissExpandedBubbleTestCases.kt 0 → 100644 +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 libs/WindowManager/Shell/tests/e2e/bubbles/flicker-explicit/src/com/android/wm/shell/flicker/bubbles/utils/BubbleFlickerTestHelper.kt +5 −1 Original line number Diff line number Diff line Loading @@ -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()) Loading tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ScrollToFinishHelper.kt 0 → 100644 +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
libs/WindowManager/Shell/tests/e2e/bubbles/flicker-explicit/src/com/android/wm/shell/flicker/bubbles/DismissExpandedBubbleViaBubbleViewTest.kt +5 −65 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 = { Loading Loading @@ -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() { Loading
libs/WindowManager/Shell/tests/e2e/bubbles/flicker-explicit/src/com/android/wm/shell/flicker/bubbles/ScrollableBubbleAppTest.kt 0 → 100644 +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
libs/WindowManager/Shell/tests/e2e/bubbles/flicker-explicit/src/com/android/wm/shell/flicker/bubbles/testcase/DismissExpandedBubbleTestCases.kt 0 → 100644 +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
libs/WindowManager/Shell/tests/e2e/bubbles/flicker-explicit/src/com/android/wm/shell/flicker/bubbles/utils/BubbleFlickerTestHelper.kt +5 −1 Original line number Diff line number Diff line Loading @@ -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()) Loading
tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ScrollToFinishHelper.kt 0 → 100644 +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