I have an android application that is meant to be used with a game controller connected to the android device.
Most game controllers have a center 'home' button that I would like to use to pause the game (for example, an Xbox controller center nexus button should pause).
However, when you press the center nexus button on the controller it causes the entire app to close as though the actual home button on the phone was pressed. Why is the center button on some controllers causing the app to return to the home screen? Note, this doesn't happen with all controllers or all devices. For example, using a pixel 6 and an xbox controller it doesn't send the app home. But using a galaxy a32 the center nexus button does triggers the home action.
I understand its not possible to intercept the actual home action from within an app. But is it possible to do so from a physical controller? Or is it possible to remap the controller buttons?
I tried this in an attempt to intercept the home action:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.e("KeyPress", "Code: " + keyCode);
switch (event.getKeyCode()){
case KeyEvent.KEYCODE_HOME:
return false;
default:
return super.onKeyDown(keyCode, event);
}
}
but this isn't working. Pressing the center button on the controller doesn't trigger the log but it still goes to the home screen.
Any ideas how to make certain button on physical controllers not trigger the home action?
Thanks
This happens with gamepads that send the same input code used for the "Homepage" key on some keyboards. By default, HID input devices are handled by the hid-input driver which always translates the "Consumer Application Control Home" usage (000C:0223) to the KEY_HOMEPAGE Linux input event code.
https://github.com/torvalds/linux/blob/4e23eeebb2e57f5a28b36221aa776b5a1122dde5/drivers/hid/hid-input.c#L1151
The Android OS converts KEY_HOMEPAGE to KeyEvent.KEYCODE_HOME which is handled by the framework and never delivered to applications. Probably it should convert it to BTN_MODE as suggested by the Linux gamepad specification.
If you have root access you can fix this by adding a Key Layout file to correct the button mapping for a specific device. See Vendor_045e_Product_02fd.kl for an example of a key layout file that maps KEY_HOMEPAGE (Linux input event code 172) to Android's KeyEvent.KEYCODE_BUTTON_MODE.
Related
I have written a sailing app for watches running Wear OS. Sailing watches often get wet so I disabled the screen and navigate the menu using physical key presses (single and multiple presses). So far so good
I am now trying to detect a Long Press of the physical key (for an emergency Man-Over-Board function) but so far I have been unable to find any event which is triggered when a physical key is held down on the Samsung Galaxy Watch 4.
Can anyone suggest how to detect a long key press on the Samsung Galaxy Watch 4?
Most of the key press detection can be done by overriding onKeyDown()
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
return if (keyCode == bottomKeyCode) {
// process bottomKeyPress
writeToLog("onKeyDown()")
event.startTracking() // required to enable LongPress (works on TicWatch NOT Samsung)
true
} else
super.onKeyDown(keyCode, event)
}
On the Samsung Galaxy Watch 4 a short press will trigger the onKeyDown() event
The problem is no events are triggered when the key is held down. Holding down the key does not trigger onKeyDown or onKeyLongPress. It does not even trigger onKeyUp when the key is released!
Further testing
I have also looked at dispatchKeyEvent()
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
writeToLog("dispatchKeyEvent() keyCode ${event.keyCode} keyAction ${event.action}")
return super.dispatchKeyEvent(event)
}
This was also unsuccessful
I have run the code on a Ticwatch Pro 3 GPS (Wear OS 2) and the behaviour is 'closer' to what is described in the Android documentation. When the key is first pressed onKeyDown() is triggered. Continuing to hold the key down results in a second onKeyDown() 350msec later. This is followed by more onKeyDown() events sent every 50msec after that (along with an onLongKeyPress()). Hence the easiest way to implement Long Key Press detection on the TicWatch is to simply count the number of onKeyDown() events (to avoid the unneeded onLongKeyPress() event simply remove event.startTracking()).
Note the Samsung Galaxy Watch 4 uses keyCode == KeyEvent.KEYCODE_BACK for the bottom physical key rather than the Ticwatch which uses KeyEvent.KEYCODE_STEM_1. For completeness I investigated onBackPressed() but this is also not being triggered
override fun onBackPressed() {
writeToLog("onBackPressed()")
super.onBackPressed()
}
Samsung finally responded and the formal answer is Long Press is not supported
Unfortunately, it is not possible to get dispatched long-press keyEvent from the Samsung Galaxy watch 4.
Both Hardware buttons (named Home key and Back key) of watch 4 are system keys.
According to Samsung's policy, in the case of system keys, 3rd party can not get the KeyEvent of the watch 4 devices.
Factually it is possible for 3rd party apps to get access to the onKeyDown() event (as shown in the original question) PROVIDED it is only a short press
If the back key is held down then the watch does not trigger the onKeyDown() event (meaning any attempt to use a timer to simulate an onLongKeyPress() event will also be unsuccessful)
I'm developing an app with jquery mobile and cordova and it all works great except in ios devices where the vlcick event is fired twice, but in different pages, i mean, i fire a vclick to change the page, and another vclick is automatically fired in the button that would be in the same position in the page that i'm changing to.
Somthing similar is happening when i touch the physical back button on my android, it shows me the previous page but instantlly returns to the page whre i touched the back button.
You should stop the propagation:
$(".you_selector").on("tap", function () {
event.stopPropagation();
event.preventDefault();
// Your logic
});
I tried both the Intent-receiver and the onKeyDown Method. Both work fine for most buttons but the Beats Solo Headset has multiple Buttons and only the Play Button is detected, the + / - Buttons don't trigger the Receiver nor they trigger onKeyDown().
Any ideas?
Ok, I found the problem in the AOSP Tech Specs. There are a lot of HID Interactions that aren't defined for Android. So I will try to read out the HID code with a scope and map this Key to Android.
Android AOSP // KEYBOARD
EDIT: I connected them to the scope while a menu button press is clearly visible, the + amplitude is pretty small and - is nearly indetectable. I attached both scope screenshots. If anyone has found a solution then contact me please.
NOTE: the screenshot shows the menu button pressed 3 times!
I couldn't find it in the docs, is there a module, or some other way to catch events from the android back button? If not it would be a nice and probably quick module to add.
No: the back button just pops you one item back in the history stack. You do something like change the hash fragment to track navigation through your app (frameworks like Backbone.js can do this for you automatically).
The reason we've taken that approach is there's no hardware back button on iOS so we're wary of setting people up to rely on it in their app, only for the app to be fundamentally broken on that platform: we're aiming for consistency of completeness at the moment.
Update: due to popular demand, we've added support for controlling the back button behaviour on Android: http://docs.trigger.io/en/v1.4/modules/event.html#backpressed-addlistener - note backPressed.preventDefault too.
The event handler is passed a function which, when invoked, closes the app, so you could have code like:
forge.event.backPressed.addListener(function (close) {
if (atHomeScreen) {
close();
}
}
I'm developing an industrial app that's running effectively in a KIOSK mode - that is users must not be able to exit it.
To achieve this I've simply made the app a launcher/home screen replacement. This works very effectively and so far seems to be working as a method of preventing people getting out.
The only problem I have is that if I'm not careful we're going to end up with bricked devices where we can't get back to a normal launcher application.
What I'm looking for is a method of programmatically presenting the Android Launcher Selection Dialog.
Android seems to do this on it's own when you first launch a launcher, but I can't figure out a way of doing it programmatically.
What I'm looking for is a method of pro grammatically presenting the Android Launcher Selection Dialog.
Intent.createChooser() returns an Intent that will launch a chooser (which I think is what you mean by "Android Launcher Selection Dialog") for a given Intent. So, create an Intent for ACTION_MAIN and CATEGORY_HOME, wrap that in Intent.createChooser(), and call startActivity() on the resulting Intent.
If I understand this question right you don't want to get the user out of your app if he don't want it?
I would do it like this:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return true;
}
Now button clicks will be ignored for the activity. Now you only have to make a menu point for the exit.