Android怎样监听蓝牙耳机的按键事件

写在前面:

直接想要代码非常easy,你直接把滚动栏拉到最底端就能够看到。假设想要十分地了解为什么,那就依照我规划的一步一步来理解。下面測试环境以手头上有的「Bluedio + 红米手机」。

1.蓝牙耳机的使用

蓝牙耳机的使用说明书中都会有相关的具体使用说明,这里拣重点说明一下。除了电源开关,耳机上一般有三个键。例如以下所看到的:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQva2FuZ2Vhcg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

它们每一个都是多功能键。在不同的情况下有不同的功能。1号键的功能包含:開始播放音乐/停止插入音乐/接听电话/挂断电话;2号键的功能有:添加音量/上一曲;3号键的功能有 减小音量/下一曲。



watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQva2FuZ2Vhcg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

注:暂不包含通话模式;其他型号蓝牙耳机并不一定全然同样。

2.蓝牙耳机上的按键实现原理

试用后会明确,一个按键会有多个功能。那么在Android系统中是怎样表示的呢?事实上对于Android系统,每次按键仅仅会有一个唯一「键值」响应。使用起来感觉会模模糊糊的,可是事实上对于系统来说是非常清晰的。

AVRCP全称(Audio/Video Remote Control Profile)。是蓝牙协议中的一个profile。从名字上就能够看出主要应用于Audio/Video控制。每一个按键并非独立的。上-曲/下一曲是在正在播放音乐的时候才会有效,即才会向Android发送「键值」。

基于按键从Linux到Android分析详细对于的键值:

Linux扫描码 功能    映射字串               Android键值

00c8 200     開始放音乐  MEDIA_PLAY          KEYCODE_MEDIA_PLAY

00c9 201     停止放音乐  MEDIA_PAUSE         KEYCODE_MEDIA_PAUSE

00a3 163        下一曲      MEDIA_NEXT          KEYCODE_MEDIA_NEXT

00a5 165        上-曲      MEDIA_PREVIOUS     KEYCODE_MEDIA_PREVIOUS

Android应用代码,完整測试应用:TeskKey

总结:1号键会交替发送KEYCODE_MEDIA_PLAY/KEYCODE_MEDIA_PAUSE;2/3号键会在播放音乐时分别发送KEYCODE_MEDIA_PREVIOUS/.KEYCODE_MEDIA_NEXT。假设想要把蓝牙耳机上的按键利用起来。能够在接收到KEYCODE_MEDIA_PLAY时播放 无声音乐 以使能2/3号键。这样就能完整接收3种键值了自行控制了。这个详细自行设计(測试代码已经更新包括了)。

注:这样的实现并不一定通用,比方我在深度定制的MIUI中測试,虽然启动的TestKey应用,系统自带的音乐播放器仍然能同一时候响应键值。

更新:

已经更新TestKey源代码,加入对蓝牙耳机按键的监听。实现方法就是上述中猜測的方法,已经成功验证过了。播放音乐參考《Android多媒体开发--资源文件播放》。效果图:

须要说明一点的是,程序带了两个音乐文件在/res/raw中,默认播放的是lapple.mp3一个有声音的mp3音乐文件,silence10sec.mp3是一个无声音的10秒钟音乐文件,实际应用中能够使用它。

问与答

1.这个仅仅能在播放音乐的状态下才干监听到么?

答:依据上述的原理,这些按键也不过应用在控制媒体时使用。且依据实际验证没有播放音乐时蓝牙耳机的2/3号键是并没有向Android设备发送键值(从底层Linux来看)。综上所述,须要通过播放音乐来实现激活其向Android设备发送键值,针对这样的情况能够播放一个「没有声音」的音乐文件来实现,这样既能够监听到2/3号键又能够不影响其他声音的输出。能够在前台时播放音乐,后台停止播放。

2.我如今主要是想监听得到开关键(1号键)。 在做一个按下蓝牙开关键后启动一个语音识别的功能?

答:在我的測试条件下,1号键是能够正常监听到的。1号键会交替发送KEYCODE_MEDIA_PLAY/KEYCODE_MEDIA_PAUSE键值。

这个键不须要模拟播放音乐就能够正常的监听到。

3. 4号按键的监听方法

答:所谓的4号按键,也就是指本文中的所測试型号的蓝牙耳机上并没有,但有可能其他型号的蓝牙耳机上有。我没有办法測试验证。所以这里就简单叙述一下「新按键」的键值确定思路:1.先使用TestKey測试应用測试按键,測试Android上层能否够得到相应键值。

2.假设没有得到,那么就使用adb shell getevent来看Linux底层能够不能够得到键值。然后依据按键从Linux到Android来确定Android上层使用的键值码究竟是多少。(当然。假设你实在不知道怎样监听,把蓝牙耳机寄给我。我给你确定也行。

:))

注:事实上上述文章全然是依据按键从Linux到Android測试确定下来的。那是篇文章是剥开Android外壳来看「按键」事件的流程的。方法适用于全部输入事件:各种按键/触摸/物理键盘/鼠标等待输入设备。没有一定的Linux开发经验非常难看懂和理解。

4. Android后台监听按键怎么实现

或:怎样启动一次应用后在后台一直监听播放键 由于有这样一个场景 在用户开车的时候需按一下开关键就启动语音识别的功能。

这个问题事实上已经超出了本文讨论的范围,是Android系统相应用层的键盘事件(按键)的分发的问题了。正常情况下。按键仅仅会向当前最端的应用分发键盘事件。也就是说在后台你边音量键都监听不了。

可是既然这样的情况(后台应用监听按键)的需求存在,那么就一定有它存在的道理。

比方「相机键」,按下后直接调出相机到最前台。从表面上看是相机响应了按键,可是从实现方法上来看,并非通过键值来操作。必须通过其他方法,比方广播或者其他等等。

明确了当中的道理后。那么想要实现就好办了。先看这个按键有没有广播,如要有接听系统中发出来的广播;假设没有那么对于定制系统能够自己在系统中加入一个广播。总之,正常渠道是没有办法在后台监听一些不应该是你监听到的按键的。

更:查了一下。这个按键是有广播的。这样就能够后台响应了(不须要C/不须要root)。样例我就不试了,见Android官方样例RandomMusicPlayer

当中的重点是这个广播android.intent.action.MEDIA_BUTTON。

   20141029更:

本来不想再更新那个Testkey了,好吧,我还是更新了一下。关于后台监听媒体相关按键的方法。没有在界面上更新。通过LogCat查看信息打印。

上述内容算「」,下边把「」也提供了:

第一步先直接编译执行RandomMusicPlayer,然后发现确实不能收到广播。然后推断是系统版本号问题,有可能是RandomMusicPlayer并没有更新为适合4.0以上的。

Capture media button on Android >=4.0 (works on 2.3)这里找到了问题所在。加入之成功。然后整合到Testkey上。详细改了哪些内容通过Github上的commit id查看。

20150108更:

关于測试程序的源代码,是托管在Github上的。文中找到"TestKey"链接,打开后例如以下图下载:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQva2FuZ2Vhcg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

APK下载

更新源代码,加入编译好的APK文件。

直接下载地址:https://github.com/kangear/TestKey/raw/master/apk/TestKey.apk

20150109更:

已经root的Android设备获取键值方法

假设设备已经root过了,那么能够更底层地获取键值。

1.下载终端模拟器http://shouji.baidu.com/soft/item?

docid=7309820

2.执行su -c getevent 然后按下须要測试的按键 注:su -c getevent中间有空格.

3.会有例如以下输出,当中每次按下后输出数据的倒数第二行 倒数第二个是该按键的原始键值

4.将此键值告知我,我来推断怎样实现对应功能

注:

1.该命令会监听全部输入事件 触摸屏/按键/蓝牙耳机/鼠标键盘 都会检測到,所以输出命令后不要再点击触摸屏 不然会有大量输出.

2.普通情况下每次按键会输出4行信息.

3.下图最后输出4行是按下 Vol- 的输出.假设你的測试没有达到这个效果,要自行去对照哪里出现了问题.

4.下面监听蓝牙按键的实例

20150112更:

哪些键值会是蓝牙传递过来的

1. 连接蓝牙后,假设直接按下蓝牙耳机上的某个键,你的手机会自己主动播放音乐,那么说明是该键值是从蓝牙耳机传递过来的.

2. 播放音乐后,假设能够只通过蓝牙耳机上的某个键,你的手机会切换音乐,那么说明是该键值是从蓝牙耳机传递过来的.

3. 播放音乐时,假设能够只通过蓝牙耳机上的某个键,你的手机屏幕上显示增大或者减小音量,那么说明该键值是从蓝牙耳机传递过来的.反之假设不过蓝牙耳机内部音量进行了改变,Android没有不论什么的反应,那么说明该按键唯独控制蓝牙耳机音量的功能,并没有向Android上报键值.

4. 连接蓝牙通话,假设通过按下某个键,能够挂断电话,那么说明该按键是从蓝牙耳机传递过来的.

案例:

a.某个4.0版本号协议的蓝牙耳机更注重省电,在控制音量时仅仅是自身喇叭音量增大或者减小,并非向Android系统报告须要增大或者减小音量的,那么说明这个按键根本从来就没有向Android报告过键值.(无按键上传)

b.某些型号的蓝牙耳机,本身不控制音量,当按下按下音量键时,会将键值传递给Android设备,要求Android进行增大或者减小音频源的音量 来实现音量的控制.(有按键上传)

以上两种情况,尽管用户体验是并无太大区别,可是实现原理极为不同的.

补充知识:

播放音量/音频通话是蓝牙耳机中两个不同的规范,普通情况下都会同一时候支持,可是有时候会只支持后者(也称 单声道蓝牙耳机),为的是更省电.当然也会进一步压缩一些功能.

20150113更 单通道耳机不能使用上述方法检測按键分析

蓝牙标准规范列表:https://en.wikipedia.org/wiki/List_of_Bluetooth_profiles

这里说明几个经常使用的规范:(规范也能够理解为通道)

1._正常_播放音乐

2._正常_播放音乐时按键

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQva2FuZ2Vhcg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

3.语音通话/以及语音通话时按键

注:对于单声道耳机(默认仅仅能接听电话)通过某些软件实现的播放音乐的原理是将「音乐的信号」通过「语音通话通道」传输给耳机的。耳机实质还是工作在「语音通话」模式下。

说一千道一万,对于第三种情况下的非按键的按键怎样检測,且听下回分解。

;)

这里简单猜測一下原理。第3种情况下"按键"是被包含在通话语音信号中的,应该是直接被Phone应用解析并进行了对应操作。Android4.2以上的版本号中会有一个内置的无界面的应用程序名字叫Bluetooth.apk,它是Android系统对中蓝牙设备支持的核心,全部的规范(profile)都是通过它来解析的。所以要研究一下它和Phone应用之间做了什么见不得人的勾当才干知道怎样。 ;)

当然简单一点,也能够通过监听音量变化也实现曲线监听等等,只是这个不是我研究的重点。

另外一点是 对于单声道耳机按键研究 眼下也仅仅能是挖的一个坑。什么时候埋临时不好说。

先写到这里 (语音通话时“按键”处理过程)

文字描写叙述:已经找到处理过程。和猜測的一致。Bluetooth解析出特定的“按键”后直接进行处理。没有向外界通知什么。依据高亮的英文也能猜測出含意。第一张图是语音通话时的各种“按键”事件。第二张图是对“拨号/重拨”键的处理。高亮出是重拨时获取通话记录中最后一个号码。

假设能够訪问Google那么你也能够直接在线查看我截图的这两段代码片段。HeadsetStateMachine.java(另:我是基于4.2.2分析的),这是简单的分析过程,对于怎样在APP中监听,下回再说。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQva2FuZ2Vhcg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

语音通话相关參考文档:

1.GSM 07.07_V5.0.pdf

2. Bluetooth.apk源代码 hfp

时间: 07-11

Android怎样监听蓝牙耳机的按键事件的相关文章

Android App监听软键盘按键的三种方式(转)

最近有类似需求,在csdn上刚好发现,粘贴过来,以防止忘记喽 前言: 我们在android手机上面有时候会遇到监听手机软键盘按键的时候,例如:我们在浏览器输入url完毕后可以点击软键盘右下角的“GO”按键加载url页面:在点击搜索框的时候,点击右下角的search符号键可以进行搜索:或者在全部数据输入完毕后,点击右下角的"done"就马上进行下一步操作. 效果图: function 1: 重写Activity的dispatchKeyEvent(KeyEvent event)方法,在其中

Android App监听软键盘按键的三种方式

前言: 我们在android手机上面有时候会遇到监听手机软键盘按键的时候,例如:我们在浏览器输入url完毕后可以点击软键盘右下角的"GO"按键加载url页面:在点击搜索框的时候,点击右下角的search符号键可以进行搜索:或者在全部数据输入完毕后,点击右下角的"done"就马上进行下一步操作. 效果图: function 1: 重写Activity的dispatchKeyEvent(KeyEvent event)方法,在其中监听KeyEventKey.KEYCODE

监听按钮点击事件的三种方式实现及调试信息输出的三种方式实现

监听按钮点击事件的三种方式实现: 1.匿名内部类 2.外部独立类 3.接口实现 package com.example.button; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View;

键盘-App监听软键盘按键的三种方式

前言: 我们在android手机上面有时候会遇到监听手机软键盘按键的时候,例如:我们在浏览器输入url完毕后可以点击软键盘右下角的“GO”按键加载url页面:在点击搜索框的时候,点击右下角的search符号键可以进行搜索:或者在全部数据输入完毕后,点击右下角的"done"就马上进行下一步操作. 效果图: function 1: 重写Activity的dispatchKeyEvent(KeyEvent event)方法,在其中监听KeyEventKey.KEYCODE_ENTER键(右下

Android 监听 Android中监听系统网络连接打开或者关闭的实现代码

本篇文章对Android中监听系统网络连接打开或者关闭的实现用实例进行了介绍.需要的朋友参考下 很简单,所以直接看代码 复制代码 代码如下: package xxx; import android.content.BroadcastReceiver;  import android.content.Context;  import android.content.Intent;  import android.net.ConnectivityManager;  import android.ne

复选框 省市区 联动(监听input的change事件)

需求:省市区三级包含复选框按钮以及文字描述.点击文字显示对应的下级地区,点击复选框选择对应的下级区域勾选. 分析:监听input的change事件当点击复选框省  选择对应的第一个市区,同时默认选中第三级区域的第一个.同理监听span或者label(因为label与input的搭配使用) 辅助:后台提供省市区的数据: 两种方式: A:后台直接给dom结构(后台写好基本构架,前段自己在后台code填写需要的dom,class,方便前端开发) B:后台直接给前段一个json数据,前段自己遍历.(和后

vue使用element-ui的el-input监听不了键盘事件解决

vue使用element-ui的el-input监听不了键盘事件,原因应该是element-ui自身封装了一层div在input标签外面,把原来的事件隐藏了,所以如下代码运行是无响应的: <el-input v-model="name" placeholder="账号" @keyup.enter="doLogin"></el-input> 在执行的时候事件是定义在input外面的div上的,所有没有响应. 解决方法需要在事

Android之——监听手机开机事件

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/47028535 本文中,主要通过监听开机广播来达到监听手机开机状态的操作,在Android中可以通过广播机制来监听一些系统服务和系统级的操作,好了,不多说,直接上代码吧 1.创建广播接收者类BootCompleteReceiver 这个类中的回调方法是手机开机后自动调用,我在这里只是打印出相关日志,具体的业务逻辑大家可以自己根据自己的具体需求去实现. 代码如下: package c

android editText 监听事件

在软键盘中注意 在监听的 edittext中 使用android:imeOptions属性的时候,一定要对EditText设置 android:inputType 或者 设置 android:singleline="true" 在activity_main.xml文件中,定义了8个EditText,imeOptions分别是: actionDone 完成 对应 EditorInfo.IME_ACTION_DONE actionGo 前进 对应 EditorInfo.IME_ACTION