How to perform a three finger tap?

Appium v2.5.1
[email protected]
Appium-Python-Client==2.11.1

Hi, how do I perform a three finger tap with appium? I want to perform the three finger tap 3 times.

My current code looks like this:
# Set up coordinates for the taps if needed, or find an element to tap on
x1, y1 = 850, 450 # Coordinates for first finger
x2, y2 = 900, 450 # Coordinates for second finger
x3, y3 = 950, 450 # Coordinates for third finger

    # Create TouchAction instances for each tap
    tap1 = TouchAction(self.driver).tap(x=x1, y=y1)
    tap2 = TouchAction(self.driver).tap(x=x2, y=y2)
    tap3 = TouchAction(self.driver).tap(x=x3, y=y3)

    # Create a MultiAction object
    multi_touch = MultiAction(self.driver)
    multi_touch.add(tap1, tap2, tap3)

    # Perform the multi-touch action (the triple tap)
    multi_touch.perform()
    multi_touch.perform()
    multi_touch.perform()

However, I’m encountering this error:

E       Stacktrace:
E       io.appium.uiautomator2.common.exceptions.UiAutomator2Exception: Cannot invoke method public boolean androidx.test.uiautomator.InteractionController.performMultiPointerGesture(android.view.MotionEvent$PointerCoords[][]) on object androidx.test.uiautomator.InteractionController@f87e653 with parameters [[[Landroid.view.MotionEvent$PointerCoords;@97eb642]
E               at io.appium.uiautomator2.utils.ReflectionUtils.invoke(ReflectionUtils.java:85)
E               at io.appium.uiautomator2.core.InteractionController.doPerformMultiPointerGesture(InteractionController.java:127)
E               at io.appium.uiautomator2.core.InteractionController.access$400(InteractionController.java:29)
E               at io.appium.uiautomator2.core.InteractionController$5.run(InteractionController.java:142)
E               at android.app.UiAutomation.executeAndWaitForEvent(UiAutomation.java:920)
E               at io.appium.uiautomator2.core.EventRegister.runAndRegisterScrollEvents(EventRegister.java:40)
E               at io.appium.uiautomator2.core.EventRegister.runAndRegisterScrollEvents(EventRegister.java:81)
E               at io.appium.uiautomator2.core.InteractionController.performMultiPointerGesture(InteractionController.java:139)
E               at io.appium.uiautomator2.handler.MultiPointerGesture.safeHandle(MultiPointerGesture.java:44)
E               at io.appium.uiautomator2.handler.request.SafeRequestHandler.handle(SafeRequestHandler.java:59)
E               at io.appium.uiautomator2.server.AppiumServlet.handleRequest(AppiumServlet.java:277)
E               at io.appium.uiautomator2.server.AppiumServlet.handleHttpRequest(AppiumServlet.java:271)
E               at io.appium.uiautomator2.http.ServerHandler.channelRead(ServerHandler.java:68)
E               at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
E               at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
E               at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
E               at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
E               at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
E               at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
E               at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
E               at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:435)
E               at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
E               at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
E               at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:250)
E               at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
E               at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
E               at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
E               at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:266)
E               at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
E               at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
E               at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
E               at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1294)
E               at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
E               at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
E               at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:911)
E               at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
E               at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:611)
E               at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:552)
E               at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:466)
E               at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438)
E               at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:140)
E               at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
E               at java.lang.Thread.run(Thread.java:1012)
E       Caused by: java.lang.reflect.InvocationTargetException
E               at java.lang.reflect.Method.invoke(Native Method)
E               at io.appium.uiautomator2.utils.ReflectionUtils.invoke(ReflectionUtils.java:83)
E               ... 42 more
E       Caused by: java.lang.IllegalArgumentException: Must provide coordinates for at least 2 pointers
E               at androidx.test.uiautomator.InteractionController.performMultiPointerGesture(InteractionController.java:724)```

It is worth noting, that I don’t see any errors when I run multi_touch.perform() just once.

Touch Actions are deprecated

Any example code snippets? I’ve tried updating my code to use PointerInput, but still have issues witha triple touch tap…

    # Set up the pointer input devices (one for each finger)
    finger1 = PointerInput(PointerInput.POINTER_TOUCH, "finger1")
    finger2 = PointerInput(PointerInput.POINTER_TOUCH, "finger2")
    finger3 = PointerInput(PointerInput.POINTER_TOUCH, "finger3")

    # Coordinates for each finger tap
    x1, y1 = 935, 450
    x2, y2 = 1135, 470
    x3, y3 = 1335, 480

    for _ in range(3):  # Repeat the gesture three times
        action = ActionBuilder(self.driver)

        # Create actions for each finger
        action.add_pointer_input(
            finger1, finger1.create_pointer_move(x=x1, y=y1, duration=0)
        )
        action.add_pointer_input(
            finger1, finger1.create_pointer_down(PointerInput.POINTER_TOUCH)
        )
        action.add_pointer_input(
            finger1, finger1.create_pointer_up(PointerInput.POINTER_TOUCH)
        )

        action.add_pointer_input(
            finger2, finger2.create_pointer_move(x=x2, y=y2, duration=0)
        )
        action.add_pointer_input(
            finger2, finger2.create_pointer_down(PointerInput.POINTER_TOUCH)
        )
        action.add_pointer_input(
            finger2, finger2.create_pointer_up(PointerInput.POINTER_TOUCH)
        )

        action.add_pointer_input(
            finger3, finger3.create_pointer_move(x=x3, y=y3, duration=0)
        )
        action.add_pointer_input(
            finger3, finger3.create_pointer_down(PointerInput.POINTER_TOUCH)
        )
        action.add_pointer_input(
            finger3, finger3.create_pointer_up(PointerInput.POINTER_TOUCH)
        )

        # Perform the actions
        action.perform()
        print("performing triple tap")
        sleep(0.1)  # Wait for a short duration between gestures

I think you want to use ‘tap’ method here:

1 Like

Thank you!, I was able to get multi-touch working with ‘tap’.

   coords = [(935, 450), (1135, 470), (1335, 480)]

    for _ in range(3):
        self.page_utils.tap_location(coords)
        print("Performed triple tap.")
1 Like