I've got an Android app which is mostly a wrapper around a WebView which show local files.
The WebView gets the events because setContentView(thewebview) is called. This works fine most of the times (since we also handle Android Webkit Browser in the online version).
Problem is that I want to add support for D-Pad/Trackball events. I've written the appropriate onKeyDown's, but the WebView is consuming the events, not the activity.
This can be fixed in two ways:
Handle the event keycode for D-Pad Down/Up/etc. in the Javascript onKeyDown function
Get and consume the appropriate key events before the webview can get them. (ofcourse also all events can be gotten, most will simply not be consumed)
Problem is I don't know how to do either. How can I do this or solve this in a different way?
Simply 'catch' the keypresses on the WebView by using View.setOnKeyListener() to handle the KeyEvents.
public void setOnKeyListener (View.OnKeyListener l)
Register a callback to be invoked when a key is pressed in this view.
In your example that would be used like this:
thewebview.setOnKeyListener(new OnKeyListener()
{
#Override
public boolean onKey(View v, int keyCode, KeyEvent event)
{
// do your stuff here
}
});
Related
I followed the NativeScript tutorial to extend Activity at this page:
https://docs.nativescript.org/core-concepts/android-runtime/advanced-topics/extend-application-activity
The extended activity worked, so I went on and added my own onKeyUp and onKeyDown codes:
onKeyDown: function (keyCode, event) {
console.log(keyCode);
return this._callbacks.onKeyDown(this, keyCode, event, superProto.onKeyDown);
},
onKeyUp: function (keyCode, event) {
console.log(keyCode);
return this._callbacks.onKeyUp(this, keyCode, event, superProto.onKeyUp);
},
I made sure that my modified Activity was in use by adding a console.log inside onCreate to print out a message. And the Activity still worked (as I could see that message in the log), but the onKeyUp and onKeyDown were never fired. At the same time, the onBackPressed event that's in the sample Activity in the tutorial was correctly fired when I pressed the back button (I added a console.log to check).
FYI, I understand that software keyboard may not trigger the two key events, but I was using a Bluetooth keyboard. I also verified that the Bluetooth keyboard was indeed connected and working.
Thanks for Manoj's help, I found an answer. First of all, my original problem is not code related. After I did a clean build, as suggested by Manoj, the two key events were fired without any problem.
But that brought up a different problem. As mentioned by Manoj (again), I could not simply call the superclass's onKeyUp and onKeyDown because the this._callbacks does not contain the two members.
I decided not to catch the key event in onKeyUp and onKeyDown at all. Instead, I chose to override the dispatchKeyEvent. Again, I faced the same problem, how could I call the super dispatchKeyEvent? It turned out that I could not simply do:
dispatchKeyEvent: function (event) {
console.log("Dispatch Key Event");
return superProto.dispatchKeyEvent (event);
}
If I did that, I would get an error saying: The JavaScript instance no longer has available Java instance counterpart.
Instead, I need to call the super dispatchKeyEvent the following way:
dispatchKeyEvent: function (event) {
console.log("Dispatch Key Event");
return superProto.dispatchKeyEvent.call(this, event);
}
This worked like a charm!
How can I detect any gesture in my Activity, even with many things there (Layouts, Images, RecyclerViews, etc).
I intent to create an gesture that can be done at any time.
Is it possible?
I've tried this:
findViewById(android.R.id.content).setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.e("GESTURE", "GESTURE");
return false;
}
});
But it's not working. I think it's because the others views is intercepting the event.
Idk if is it possible to detect the gesture above the activity, like in the window.
Thank you!
You can, but it's a bit tricky. Read up on touch handling and especially onInterceptTouchEvent, which can be used on a parent to intercept touches going to the children.
You would implement that method in a (custom) root view, and then do your gesture magic in there.
Some valuable info here: Android: Difference between onInterceptTouchEvent and dispatchTouchEvent?
I want to know how applications handle input from a touch screen. For example, if the user touch the coordinates x,y, how an opened (active in the foreground) application will know that the gadget (button for example) at the coordinates x,y must be clicked now?
Also, can I control the way by which apps handle the touch input using another app? I mean, I want to build an app that uses services to control how other apps handle their inputs, of course this needs my app to have permission to access other apps settings, but my question is, is it possible?
I have searched for how apps handle touch input, I found these results, which are useful, but not relevant to my case,
http://developer.android.com/training/gestures/index.html
How does Android device handle touch screen input?
Also, I know that any input hardware is controlled by HAL (Hardware Abstraction Layer) in Android, also every input device has its own driver. But how apps handles the inputs coming from these devices?
Thank you.
There are several ways to handle touches in Android.
First with Buttons you can set a onClick() method that will automatically be triggered when you touch the screen.
Another option is to attach a onTouchlistener to your activity.
In this example a custom view class called "Example" with the id "exampleid" is getting attached to a "onTouchListener
Public class Example extends View implements View.onTouchListener {
public Example(Context context) {
Example exampleView = (Example) findViewById(R.id.exampleid); //This is how you set up a onTouch Listener.
gameView.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
//Do something when touched.
}
}
I am creating a custom Android component that needs sometimes to consume the onBackPressed event (e.g. there's a popup menu inside the custom ViewGroup, if it's showing, the back button event closes it and is consumed, otherwise it's ignored). Is that possible? Can I intercept this event from inside my ViewGroup subclass and how?
Edit:
I tried overriding onKeyPreIme as the Android documentation implies, the method is never invoked from within ViewGroup.
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event)
{
return true;
}
In the onKeyPreIme documentation it says:
Handle a key event before it is processed by any input method associated with the view hierarchy. This can be used to intercept key events in special situations before the IME consumes them; a typical example would be handling the BACK key to update the application's UI instead of allowing the IME to see it and close itself.
The reason why onKeyDown or onKeyPreIme are never invoked is because the ViewGroup does not have focus.
The solution was to request focus in the ViewGroup subclass' constructor:
this.setFocusable(true);
this.setFocusableInTouchMode(true);
this.requestFocus();
onBackPressed belongs to Activity and views/viewgroups are something placed inside Activity. So technically, you cant get this done. However, you may use some kind of observer/observable pattern to pass any kind of information to your views.
Or perhaps try using onKeyDown event inside your view class and track the back key event code.
I want to listen to touch events for a viewFlipper. I've been able to listen to touch events in my activity and then modify the viewFlipper but these events are fired wherever the user is within the activity and I need to capture touch events specifically on the viewFlipper. I have tried adding setOnTouchListener but it is not called. I'm assuming the viewFlippers children (webviews) are 'consuming' the touch events.
One solution would be to setOnTouchListener's to each of the webviews but this feels like a hack. Does anyone know another way?
Thanks,
Ian
Sorry if this is a double post - but my previous post seems to have vanished.
Use ViewGroup.onInterceptTouchEvent(MotionEvent)
You should Reference the Android Documentation as it's usage is quite complicated.
Basic Summary of use:
You receive the touch event here. If you want to consume it, return true and control will be passed to the ViewFlipper's onTouchEvent(). Return false and it will continue to be passed to the child. onTouchEvent() should also return true to ensure all further events are returned to the ViewFlipper's method. The child will also receive the original event with the action ACTION_CANCEL.
Finally It worked for me. Return true by default to get multiple calls on this listener.
viewFlipper.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (this.gestureDetector.onTouchEvent(event)) {
return false;
}
return true;
}
});
I was having the same problem and found your page trying to google for an answer.
After a few very frustrating attempts I ended up finding a quite easy solution, I'm still listening to the touch on the whole activity just like you did, but on the OnTouchEvent I filter if the ViewFlippers is touched or not:
#Override
public boolean onTouchEvent(MotionEvent event) {
if(mFlip.isInTouchMode()){
return gestureDetector.onTouchEvent(event);
} else{
return super.onTouchEvent(event);
}
}
hope it helps!