Catch touch events in background applications
A while back I have worked with a friend in an application that would catch all touch events done on your phone. As you may well guess you are not suppose to be able to do this as it is considered a security breach; but if you have a rooted phone you may have an application doing this. The documentation on this subject on the net isn't very complete(at least wasn't when I built my application) and there wasn't any detailed explanation about to do it especially if you want to do get precise information.
Possible solutions
We have come up with multiple solutions before actually using the one I will explain a bit later. But first let see other ways of achieving this.
System Overlay
Consist of creating an application service that will show a transparent widget on top of everything. This way all touch events will be done on our widget and we will be able to catch them all. The service type we used was WindowManager.LayoutParams.TYPE_SYTEM_OVERLAY
But sadly with this method we could only get access to some of the events. Normally there should be 3 event :
- down : When a finger touches the screen for the first time
- move : Once it touched down, the finger moves on the screen
- up : Once the interaction finished you remove you finger from the screen
But we could only aces the down events and nothing else, worse the framework API version 14 and newer blocked even this event for security reasons.
Therfore we needed another solution
We switched our service type a few times and found out that a service of type
Window.Manager.LayoutParams.TYPE_SYTEM_RADION was able to catch all the events, but it made the interaction with the phone impossible. The service used the events without transmitting them to the underlayers. We weren't able to figure a way to make it work.
Glass Pane, event injection
The android framework didn't allow us to transfer events as we wished, but what if we started thinking more low level. What if we retransmitted the events to the android system by injecting them back?
We could do an applicaiton working this way :
- Start service on top layer(as seen before)
- Get an event
- Remove the top player
- Inject the event back into Android (writing into a specific system file)
- The event goes to the correct application (ours has no widget on top of it)
- Activate back the widget
If you have and notion about how the injection work you understand why this is very complicated to put inplace, near impossible. The problem is that the injection will be done at the driver level, below the framework level.
- It isn't that touchscreen driver that decides if the event is a move or down event, it is the framework. Therfore if we catch a down event, inject it, the framework will see the new event as a move event, as you can't have to consecutive down events.
- Same principle for up events,
You can see the problem in this image :
With a bit of work this can be fixed of course but it will add lag to the usage; and as you can see in the image it becomes quite complicated.
We need to send false events in order to get the system work as if our probe wasn't present.
So we need another solution.
So? Let's read events
What we will try and do is read directly the system events, before anything Android is Unix based so everything passes by files, even if they are not true files stored on a hardrive. We must find which file contains the information that we require then read this file and understand what is happening in it. But first things first we need to get root permissions.
Get root acces
Getting root acces is actually very simple, we will just use the terminal(in Java launch a command) and do like many unix systemes :
su -c <thecommand></thecommand>
This will popup a screen on your phone asking you to give the application launching it the root acces it. We will of course do this using a Runtime in java. We will see this later.
Finding the events file
Now that we now how to get root acces just let us find the file we need to read, to do this we have a command that will help us. If we type :
getevent -p
We will use this code to do this in java :
String[] cmd = {"su", "-c", "getevent -p"};
Process p = Runtime.getRuntime().exec(cmd);
We will get multiple lines with information about the data that is in each input file. We are searching the one with touchscreen as information in it. On my HD2 it looks like this :
add device 6: /dev/input/event0
name: "htcleo-touchscreen"
KEY (0001): 0102 014a
ABS (0003): 0000 : value 0, min 6, max 576, fuzz 5, flat 0, resolution 0
0001 : value 0, min 6, max 952, fuzz 5, flat 0, resolution 0
0018 : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
001c : value 0, min 0, max 5, fuzz 0, flat 0, resolution 0
0030 : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
0032 : value 0, min 0, max 1, fuzz 0, flat 0, resolution 0
0035 : value 0, min 6, max 576, fuzz 5, flat 0, resolution 0
0036 : value 0, min 6, max 952, fuzz 5, flat 0, resolution 0
We can see that we need to read the input file 0 (/dev/input/event0) this value isn't the same on all smart phones so you will need to find it at the application start using this command. You should also keep in mind that min, max values that are to be found will be useful later on if you decide to calibrate your sensor.
Another note, you might on some devices find 2 touchscreen, don't be suprised but some devices using capacitive buttons at the buttom of the screen uses a second touchscreen. On some other devices the size of the touch screen is bigger then the size of the screen due to this.
On a special noten now that I re read this I wonder how it works with the samsung galaxy edge,
Single touch events only
So if we read the content in the /dev/input/event0 file we will see something looking like this :
558662-144777: 0000 0000 00000000
558662-155214: 0003 0035 000000e3
558662-155428: 0003 0036 00000342
558662-155580: 0003 0030 00000064
558662-155702: 0003 0032 00000000
558662-156130: 0000 0002 00000000
558662-156404: 0000 0000 00000000
558662-165804: 0003 0035 000000f3
558662-165865: 0003 0036 00000372
558662-165865: 0003 0030 00000064
558662-165895: 0003 0032 00000000
To be completed ...
Manufecturers doesn't always do it right
This is the worst part, you have done all this work to learn that what you just did might not work on some smartphones. This is how google has described the events that should be in that file, but as android is open source some manufecturers have decided to do things differently and moidfy the source code. This of course isn't a problem for 99.9% of programers but if you need to work on something like this it becaumes horrible.