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

Commit 204c18ff authored by Gavin Williams's avatar Gavin Williams Committed by Android (Google) Code Review
Browse files

Merge "Autoclick: Create test helper functions" into main

parents feee8f8a bfcd3c33
Loading
Loading
Loading
Loading
+4 −76
Original line number Diff line number Diff line
@@ -32,17 +32,10 @@ import android.widget.Button
import android.widget.LinearLayout
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By
import androidx.test.uiautomator.BySelector
import androidx.test.uiautomator.Configurator
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiObject2
import androidx.test.uiautomator.Until
import com.android.compatibility.common.util.PollingCheck
import com.android.compatibility.common.util.PollingCheck.waitFor
import com.android.compatibility.common.util.SettingsStateChangerRule
import com.android.server.accessibility.Flags
import kotlin.time.Duration.Companion.seconds
import org.junit.AfterClass
import org.junit.Before
import org.junit.BeforeClass
@@ -92,10 +85,6 @@ class AutoclickClickTypeTests {
        }
    }

    private fun findObject(selector: BySelector): UiObject2 {
        return uiDevice.wait(Until.findObject(selector), FIND_OBJECT_TIMEOUT.inWholeMilliseconds)
    }

    private fun moveMouseToView(view: View) {
        val xOnScreen = view.locationOnScreen[0]
        val yOnScreen = view.locationOnScreen[1]
@@ -104,57 +93,9 @@ class AutoclickClickTypeTests {
        desktopMouseTestRule.move(DEFAULT_DISPLAY, centerX, centerY)
    }

    // The panel is considered open when more than one click type button is visible.
    private fun isAutoclickPanelOpen(): Boolean {
        val clickTypeButtonGroupContainer = findObject(
            By.res(CLICK_TYPE_BUTTON_GROUP_ID)
        )
        return clickTypeButtonGroupContainer.childCount > 1
    }

    private fun changeClickType(clickTypeResourceId: String) {
        // First move the cursor to the edge of the screen so the next move will trigger an
        // autoclick.
        desktopMouseTestRule.move(DEFAULT_DISPLAY, targetXPx = 0, targetYPx = 0)

        if (!isAutoclickPanelOpen()) {
            // The click type button group starts closed so click it to open the panel.
            val clickTypeButtonGroup = findObject(
                By.res(CLICK_TYPE_BUTTON_GROUP_ID)
            )
            desktopMouseTestRule.move(
                DEFAULT_DISPLAY,
                clickTypeButtonGroup.visibleCenter.x,
                clickTypeButtonGroup.visibleCenter.y
            )

            // Wait for the panel to fully open before attempting to select a click type.
            waitAndAssert {
                isAutoclickPanelOpen()
            }
        }

        desktopMouseTestRule.move(DEFAULT_DISPLAY, targetXPx = 0, targetYPx = 0)
        val targetClickTypeButton = findObject(By.res(clickTypeResourceId))
        desktopMouseTestRule.move(
            DEFAULT_DISPLAY,
            targetClickTypeButton.visibleCenter.x,
            targetClickTypeButton.visibleCenter.y
        )

        // Wait for the panel to close as the signal that the click type was selected.
        waitAndAssert {
            !isAutoclickPanelOpen()
        }
    }

    private fun waitAndAssert(condition: PollingCheck.PollingCheckCondition) {
        waitFor(FIND_OBJECT_TIMEOUT.inWholeMilliseconds, condition)
    }

    @Test
    fun performLeftClick_buttonReflectsClickType() {
        changeClickType(LEFT_CLICK_BUTTON_LAYOUT_ID)
        changeClickType(uiDevice, desktopMouseTestRule, LEFT_CLICK_BUTTON_LAYOUT_ID)
        moveMouseToView(testClickButton)

        waitAndAssert {
@@ -164,7 +105,7 @@ class AutoclickClickTypeTests {

    @Test
    fun performDoubleClick_buttonReflectsClickType() {
        changeClickType(DOUBLE_CLICK_BUTTON_LAYOUT_ID)
        changeClickType(uiDevice, desktopMouseTestRule, DOUBLE_CLICK_BUTTON_LAYOUT_ID)
        moveMouseToView(testClickButton)

        waitAndAssert {
@@ -174,7 +115,7 @@ class AutoclickClickTypeTests {

    @Test
    fun performRightClick_buttonReflectsClickType() {
        changeClickType(RIGHT_CLICK_BUTTON_LAYOUT_ID)
        changeClickType(uiDevice, desktopMouseTestRule, RIGHT_CLICK_BUTTON_LAYOUT_ID)
        moveMouseToView(testClickButton)

        waitAndAssert {
@@ -184,7 +125,7 @@ class AutoclickClickTypeTests {

    @Test
    fun performLongPress_buttonReflectsClickType() {
        changeClickType(LONG_PRESS_BUTTON_LAYOUT_ID)
        changeClickType(uiDevice, desktopMouseTestRule, LONG_PRESS_BUTTON_LAYOUT_ID)
        moveMouseToView(testClickButton)

        waitAndAssert {
@@ -243,7 +184,6 @@ class AutoclickClickTypeTests {
    }

    private companion object {
        private val FIND_OBJECT_TIMEOUT = 5.seconds
        private val TEST_BUTTON_ID = View.generateViewId()

        // Button text.
@@ -252,18 +192,6 @@ class AutoclickClickTypeTests {
        private val RIGHT_CLICK_TEXT = "Right Clicked!"
        private val LONG_PRESS_TEXT = "Long Press Clicked!"

        // Autoclick panel resource ids.
        private val LEFT_CLICK_BUTTON_LAYOUT_ID =
            "android:id/accessibility_autoclick_left_click_layout"
        private val LONG_PRESS_BUTTON_LAYOUT_ID =
            "android:id/accessibility_autoclick_long_press_layout"
        private val RIGHT_CLICK_BUTTON_LAYOUT_ID =
            "android:id/accessibility_autoclick_right_click_layout"
        private val DOUBLE_CLICK_BUTTON_LAYOUT_ID =
            "android:id/accessibility_autoclick_double_click_layout"
        private val CLICK_TYPE_BUTTON_GROUP_ID =
            "android:id/accessibility_autoclick_click_type_button_group_container"

        @BeforeClass
        @JvmStatic
        fun setupBeforeClass() {
+9 −64
Original line number Diff line number Diff line
@@ -17,26 +17,18 @@ package com.android.server.accessibility.integration

import android.app.Instrumentation
import android.app.UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES
import android.content.Context
import android.graphics.Point
import android.platform.test.annotations.RequiresFlagsEnabled
import android.platform.test.flag.junit.CheckFlagsRule
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.provider.Settings
import android.view.Display.DEFAULT_DISPLAY
import android.view.WindowManager
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By
import androidx.test.uiautomator.BySelector
import androidx.test.uiautomator.Configurator
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiObject2
import androidx.test.uiautomator.Until
import com.android.compatibility.common.util.PollingCheck
import com.android.compatibility.common.util.PollingCheck.waitFor
import com.android.compatibility.common.util.SettingsStateChangerRule
import com.android.server.accessibility.Flags
import kotlin.time.Duration.Companion.seconds
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
@@ -68,8 +60,6 @@ class AutoclickPanelTests {
    val desktopMouseTestRule = DesktopMouseTestRule()

    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
    private val context: Context = instrumentation.context
    private val windowManager: WindowManager = context.getSystemService(WindowManager::class.java)

    private lateinit var uiDevice: UiDevice

@@ -82,50 +72,22 @@ class AutoclickPanelTests {
        desktopMouseTestRule.move(DEFAULT_DISPLAY, 0, 0)
    }

    private fun findObject(selector: BySelector): UiObject2 {
        return uiDevice.wait(Until.findObject(selector), FIND_OBJECT_TIMEOUT.inWholeMilliseconds)
    }

    private fun clickPauseButton() {
        findObject(
            uiDevice,
            By.res(PAUSE_BUTTON_LAYOUT_ID)
        ).click()
    }

    private fun clickClickTypeButton(resourceId: String) {
        findObject(By.res(resourceId)).click()
        // The delay is needed to let the animation of the panel opening/closing complete before
        // querying for the next element.
        uiDevice.waitForIdle(DELAY_FOR_ANIMATION.inWholeMilliseconds)
    }

    private fun clickLongPressButton() {

        if (!isAutoclickPanelOpen()) {
            clickClickTypeButton(CLICK_TYPE_BUTTON_GROUP_ID)

            // Wait for the panel to fully open before attempting to select a click type.
            waitAndAssert {
                isAutoclickPanelOpen()
            }
        }

        clickClickTypeButton(LONG_PRESS_BUTTON_LAYOUT_ID)

        // Wait for the panel to close as the signal that the click type was selected.
        waitAndAssert {
            !isAutoclickPanelOpen()
        }
    }

    private fun clickPositionButton() {
        clickClickTypeButton(POSITION_BUTTON_LAYOUT_ID)
        findObject(uiDevice, By.res(POSITION_BUTTON_LAYOUT_ID)).click()
    }

    // The panel is considered open when every click type button is showing.
    private fun isAutoclickPanelOpen(): Boolean {
        val PANEL_OPEN_CLICK_TYPE_COUNT = 6
        val clickTypeButtonGroupContainer = findObject(
            uiDevice,
            By.res(CLICK_TYPE_BUTTON_GROUP_ID)
        )
        return clickTypeButtonGroupContainer.childCount == PANEL_OPEN_CLICK_TYPE_COUNT
@@ -133,19 +95,17 @@ class AutoclickPanelTests {

    private fun getAutoclickPanelPosition(): Point {
        return findObject(
            uiDevice,
            By.res(AUTOCLICK_PANEL_ID)
        ).visibleCenter
    }

    private fun waitAndAssert(condition: PollingCheck.PollingCheckCondition) {
        waitFor(FIND_OBJECT_TIMEOUT.inWholeMilliseconds, condition)
    }

    @Test
    fun togglePauseResumeButton_contentDescriptionReflectsTheState() {
        // Expect the panel to start with the pause button.
        assertNotNull(
            findObject(
                uiDevice,
                By.res(PAUSE_BUTTON_IMAGE_ID).desc("Pause")
            )
        )
@@ -154,6 +114,7 @@ class AutoclickPanelTests {
        clickPauseButton()
        assertNotNull(
            findObject(
                uiDevice,
                By.res(PAUSE_BUTTON_IMAGE_ID).desc("Resume")
            )
        )
@@ -162,6 +123,7 @@ class AutoclickPanelTests {
        clickPauseButton()
        assertNotNull(
            findObject(
                uiDevice,
                By.res(PAUSE_BUTTON_IMAGE_ID).desc("Pause")
            )
        )
@@ -171,9 +133,9 @@ class AutoclickPanelTests {
    fun switchClickType_LongPressClickTypeIsSelected() {
        // Click the long press button then verify only the long press button is visible with all
        // other click type buttons hidden.
        clickLongPressButton()
        changeClickType(uiDevice, desktopMouseTestRule, LONG_PRESS_BUTTON_LAYOUT_ID)
        assertNotNull(
            findObject(By.res(LONG_PRESS_BUTTON_LAYOUT_ID))
            findObject(uiDevice, By.res(LONG_PRESS_BUTTON_LAYOUT_ID))
        )
        assertFalse(isAutoclickPanelOpen())
    }
@@ -210,21 +172,4 @@ class AutoclickPanelTests {
        val fifthPosition = getAutoclickPanelPosition()
        assertEquals(startingPosition, fifthPosition)
    }

    private companion object {
        private val FIND_OBJECT_TIMEOUT = 30.seconds
        private val DELAY_FOR_ANIMATION = 2.seconds

        // Resource ids
        private val PAUSE_BUTTON_LAYOUT_ID = "android:id/accessibility_autoclick_pause_layout"
        private val PAUSE_BUTTON_IMAGE_ID = "android:id/accessibility_autoclick_pause_button"
        private val LEFT_CLICK_BUTTON_LAYOUT_ID =
            "android:id/accessibility_autoclick_left_click_layout"
        private val LONG_PRESS_BUTTON_LAYOUT_ID =
            "android:id/accessibility_autoclick_long_press_layout"
        private val POSITION_BUTTON_LAYOUT_ID = "android:id/accessibility_autoclick_position_layout"
        private val CLICK_TYPE_BUTTON_GROUP_ID =
            "android:id/accessibility_autoclick_click_type_button_group_container"
        private val AUTOCLICK_PANEL_ID = "android:id/accessibility_autoclick_type_panel"
    }
}
+101 −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.accessibility.integration

import android.view.Display.DEFAULT_DISPLAY
import androidx.test.uiautomator.By
import androidx.test.uiautomator.BySelector
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiObject2
import androidx.test.uiautomator.Until
import com.android.compatibility.common.util.PollingCheck
import com.android.compatibility.common.util.PollingCheck.waitFor
import kotlin.time.Duration.Companion.seconds
import platform.test.desktop.DesktopMouseTestRule

private val FIND_OBJECT_TIMEOUT = 5.seconds

// Autoclick panel resource ids.
val LEFT_CLICK_BUTTON_LAYOUT_ID =
    "android:id/accessibility_autoclick_left_click_layout"
val LONG_PRESS_BUTTON_LAYOUT_ID =
    "android:id/accessibility_autoclick_long_press_layout"
val RIGHT_CLICK_BUTTON_LAYOUT_ID =
    "android:id/accessibility_autoclick_right_click_layout"
val DOUBLE_CLICK_BUTTON_LAYOUT_ID =
    "android:id/accessibility_autoclick_double_click_layout"
val CLICK_TYPE_BUTTON_GROUP_ID =
    "android:id/accessibility_autoclick_click_type_button_group_container"
val PAUSE_BUTTON_LAYOUT_ID = "android:id/accessibility_autoclick_pause_layout"
val PAUSE_BUTTON_IMAGE_ID = "android:id/accessibility_autoclick_pause_button"
val POSITION_BUTTON_LAYOUT_ID = "android:id/accessibility_autoclick_position_layout"
val AUTOCLICK_PANEL_ID = "android:id/accessibility_autoclick_type_panel"

fun findObject(uiDevice: UiDevice, selector: BySelector): UiObject2 {
    return uiDevice.wait(Until.findObject(selector), FIND_OBJECT_TIMEOUT.inWholeMilliseconds)
}

fun waitAndAssert(condition: PollingCheck.PollingCheckCondition) {
    waitFor(FIND_OBJECT_TIMEOUT.inWholeMilliseconds, condition)
}

// The panel is considered open when more than one click type button is visible.
fun isAutoclickPanelOpen(uiDevice: UiDevice): Boolean {
    val clickTypeButtonGroupContainer = findObject(
        uiDevice, By.res(CLICK_TYPE_BUTTON_GROUP_ID)
    )
    return clickTypeButtonGroupContainer.childCount > 1
}

fun changeClickType(
    uiDevice: UiDevice,
    desktopMouseTestRule: DesktopMouseTestRule,
    clickTypeResourceId: String
) {
    // First move the cursor to the edge of the screen so the next move will trigger an
    // autoclick.
    desktopMouseTestRule.move(DEFAULT_DISPLAY, targetXPx = 0, targetYPx = 0)

    if (!isAutoclickPanelOpen(uiDevice)) {
        // The click type button group starts closed so click it to open the panel.
        val clickTypeButtonGroup = findObject(
            uiDevice, By.res(CLICK_TYPE_BUTTON_GROUP_ID)
        )
        desktopMouseTestRule.move(
            DEFAULT_DISPLAY,
            clickTypeButtonGroup.visibleCenter.x,
            clickTypeButtonGroup.visibleCenter.y
        )

        // Wait for the panel to fully open before attempting to select a click type.
        waitAndAssert {
            isAutoclickPanelOpen(uiDevice)
        }
    }

    desktopMouseTestRule.move(DEFAULT_DISPLAY, targetXPx = 0, targetYPx = 0)
    val targetClickTypeButton = findObject(uiDevice, By.res(clickTypeResourceId))
    desktopMouseTestRule.move(
        DEFAULT_DISPLAY,
        targetClickTypeButton.visibleCenter.x,
        targetClickTypeButton.visibleCenter.y
    )

    // Wait for the panel to close as the signal that the click type was selected.
    waitAndAssert {
        !isAutoclickPanelOpen(uiDevice)
    }
}