Browsed by
Tag: automate

Create touch events programmatically in Android

Create touch events programmatically in Android

Creating a touch event in Android is pretty easy. Although, is the easy way the best? Let’s find out!
The simplest way is to use the “input” binary which you can use to create touch events all over the screen (via the shell user). The command to create a simple tap event is as simple as – adb shell input tap x y.

However, there’s a latency of more than 1 second while executing this command. If we’re making some automation related app, we definitely wouldn’t want this.

Another approach is to write values directly to the device node file available inside /dev for input. This approach has slightly lesser latency, but file writing operations are anyways expensive. On top of that, some devices/OEMs might have different locations/names for the device nodes which makes this approach a nightmare to implement.

Can we do better both in terms of consistency and latency? Definitely!

Luckily, there’s a class called InputManager in Android which has some interesting methods, although the methods of our interest are either private or hidden.

Now’s when Java’s Reflection API comes to the rescue. We’ll follow a series of hacky reflection API calls to get our input injection working.

First of all, we need the instance of InputManager class. For that, we’ll just invoke the getInstance method via reflection.

Next, we need to make obtain method of MotionEvent class accessible. Then, we will get the reflection reference of injectInputEvent method.

We’re all set now, and just need to write the code to actually pass the touch events to the Android system. The code involves creating a MotionEvent object, and calling the injectInputEvent via reflection.

Another awesome thing with this approach is that, the framework will itself figure out if the current event will be a normal tap, swipe or a long press.

The full implementation of this approach is present in RemoteDroid –

Where can you create touch events?

Of course, a random user (every app is run by its own user) can’t just create touch events on anywhere on the screen just like that. A particular app can create touch events on those views only which are owned by the same app.

But there’s a catch, shell user (uid 200) can create touch events all over the screen.

Now the question becomes, how would you start your app so that the app’s code is executed by the shell user. Either figure this out yourself or search my blog for something close to that. 😉