oldpride
oldpride

Reputation: 975

In Appium Python, how to make double-tap faster?

I am using Appium Python to send double-tap (also known as double-click). I tried the following 3 codes. They sometimes work but sometimes not.

action = TouchAction(driver)
action.tap(x=x, y=y).wait(10).tap(x=x, y=y).perform() # 1
action.tap(x=x, y=y).tap(x=x, y=y).perform()          # 2
action.tap(x=x, y=y, count=2).perform()               # 3

I looked into Appium server log.

When they didn't work, the two taps had too much time in between, even if I set 0 wait between the 2 taps. Below I saw 0.9 second between 2 taps.

    2023-01-01 00:45:15:379 [W3C (0e33c728)] Calling AppiumDriver.performTouch() with args: [[{"action":"tap","options":{"x":551.5,"y":1107,"count":1}},{"action":"tap","options":{"x":551.5,"y":1107,"count":1}}],"0e33c728-8dc6-49b5-82dd-567c1508a410"]
    2023-01-01 00:45:15:382 [WD Proxy] Proxying [POST /appium/tap] to [POST http://127.0.0.1:8200/wd/hub/session/448df8e5-309e-4448-bf69-dbfd36602b77/appium/tap] with body: {"x":551.5,"y":1107,"undefined":null}
    2023-01-01 00:45:16:256 [WD Proxy] Got response with status 200: {"sessionId":"448df8e5-309e-4448-bf69-dbfd36602b77","value":null}
    2023-01-01 00:45:16:259 [WD Proxy] Proxying [POST /appium/tap] to [POST http://127.0.0.1:8200/wd/hub/session/448df8e5-309e-4448-bf69-dbfd36602b77/appium/tap] with body: {"x":551.5,"y":1107,"undefined":null}
    2023-01-01 00:45:16:931 [WD Proxy] Got response with status 200: {"sessionId":"448df8e5-309e-4448-bf69-dbfd36602b77","value":null}

When they worked, I saw the interval was 0.28 second.

Part of the delay was from my computer. I am using Android Wireless Debugging. I cannot do much about this.

There are at least 2 other things that I'd like to explore:

  1. is there a way to extend Android device's double-tap timer? To allow 0.9 second between two taps.
  2. is there a way that Appium TouchAction can send the 2nd action without waiting for the response from the 1st action?

I welcome other suggestions.

Thank you

Upvotes: 1

Views: 955

Answers (2)

oldpride
oldpride

Reputation: 975

This is what worked for me. It is a hack, but hopefully Appium dev can integrate it into future release.

in my program, call the new action name 'tap2'

action = TouchAction(driver)
action.tap2(x=x, y=y, wait=200).perform()

define the tap2 in site-packages/appium/webdriver/common/touch_action.py

def tap2(
        self,
        element: Optional['WebElement'] = None,
        x: Optional[int] = None,
        y: Optional[int] = None,
        wait: int = 200,
        count: int = 1,
    ) -> 'TouchAction':
        """Perform a tap action on the element

        Args:
            element: the element to tap
            x : x coordinate to tap, relative to the top left corner of the element.
            y : y coordinate. If y is used, x must also be set, and vice versa

        Returns:
            `TouchAction`: Self instance
        """
        opts = self._get_opts(element, x, y)
        opts['count'] = count
        self._add_action('tap2', opts)

        return self

added in appdata/Roaming/npm/node_modules/appium/node_modules/appium-android-driver/build/lib/commands/touch.js

case 'tap2':
  return await this.tap2(null, x, y, count);

added in appdata/Roaming/npm/node_modules/appium/node_modules/appium-uiautomator2-driver/build/lib/commands/element.js

commands.tap2 = async function (elementId = null, x = null, y = null, wait=200, count = 1) {
  let tianstack = new Error("tianstack");
  _logger.default.info(`tianstack: ${tianstack.stack}`);

  const areCoordinatesDefined = _appiumSupport.util.hasValue(x) && _appiumSupport.util.hasValue(y);

  if (!areCoordinatesDefined) {
    throw new Error(`both absolute coordinates should be defined`);
  }

  Promise.all([
    new Promise(resolve => setTimeout(resolve, wait))
      .then(() => this.uiautomator2.jwproxy.command(`/appium/tap`, 'POST', {
        x,
        y,
        [_appiumBaseDriver.W3C_ELEMENT_KEY]: elementId
      })),
    this.uiautomator2.jwproxy.command(`/appium/tap`, 'POST', {
      x,
      y,
      [_appiumBaseDriver.W3C_ELEMENT_KEY]: elementId
    })
  ]).catch((error) => {
    _logger.default.info / (`Failed during tap2: ${error}`)
  });;
};

This last step allowed me to fire the 1st action without waiting for the response coming back from the 2nd action. This way I can control the timing of the two taps without WIFI's interference.

Upvotes: 2

Dima Berezovskyi
Dima Berezovskyi

Reputation: 131

call 2 times

action.press(x,y).wait(50).release().perform()


OR

action.press(x,y).wait(50).release().perform().press(x,y).release().perform()


Last one MultiAction

Usage:
            | a1 = TouchAction(driver)
            | a1.press(el1).move_to(el2).release()
            | a2 = TouchAction(driver)
            | a2.press(el2).move_to(el1).release()
            | MultiAction(driver).add(a1, a2)

        action0 = TouchAction().tap(el)
        action1 = TouchAction().tap(el)
        MultiAction(self.driver).add(action0, action)

Tests here
Source code here

Upvotes: 0

Related Questions