Intercept joystick input events - android

I am developing an android IME for joysticks. It consists of a Thread that is constantly listening events from a specific device, and then if some conditions are true decides to do something. Is there a way to exclusively bind input events from this device to my IME, so that they won't propagate to applications?
I tried using ioctl(fd,EVIOCGRAB,1) inside a native library to take exclusive control of my device but it doesn't seem to work.
Update: EVIOCGRAB works fine and that's how I solved the problem!

For who's interested I finally found the way to do it:
use this on your "source" device (it is native code that you can use together with libEventInjector):
int fd = open("/dev/input/eventX", O_RDONLY);
if(fd<0) return;
if(ioctl(fd,EVIOCGRAB,1) <0) return;
if everything goes ok the library will have exclusive access to the device, now in your IME start a thread that keeps reading /dev/input/eventX so that you can read the events but they won't propagate to elsewhere.
UPDATE: EVIOCGRAB gives exclusive control only to an instance of a function of your Java class. The best way to intercept events without blocking the device when you close your program is this:
public class Class extends Thread{
boolean running = true;
public void run(){
mySourceDevice.getExclControl();
while(running){
}
mySourceDevice.releaseExclControl();
}
public void interrupt(){
runing=false;
super.interrupt();
}
}

Related

IOIO board on Android: Working with external interrupts and change notifications

I am developing an Android application which controls some relays based on some sensors input. I have everything set up and code works just fine, except I don't like the fact that I have to poll for state changes in my activity.
My code is based on this example: https://github.com/ytai/ioio/blob/master/applications/HelloIOIO/src/main/java/ioio/examples/hello/MainActivity.java
For instance:
fun looper() {
// ...
DigitalInput in = ioio.openDigitalInput(exti1Pin, DigitalInput.Spec.Mode.PULL_DOWN);
boolean value = in.read();
// do something if true
// ...
} // looper
The PIC24 on the IOIO board comes with 5 external interrupts as well as change notifications on most pins. However I can't seem to find any way to set up interrupt handlers or change notifications.
Would appreciate any pointers/ideas/suggestions

Why does my QGestureRecognizer not receive Touch Events?

Context: I'm trying to create a fader-like widget that can have multiple instances in the same view, each of which can be controlled simultaneously by different fingers.
I want to use Qt's gesture recognition system, but I also need some functionality above and beyond the standard Qt::PanGesture. To this end, I've subclassed both QGesture and QGestureRecognizer. In FooGestureRecognizer::recognize(...), I'm currently intercepting both QMouseEvents and QTouchEvents (for the time being, at least).
On Windows I only receive QMouseEvents - I handle them and everything works as expected (though obviously I don't have to deal with the multitouch problem when my input is from a physical mouse). The events I receive (in order):
QEvent::MouseButtonPress
A string of QEvent::MouseMoves
QEvent::MouseButtonRelease
On Android, I receive a strange mix of QMouseEvents and QTouchEvents (in order):
QEvent::TouchBegin
QEvent::MouseButtonPress
QEvent::MouseMove (with no actual change in position)
Another QEvent::MouseButtonPress (not sure why I needed another one)
My actual string of QEvent::MouseMoves, as expected
QEvent::MouseButtonRelease
The global attribute Qt::AA_SynthesizeMouseForUnhandledTouchEvents is true by default. Turning it off changes the events I receive to:
QEvent::TouchBegin
...nothing else.
Here's a precursor question then: What can I do inside QGestureRecognizer::recognize() to tell Qt that I'm handling the QEvent::TouchBegin, and that it doesn't need to synthesize a QEvent::MouseButtonPress for me? event->accept() doesn't appear to make any difference.
The actual question: If (as it appears) Qt is synthesizing MouseEvents from TouchEvents, why do I see I see QEvent::MouseMove and QEvent::MouseButtonRelease but not QEvent::TouchUpdate or QEvent::TouchRelease?
Code is available, but in the interests of conciseness I've not included it here. Please ask if needed.
From the QTouchEvent docs:
The QEvent::TouchUpdate and QEvent::TouchEnd events are sent to the widget or item that accepted the QEvent::TouchBegin event. If the QEvent::TouchBegin event is not accepted and not filtered by an event filter, then no further touch events are sent until the next QEvent::TouchBegin.
The root of this problem is that QGestureRecognizer does not accept the initial TouchBegin, and hence we don't receive any further touch events. I got around this by:
Creating a thin event filter QObject owned by my QGestureRecognizer.
Containing the following code:
bool FooGestureRecognizer::FooEventFilter::eventFilter(QObject *Object, QEvent *Event)
{
if(Event->type() == QEvent::TouchBegin)
{
return true;
}
else
{
return QObject::eventFilter(Object, Event);
}
}
Installing my event filter AND calling setAttribute(Qt::WA_AcceptTouchEvents) on every valid* Target that comes through FooGestureRecognizer::create().
Returning true from eventFilter tells Qt that my fader is interested in receiving further touch events, and these touch events are delivered as expected to the gesture recognizer.
This solution feels like a hack, and one that might not be necessary in future versions of Qt, so I'm going to keep an eye on this code.
Notes:
During the construction of a QGestureRecognizer, create() is called with a null Target (expecting a dummy QGesture to be returned). Watch out for this if you're installing event filters on all Targets.
My application needs to handle desktop mouse events in one way, and multi-finger touch events in another, so I've disabled Qt::AA_SynthesizeMouseForUnhandledTouchEvents. Keeping this enabled may lead to other considerations (e.g. I'm not sure if you'd need to return true for all touch events in eventFilter, so as to avoid them being duplicated as synthesised mouse events).

PhoneStateListener - what can I expect from onCellInfoChanged?

I posted this on Android dev group. I'm hoping I can get some feedback here.
The PhoneStateListener's callbacks onCellLocationChanged and onSignalStrengthsChanged were the goto methods for when I wanted to handle cell and signal data changes in GSM and CDMA. With API 17+, I can see that there's a new callback (onCellInfoChanged) for handling both cell and signal changes.
Looking at the documentation, it's not clear what I can expect from the introduction of this new callback.
Will LTE changes always and only trigger onCellInfoChanged?
Will GSM/CDMA changed remain on the older callbacks?
Does one overlap with the other? (i.e. Both old and new get triggered for LTE or GSM/CDMA.)
It may very well be that different OEMs will have different implementations (sigh!), but I'm hoping there are guidelines that everyone's supposed to follow.
Can anyone shed some light on this?
Thanks,
Sebouh
I didn't test if but it looks from the code that both will be called.
I downloaded code source of Android 4.3(API 18) using the SDK Manager.
The following observations made me think that both would be called.
The class that triggers these events is: com.android.server.TelephonyRegistry
It notifies the listener though:
public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow)
This same function calls for both type of notifications(Location and CellInfo) in a non exclusive way.
On line 256:
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
try {
if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation=" + mCellLocation);
r.callback.onCellLocationChanged(new Bundle(mCellLocation));
} catch (RemoteException ex) {
remove(r.binder);
}
}
This one will call onCellLocationChanged even on new LTE phone since there is nothing from the above code that would prevent this. This needs double checking that there is no upper layer that filters the events themselves
On line 300 in the same code:
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
try {
if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo=" + mCellInfo);
r.callback.onCellInfoChanged(mCellInfo);
} catch (RemoteException ex) {
remove(r.binder);
}
}
There are other things from the code that look like CDMA will be calling the newer API. For example com.android.internal.telephony.cdma.CdmaLteServiceStateTracker seems to be dealing with CDMA and LTE. Again it would require a more careful look but that should give you a good place to start.
You can also try to simulate that with the emulator.

Inject events in Android without root

I've been trying to figure out how to inject touch/ keyboard events into an Android device for a while now (within and outside of you application).
I found an app that does this without root permissions:
https://play.google.com/store/apps/details?id=com.vmlite.vncserver
Does anyone have any clue how they did it?
If you want to inject touch events on android app without root:
you can use Instrumentation class,
https://developer.android.com/reference/android/app/Instrumentation.html
import android.app.Instrumentation;
public class MainActivity extends Activity {
Instrumentation m_Instrumentation;
public void onCreate(Bundle savedInstanceState) {
m_Instrumentation = new Instrumentation();
int x=0; //your x coord in screen.
int y=0; // your y coord in screen.
m_Instrumentation.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(),MotionEvent.ACTION_DOWN,x, y,0));
m_Instrumentation.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(),MotionEvent.ACTION_UP,x, y,0));
}
}
This method obtains ACTION_DOWN and ACTION_UP event which injects an event on the current layout.
Note: if the injection of your coordinates (x,y) is outside of screen size, the app will crash.
This method injection works only inside app, if you want to inject touch events, you need a rooted device and inject events through adb command.
for non-rooted devices, every time after turning the device completely off and on, you will have to connect your device to a Windows PC or Mac using a USB cable, then run a free desktop program, VMLite Android App Controller, to start the server on your device.
I'm quite sure that at this step it changes the permissions on /dev/input/event.. files and performs the injecting by writing those (sidestepping the Android VM). This technique is detailed in this blog post: Part1, Part2

Android Java code to mimic a 2 Keystroke sequence (to perform a device screenshot)

I have been trying to get a bitmap screenshot of a SurfaceView for days but the more I look into it, there doesn't seem to be a solution at present for Android OS 2.3.4 based OSs my device from HTC.
So on to Plan B, where I just found out another blog: "On my HTC Evo 3d, all I have to do is hold the power button for 1-2 sec and then hit the home button and it takes a screen shot. No app required." Turns out this works perfectly on my tablet.
I also know from digging around there are these intents: android.intent.action.SCREEN_OFF & android.intent.category.HOME
(So I tried a bunch of code experiments to try to mimic the 2-key combo in code to get a screenshot in this brute force manor. Unfortunately without success).
So my ? -- Does anyone have any insights into a method to invoke this 'screenshot sequence' for my HTC device from java code? (Presume I need to fool the OS into thinking I am holding down the power key AND tap the Home key, simultaneously)...
More: Here is a snip of the code I am attempting:
Button click for test... ...
Thread t = new Thread() {
public void run() {
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_POWER);
Instrumentation inst2 = new Instrumentation();
inst2.sendKeyDownUpSync(KeyEvent.KEYCODE_HOME);
} // run
}; // thread t
Doesnt work as the inst.sendKeyDownUpSync is wrong as I need a sendKeyDown (& hold) behavior or its equivel
Many thanks for any advise. If I do get this working, I will post the solution here. Cheers GH
PS; I presume there is some custom intent under the hood doing this? Is there a system log somewhere to trey to peek at the call tree to find out what it is ?
EDIT (MORE)... 9/24/11
More. Still not working but I am heading down this path & think it is closer...
// Attempt to SIMULATE A Long press (DOWN) + HOME to tell the HTC to invoke the 'Screenshot' command (WARNING: HTC Tablet specific behavior!)
Thread tt = new Thread() {
public void run() {
final KeyEvent dapowerkey = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_POWER);
Handler onesecondhandler = new Handler();
onesecondhandler.postDelayed(new Runnable() {
public void run() {
// fpr about 1 second send power down keystrokes (DOWN ONLY)
while (true) { dispatchKeyEvent(dapowerkey); }
} // we are done running on the timer past time point
}, 750); // 3/4 second key press
// send the HOME keystroke
Instrumentation inst1 = new Instrumentation();
inst1.sendKeyDownUpSync(KeyEvent.KEYCODE_HOME);
} // outer thread run tp mpt block the GUI
}; // outer thread t
tt.start();
...
Also thought if I can send the right intent directly to the proper place on the device that I might be able to kick off a screen capture function directly (which is what I really want. Through some log examinations (when you Long-Power + Home click on HTC) a program called 'com.htc.mysketcher' (FlashActivity) is being called...
Again, if I figure this out then I will post to the group... Cheers GH

Categories

Resources