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

Commit 49f14a2d authored by Jeremy Sim's avatar Jeremy Sim
Browse files

Fix flaky flicker test

Fixes flakes in the test switchAppByDoubleTapDivider by changing the way click events are sent in doubleTapDividerToSwitch().

Previously, this test relied on SystemClock.sleep() and UiObject2.click() to create a double-click action; however, in a minority of cases, this was failing -- the component was registering two spaced-out single clicks instead of a double-click.

Using UiAutomation to inject the clicks at precise times fixes the problem.

Fixes: 397395900
Flag: EXEMPT test changes only
Test: A local test run of 200+ iterations ended with no flakes (previously was failing reliably by 30-50 iterations)
Change-Id: I9399a54129b31e2f9692ff6027a33fc868249170
parent e67ea9bc
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ abstract class SwitchAppByDoubleTapDividerBenchmark(override val flicker: Legacy
                )
            }
            transitions {
                SplitScreenUtils.doubleTapDividerToSwitch(device)
                SplitScreenUtils.doubleTapDividerToSwitch(device, instrumentation.uiAutomation)
                wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()

                waitForLayersToSwitch(wmHelper)
+1 −1
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) {

    @Test
    open fun switchAppByDoubleTapDivider() {
        SplitScreenUtils.doubleTapDividerToSwitch(device)
        SplitScreenUtils.doubleTapDividerToSwitch(device, instrumentation.uiAutomation)
        wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()

        waitForLayersToSwitch(wmHelper)
+34 −6
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.wm.shell.flicker.utils

import android.app.Instrumentation
import android.app.UiAutomation
import android.content.Context
import android.graphics.Point
import android.os.SystemClock
@@ -349,13 +350,40 @@ object SplitScreenUtils {
        )
    }

    fun doubleTapDividerToSwitch(device: UiDevice) {
    fun doubleTapDividerToSwitch(device: UiDevice, uiAutomation: UiAutomation) {
        val dividerBar = device.wait(Until.findObject(dividerBarSelector), TIMEOUT_MS)
        val interval =
            (ViewConfiguration.getDoubleTapTimeout() + ViewConfiguration.getDoubleTapMinTime()) / 2
        dividerBar.click()
        SystemClock.sleep(interval.toLong())
        dividerBar.click()
        val x = dividerBar.visibleCenter.x.toFloat()
        val y = dividerBar.visibleCenter.y.toFloat()

        // To send a double-tap action, we set a DOWN event, then UP, then DOWN, then, UP.
        val startTime = SystemClock.uptimeMillis()
        val timeOfFirstUp = startTime + ViewConfiguration.getTapTimeout()
        // Between the two taps, we wait an arbitrary amount of time between the min and max times
        // for a double-tap.
        val timeOfSecondDown = timeOfFirstUp + ViewConfiguration.getDoubleTapMinTime() +
                ((ViewConfiguration.getDoubleTapTimeout() -
                        ViewConfiguration.getDoubleTapMinTime()) / 4)
        val timeOfSecondUp = timeOfSecondDown + ViewConfiguration.getTapTimeout()

        val downEvent = MotionEvent.obtain(startTime, startTime, MotionEvent.ACTION_DOWN, x, y,
            0 /* metaState */)
        downEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN)
        uiAutomation.injectInputEvent(downEvent, true)

        val upEvent = MotionEvent.obtain(startTime, timeOfFirstUp, MotionEvent.ACTION_UP, x, y,
            0 /* metaState */)
        upEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN)
        uiAutomation.injectInputEvent(upEvent, true)

        val downEvent2 = MotionEvent.obtain(timeOfSecondDown, timeOfSecondDown,
            MotionEvent.ACTION_DOWN, x, y, 0 /* metaState */)
        downEvent2.setSource(InputDevice.SOURCE_TOUCHSCREEN)
        uiAutomation.injectInputEvent(downEvent2, true)

        val upEvent2 = MotionEvent.obtain(timeOfSecondDown, timeOfSecondUp, MotionEvent.ACTION_UP,
            x, y, 0 /* metaState */)
        upEvent2.setSource(InputDevice.SOURCE_TOUCHSCREEN)
        uiAutomation.injectInputEvent(upEvent2, true)
    }

    fun copyContentInSplit(