androidkotlinmotionevent

How to simulate zoom in or zoom out using InputManager?


I am trying to simulate a zoom-in gesture using InputManager with Kotlin. But I could not find a way to perform it. I must use InputManager, because I will use it on a rooted device to control other apps.

I could only make a single-finger drag, and the code is as follows. However, I want to make a zoom-in gesture which requires two figures touching down at the same time. Event the AI could not help. Please accept my sincere gratitude if anyone can help me.

        fun simulateSingleSwipe(
            startX: Int, startY: Int, endX: Int, endY: Int, duration: Long
        ) {
            try {
                // get InputManager 
                val inputManagerClass = Class.forName("android.hardware.input.InputManager")
                val getInstanceMethod: Method = inputManagerClass.getMethod("getInstance")
                val inputManager = getInstanceMethod.invoke(null)

           
                val injectInputEventMethod: Method = inputManagerClass.getMethod(
                    "injectInputEvent", InputEvent::class.java, Int::class.javaPrimitiveType
                )

            
                val downTime = SystemClock.uptimeMillis()
                var eventTime = downTime

                // touch down
                var downEvent = MotionEvent.obtain(
                    downTime,
                    eventTime,
                    MotionEvent.ACTION_DOWN,
                    startX.toFloat(),
                    startY.toFloat(),
                    0
                )
                injectInputEventMethod.invoke(inputManager, downEvent, 0)
                sleep(1000)
                // touch move
                val steps = 100
                val stepDuration = duration / steps
                val stepX = (endX - startX) / steps.toFloat()
                val stepY = (endY - startY) / steps.toFloat()

                for (i in 1 until steps) {
                    eventTime += stepDuration
                    val moveX = startX + stepX * i
                    val moveY = startY + stepY * i

                    // create movement 
                    val moveEvent = MotionEvent.obtain(
                        downTime, eventTime, MotionEvent.ACTION_MOVE, moveX, moveY, 0
                    )
                    injectInputEventMethod.invoke(inputManager, moveEvent, 0)
                    moveEvent.recycle()
                    sleep(stepDuration)
                }

                // touch up
                val upEvent = MotionEvent.obtain(
                    downTime, eventTime, MotionEvent.ACTION_UP, endX.toFloat(), endY.toFloat(), 0
                )
                injectInputEventMethod.invoke(inputManager, upEvent, 0)

                // release
                downEvent.recycle()
                upEvent.recycle()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

Solution

  • ACTION_POINTER_DOWN is used to signify that a secondary pointer is in the down state. Add an ACTION_POINTER_DOWN event for the second finger. The first finger will be the ACTION_DOWN event. I noticed that you are a new user.

    Found here: https://developer.android.com/reference/android/view/MotionEvent#ACTION_POINTER_DOWN

    Sample code to add:

    var secondaryDownEvent = MotionEvent.obtain(
                        downTime,
                        eventTime,
                        MotionEvent.ACTION_POINTER_DOWN,
                        startX.toFloat(),
                        startY.toFloat(),
                        0
                    )
    injectInputEventMethod.invoke(inputManager, downEvent, 0)