如何在安卓系统中从蓝牙耳机捕获关键事件

20

我的应用可以通过普通耳机进行控制。它简单地覆盖了“onKeyDown”方法。但是蓝牙耳机的按键事件无法被捕获 - 为什么?或如何捕获蓝牙按键事件?

如果我按下耳机上的按钮,“日志cat”显示如下:

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)

我也尝试处理媒体按钮的操作,但这并没有起作用。我的想法是一个自由配置的键映射:用户选择“设置键”,我的应用程序监听所有键(硬件、媒体按钮、蓝牙耳机),然后用户按下一个键,事件/键代码就会存储在配置中。

总结不起作用的答案:音量按钮必须通过“VOLUME_CHANGED_ACTION”来捕获。问题是这些意图被广播到其他应用程序,并且abortBroadcast()不起作用(它仅适用于“有序”的广播)。另一个问题是有线耳机和手机上的按键会触发两次onReceive()(为什么?)而蓝牙耳机则只触发一次。接下来的问题是蓝牙耳机上的第三个键,它会触发语音命令(s3上启动s-voice),我尝试了许多不同的意图来解决这个问题,但我无法“接收”这个按钮的按下事件,也不知道原因。最后,我想捕获所有类型的按钮,并希望它们不会被其他应用程序处理(例如使用onKeyDown并返回true)。


安卓的哪个版本? - Vrashabh Irde
最小版本为4.0,最大版本为4.2(在清单中指定),在Galaxy S3上测试过,版本为4.1。 - dermoritz
@dermoritz 你有机会解决这个问题吗? - Rashad.Z
抱歉,我记不起来了,太久以前了。 - dermoritz
3个回答

31

MEDIA_BUTTON 添加广播监听器:

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

你应该在应用程序内部注册广播接收器(而不是在清单文件中注册)。否则,Google音乐播放器会捕获您的广播并中止它。

您的IntentFilter优先级应该比手机中其他媒体播放器的优先级更高。

在清单中添加android.permission.BLUETOOTH权限以支持蓝牙耳机。

在收到密钥后,您必须使用abortBroadcast()手动中止广播。

然而,只要每个应用程序仅在播放某些内容时响应,优先级和abortBroadcast()就可以很好地工作。但是,一些用户还希望在按下按钮后启动或播放默认的播放器,例如默认播放器,因此一些优先级较高的应用可能会阻止意图传递到您的应用程序。

onReceive中,您可以使用以下方式获取按钮事件:

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

key.getKeyAction()告诉你按钮是被释放还是按下,key.getKeyCode()告诉你哪个按钮被按下了。

如果你想同时处理单个按钮的耳机,也要考虑键码KEYCODE_HEADSETHOOK

在任何活动中重写onKeyDown方法并检查KeyEvent.KEYCODE_MEDIA_KEYCODE_pressed_key是否被按下。

例如:

 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; 
    } 

音量键集成示例 Android - 在我的应用程序中使用音量键
这个可能需要许可

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


或者您可以尝试通过以下链接使用类似的实现方式

Android开发者博客:处理遥控按钮
Android故事:将耳机按钮支持添加到您的Android应用


1
谢谢,但我认为您没有阅读其他答案和我的评论。这不起作用:音量按钮不是“MEDIA_BUTTONS”。它们被“volume_change”捕获。由于此意图似乎是“无序的”,因此“abortBroadcast()”无法工作-会抛出错误并且音量仍然会更改。另一方面,“KEYCODE_HEADSETHOOK”仅适用于有线耳机。蓝牙耳机发送的内容会启动语音识别(在s3上是s-voice)。我尽力尝试捕获这个,但没有成功。 - dermoritz
1
你说得对,似乎在匆忙中我错过了一些东西,很抱歉。看起来这就是你正在寻找的答案。[链接]https://dev59.com/53E85IYBdhLWcg3wPA98 还需要添加权限 <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> - Yash Krishnan
@YashwanthKrishnan:嘿,我应该设置什么优先级,以便媒体按钮键事件被我们的应用程序接收,而不是默认音乐播放器?即使我的应用程序在前台,音乐播放器仍然会接收键事件并播放,我已将其设置为10000,但仍然没有成功。 - Mahantesh M Ambi
根据 https://developer.android.com/guide/topics/manifest/intent-filter-element.html ,优先级必须大于-1000且小于1000。 - juanlugm

2

请查看这篇文章,它解释了如何使用媒体按钮操作实现类似的功能。

我知道你曾经尝试过这种方法但没有成功,还是试一下吧。注意与注册广播接收器、设置意图过滤器优先级和添加权限有关的问题(在文章中都有解释)。

希望这能帮到你。


谢谢 - 我会尝试的。如果这有效,你将获得奖励。 - dermoritz
我尝试过了,但它不起作用:问题在于这会捕获意图(音量更改或媒体按钮),但是所有其他音量按钮也会发送此意图,并且由所有其他已注册到该事件的活动处理。我想捕获事件并“消耗”它 - 就像“onKeyDown”对HW键所做的那样。 - dermoritz
@dermoritz 你确定在你的广播接收器中调用了 abortBroadcast 吗? - Eugene Loy
我刚试了一下:音量更改似乎是一个“无序广播” - abortBroadcast()对其不起作用。而耳机上的另一个按钮(用于语音命令)根本无法捕获。我尝试添加各种操作,如“android.intent.action.VOICE_COMMAND”和“android.speech.action.RECOGNIZE_SPEECH”,但我的操作没有反应 - 总是启动手机内置的“s-voice”。 - dermoritz
1
@dermoritz 我有一个想法,严格来说不是你问题的答案,但可能会帮助你最终找到解决方案。看看这个应用程序:https://play.google.com/store/apps/details?id=com.kin.bluetooth_launch。它说它可以与大多数蓝牙耳机配对(至少是遵守标准的)。如果它适用于你的情况,你可以尝试询问作者/查找来源或反向工程它,以了解它是如何解决的。如果需要,我实际上可以帮助你进行反向工程部分(之前做过类似的事情)。 - Eugene Loy
谢谢提示 - 我已经联系了作者。让我们看看会发生什么。 - dermoritz

1
如果您想从活动中监听此内容,请使用onKeyDown()并捕获KEYCODE_MEDIA_PLAY_PAUSE (KEYCODE_MEDIA_PLAYKEYCODE_MEDIA_PAUSE在ICS之后)键事件。此外,为了使广播接收器解决方案起作用,请确保没有其他应用程序安装并在后台运行,捕获这些事件可能会优先于您的事件。同时请参考:Android - registering a headset button click with BroadcastReceiver

谢谢 - 但是onKeyDown对于蓝牙不起作用,它仅捕获有线耳机和手机按键。而且我永远无法确定其他人正在运行或安装哪些应用程序。 - dermoritz
有趣的是,我认为它会捕获onKeyDown事件,就像这里提到的一样:https://groups.google.com/forum/#!topic/android-developers/v_7lT-o0ERg?还可以查看链接中的第二个答案。 - Vrashabh Irde
哪个版本的Android?在Jelly Bean之后可能会因为所有新的蓝牙功能而改变。 - Vrashabh Irde
最低版本为4.0,最高版本为4.2 - 我正在Galaxy S3上测试4.1版本。 - dermoritz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接