34

Is it possible to simulate touch from the background application (or service) or to run sh script (that simulate touch)?

It is needed for testing android system without USB or other connection to PC, thats why I can't (or don' know how) use Monkey or other autotest tools.

Added info: I found the way to run shell commands with root (tested devices rooted):

Unable to execute sendevent shell command through the android code (create touch simulation). Writing file on system partition (run commands with root permissions)

Also I get events to simulate touch.

As a result I have:

//sendevent commands to simulate touch (verify it work from cmd)
String[] touchEvent = { "sendevent /dev/input/event0 0 0 0\n",
                        "sendevent /dev/input/event6 3 53 499\n",
                        "sendevent /dev/input/event6 3 54 680\n",
                        "sendevent /dev/input/event6 3 58 40\n",
                        "sendevent /dev/input/event6 3 48 3\n",
                        "sendevent /dev/input/event6 3 57 0\n",
                        "sendevent /dev/input/event6 0 2 0\n",
                        "sendevent /dev/input/event6 0 0 0\n",
                        "sendevent /dev/input/event6 0 2 0\n",
                        "sendevent /dev/input/event6 0 0 0\n",
                        "sendevent /dev/input/event0 3 0 2\n",
                        "sendevent /dev/input/event0 0 0 0\n"};

try{
    Thread.sleep(2000);
    Process root = Runtime.getRuntime().exec("su");
    DataOutputStream os = new DataOutputStream(root.getOutputStream());             
    for(int i = 0; i < touchEvent.length; i++){
            Log.i(TAG, touchEvent[i]);  
            os.writeBytes(touchEvent[i]);
            os.flush();
    }
    root.waitFor();
} catch (IOException e) {
    Log.e(TAG, "Runtime problems\n");
    e.printStackTrace();
} catch (SecurityException se){
    se.printStackTrace();
} catch (InterruptedException e) {
    e.printStackTrace();
}

I have no any exceptions, but it is not touch simulates.

Can anybody help to solve this problem?

If there is another way to do it with android ndk or daemon on C, please tell me about it.

Thanks.

Community
  • 1
  • 1
v1k
  • 1,307
  • 2
  • 15
  • 20
  • if your on the same local network you can use monkey, adb will work over wireless as well. – L7ColWinters Feb 20 '13 at 23:11
  • Thanks for the reply. I know about it, but there should not any connection (WiFi and BT should be off). – v1k Feb 20 '13 at 23:18
  • Hi, how do you eventually accomplish this? I followed all your steps but no good news, please review my question I had posted [here](http://stackoverflow.com/questions/42745005/android-self-signed-apk) – Lance Leroy Mar 12 '17 at 07:45

3 Answers3

33

I can't execute the "sendevent" command, but found another way for myself, hope it will be helpfull for somebody.

For simulate touch I used sendPointerSync() from android.app.Instrumentation, that work only with "android.permission.INJECT_EVENTS" permission. For use it you should compile your app as a system app. To do it you should follow next steps:

  1. Getting files from android source:

    root-of-android-source-tree/out/host//framework/signapk.jar

    root-of-android-source-tree/build/target/product/security/platform.x509.pem

    root-of-android-source-tree/build/target/product/security/platform.pk8

  2. sign your app using getting files:

    Command "java -jar signapk.jar platform.x509.pem platform.pk8 YourApp-unsigned.apk" YourApp-signed.apk.

  3. adb install YourApp-signed.apk
    • Run your app
    • Use "adb shell ps" to confirm that your app is running as system.

Code with touch simulating(new thread is necessary for simulation):

Thread thread = new Thread(){
       @Override
       public void run(){
               Instrumentation m_Instrumentation = new Instrumentation();

               m_Instrumentation.sendPointerSync(MotionEvent.obtain(
                       SystemClock.uptimeMillis(),
                       SystemClock.uptimeMillis(),
                       MotionEvent.ACTION_DOWN,posx, posy, 0));
               m_Instrumentation.sendPointerSync(MotionEvent.obtain(
                       SystemClock.uptimeMillis(),
                       SystemClock.uptimeMillis(),
                       MotionEvent.ACTION_UP,width*4/5,height, 0));
       }
   };

Manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yourapp"
    **android:sharedUserId="android.uid.system"**
    android:versionCode="1"
    android:versionName="1.0" >

Using resources:

Community
  • 1
  • 1
v1k
  • 1,307
  • 2
  • 15
  • 20
  • Great, thanks. Can you please tell me what was the Android version on which you tested the code? Instrumentation works well on versions before Lollipop. I think Lollipop needs some extra work to have the instrumentation running, have you faced this problem? Or, do you know any possible solution? – Dania Mar 16 '16 at 08:19
  • 1
    I developed it on March 2013, there was no lollipop version, or it was only on preview version, I don't remember right. So I tested it only on Jelly Bean. – v1k Mar 16 '16 at 17:29
  • v1kI this is the first time I try to get files of the system. I can't figure out how to get the files to make the app as system app. Can you please help me? Can you tell me the steps to do that? – Dania Mar 24 '16 at 06:28
  • First of all, you should have an access to android OS sources, if you try to develop system app, you obviously have system, that would contain your app. There is root folder with a sources, for compiling android, so it's equals "root-of-android-source-tree" in my answer. – v1k Mar 24 '16 at 16:35
  • v1k thanks I've read your answer. My question is how to access "root-of-android-source-tree". Is it something on the device, pc, or something I get by installing another component? How can I access the root folder? – Dania Mar 24 '16 at 16:38
  • I don't know any way to access it from prepared build, or android system on device... I took it from sources, if you modify android OS, you also have sources for compile it, or from guys, who worked in this way. I already removed them, and have no access anymore. – v1k Mar 24 '16 at 16:54
  • So, for that did you follow something like this: https://source.android.com/source/downloading.html? What about installing the app as a system app by installing it first on the sd card, then moving it to the system directory. Will that help? – Dania Mar 24 '16 at 17:11
  • No, sorry for misunderstanding... I worked in company that modify android OS, so for testing I had access to their repository with sources. – v1k Mar 24 '16 at 17:14
  • Ok, I got it. Thanks. – Dania Mar 24 '16 at 19:17
30

I was about to implement your solution when I found an easier one - posting in the hope it will be helpful to someone. Since you already have a rooted device, you don't need to sign as a system app.

To simulate a touch at position (100,200), all you need to is call input from within the service using Runtime.exec as follows:

Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
String cmd = "/system/bin/input tap 100 200\n";
os.writeBytes(cmd);
os.writeBytes("exit\n");
os.flush();
os.close();
process.waitFor();
simmons
  • 835
  • 1
  • 9
  • 17
  • 1
    That's a much cleaner solutionl. Unfortunately it doesn't have event like touch_down, touch_up or move_to, which is much needed by me. :( – Xi 张熹 Nov 09 '14 at 02:38
  • Thanks , it worked on my galaxy s4 5.0.1 default ROM but it works rarely on some devices like galaxy s6 6.0.1 rooted.It's so wearied! Why? – Mohammad H Aug 14 '16 at 17:01
  • 2
    Looks like you don't even need the device rooted. A plain `Runtime.getRuntime().exec("/system/bin/input tap 100 400");` did the trick for me on a standard non-rooted Android 7.0 device. – legolas108 Apr 02 '18 at 12:24
  • But calling without "su" it will only work within the calling process ... (being a non-elevated privilege). i.e. the tap won't be sent to other processes. – noelicus Nov 27 '18 at 15:27
  • 2
    This solution works great, with one caveat: It's fairly slow. On my phone, there's about a 1+ second delay between when the command is sent, to when the touch is registered. – dkniffin May 31 '19 at 02:08
3

You can use the "swipe" input. Looking at the Input.java source code you can see the needed parameters to make a swipe.

Here is a gist I made for simulating a swipe for playing the smove game with clicks instead of swipes just to test this. You need super user access to use this implementation though.

MiichaelD
  • 93
  • 5
  • 7
    Could you make an edit to include examplish code snippet demonstrating this solution? This is on the verge of being "link-only" answer. – bardzusny Jul 25 '15 at 07:23
  • the source code is actually quite obvious and self-explainatory. for swipe: `com.android.commands.input.Input.main(new String[] {"touchscreen", "swipe", "", "", "", ""[, ""]})` ("touchscreen" is optional in some sense, but better presented. What I want to ask is that is the code really working? and do I need any declaration for permission in AndroidManifest.xml or need root access? – Valen Aug 27 '16 at 18:19
  • ^ refer to the one above: use `"blah blah".split(" ")` for better visual expression – Valen Aug 27 '16 at 18:20