20

My app can be controlled by normal headset. It simply overrides "onKeyDown". But key events from bluetooth headset are not captured - why? Or how to capture bluetooth key events?

the "log cat" shows the following if i press button on headset:

Bluetooth AT recv(3043): AT+VGS=15
AudioPolicyManagerBase(13654): FM radio recording off
AudioService(2261): sendVolumeUpdate, isKeyguardLocked...Not to update Volume Panel.
VolumePanel(2261): change volume by MSG_VOLUME_CHANGED
VolumePanel(2261): onVolumeChanged(streamType: 6, flags: 0)
VolumePanel(2261): Call setChangeSeekbarColor(false)

i also tried to handle media button actions but this isn't working. my idea is a free configurable key mapping: the user chooses "set key" my app hears on all keys (hardware, media buttons, bluetooth headset) then the user presses a key and the event/key code is stored in config.

Summerizing not working Answers: Volume buttons must be captured by "VOLUME_CHANGED_ACTION". The problem is this intents are broadcasted to other apps and abortBroadcast() doesn't work (it works only for "ordered" Broadcasts). Another problem is that keys on cable headset and on phone trigger onReceive() twice (why?) the bluetooth headset trigger it once. The next Problem is the 3rd key on Bluetooth headset. It triggers voice-command (s-voice starts on s3), i tried to capture many different intents regarding this but i can't "receive" this button press and don't know why. At the end i want capture all kinds of buttons and don't want them handled by other apps (like using onKeyDown and returning true).

dermoritz
  • 12,519
  • 25
  • 97
  • 185

3 Answers3

31

Add a broadcast listener to MEDIA_BUTTON:

<intent-filter android:priority="<some number>"> 
   <action android:name="android.intent.action.MEDIA_BUTTON" /> 
</intent-filter> 

You should register your broadcast receiver inside your application (not in manifest file). Otherwise Google Music player will catch your broadcast and aboard it.

Your IntentFilter priority should be higher that other media players priorities in your phone)

Add android.permission.BLUETOOTH permission in manifest to support Bluetooth headset

After received you key you have to manually abort the broadcast using abortBroadcast().

However priorities and abortBroadcast() work fine as long as each app only responds while e.g. something is played. But several users also expect a "default player" to be launched (or start playing) upon button press, like the default player, so it might happen some app with a higher priority number won't let the intent come through to your app

In the onReceive, you can get the button event with

KeyEvent key = (KeyEvent) 
intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 

key.getKeyAction() tells you whether the button was released or pressed, key.getKeyCode() tells which button is pressed.

If you want to handle single button cable headsets as well, also regard the key code KEYCODE_HEADSETHOOK

Override the onKeyDown method in any activity and check for the KeyEvent.KEYCODE_MEDIA_KEYCODE_pressed_key

e.g.

 boolean onKeyDown(int keyCode, KeyEvent event) { 
            AudibleReadyPlayer abc; 
            switch (keyCode) { 
            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: 
                    // code for fast forward 
                    return true; 
            case KeyEvent.KEYCODE_MEDIA_NEXT: 
                    // code for next 
                    return true; 
            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 
                    // code for play/pause 
                    return true; 
            case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 
                    // code for previous 
                    return true; 
            case KeyEvent.KEYCODE_MEDIA_REWIND: 
                    // code for rewind 
                    return true; 
            case KeyEvent.KEYCODE_MEDIA_STOP: 
                    // code for stop 
                    return true; 
            } 
            return false; 
    } 

Volume key integration example Android - Volume Buttons used in my application
This one may need permission

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />


Or you can try slimier implementations over the following link

Android Developer Blog : Handling remote control buttons
Android Tales : Add Headset button support to your Android application

Community
  • 1
  • 1
Yash Krishnan
  • 2,653
  • 1
  • 18
  • 22
  • 1
    thx but i think you didn't read the other answers and my comments. This isn't working: Volumebuttons aren't "MEDIA_BUTTONS". They are captured by "volume_change". Since this intent seem to be "not ordered" "abortBroadcast()" doesn't work - error is thrown and volume changes anyway. On the other hand "KEYCODE_HEADSETHOOK" works only with cable headset. Bluetooth headset sents something that starts voice-recognition (s-voice on s3). i hardly tried to capture this but i had no success. – dermoritz Aug 01 '13 at 07:28
  • 1
    You are right, seems like I missed few things in the rush, sorry. Seems like this is the answer you are seeking [link]http://stackoverflow.com/questions/2874743/android-volume-buttons-used-in-my-application Also add permission `` – Yash Krishnan Aug 01 '13 at 08:23
  • @YashwanthKrishnan : hey what priority should i set such that media_button key event is received by our app rather than default music player?even though i have my app in the foreground, music player is receiving the key event and playing, i have set it to 10000 but still no luck. – Mahantesh M Ambi Dec 29 '14 at 11:46
  • According to this https://developer.android.com/guide/topics/manifest/intent-filter-element.html the priority must be greater than -1000 and less than 1000. – juanlugm Aug 09 '17 at 19:55
2

Check out this article. It explains how to implement something similar using media button actions.

I know you've mentioned that you walked this way without success, still give it a try. Point your attention to gotchas related to registering broadcast receiver, setting intent filter priorities and adding permissions (all explained in the article).

Hope this will help.

Eugene Loy
  • 12,224
  • 8
  • 53
  • 79
  • thx - i will try that. and if this work you'll get the bounty – dermoritz Jul 29 '13 at 06:35
  • i tried it but it doesn't work: the problem is that this captures the intent (volume change or media button) but this intent is also sent by all other volume buttons and it is handled by all other activities that are registered to that event. i want to catch the event and "consume" it - like "onKeyDown" does for HW-Keys. – dermoritz Jul 29 '13 at 11:18
  • @dermoritz are you sure that you've called `abortBroadcast` in your broadcast receiver? – Eugene Loy Jul 29 '13 at 12:25
  • i just tried it: the volume change seem to be a "nonordered broadcast" - abortBroadcast() is not working for it. And the other button on headset (used for speech command) cant't be captured at all. i tried to add all kinds of actions like "android.intent.action.VOICE_COMMAND" and "android.speech.action.RECOGNIZE_SPEECH" but my action isn't reacting on - always the phone's built in "s-voice" is starting. – dermoritz Jul 31 '13 at 06:50
  • 1
    @dermoritz I have an idea that is not strictly speaking an answer to your question but may halp you to find the solution in the end. Check out this app: https://play.google.com/store/apps/details?id=com.kin.bluetooth_launch . It says that it works with most of the bluetooth headsets (at least ones that obey standards). If it does for your case you could try to ask author/find sources or reverse engineer it to see how it is solved there. I actually can help you with reverse engineering part if needed (done something like this before). – Eugene Loy Aug 01 '13 at 11:47
  • thx for hint - i contacted the author. let's see what happens. – dermoritz Aug 01 '13 at 13:56
1

If you are trying to listen for this from an activity, use onKeyDown() and catch the KEYCODE_MEDIA_PLAY_PAUSE (KEYCODE_MEDIA_PLAY and KEYCODE_MEDIA_PAUSE post ICS) key events.

Also for the broadcast receiver solution to work make sure there arent other apps installed and running in the background that catch these events which might take priority over yours.

Also look at this: Android - registering a headset button click with BroadcastReceiver

Community
  • 1
  • 1
Vrashabh Irde
  • 14,129
  • 6
  • 51
  • 103
  • thx - but onKeyDown isn't working for bluetooth it captures only cabled headset and phonekeys. and i never can be sure what apps someone has running or installed. – dermoritz Jul 31 '13 at 06:37
  • Interesting, I would think it would catch onKeyDown , like mentioned here : https://groups.google.com/forum/#!topic/android-developers/v_7lT-o0ERg ? Also look at the second answer in the link. – Vrashabh Irde Jul 31 '13 at 08:22
  • Which version of Android? Might be changed post Jelly bean with all the new bluetooth stuff – Vrashabh Irde Jul 31 '13 at 08:23
  • min version is 4.0 and max version is 4.2 - i am testing with 4.1 on galaxy s3 – dermoritz Aug 01 '13 at 13:57