ndroid如何監聽藍牙耳機的按鍵事件
寫在前面:
直接想要代碼很簡單,你直接把滾動條拉到最底端就可以看到。如果想要十分地了解為什么,那就按照我規划的一步一步來理解。以下測試環境以手頭上有的「Bluedio + 紅米手機」。
1.藍牙耳機的使用
藍牙耳機的使用說明書中都會有相關的詳細使用說明,這里揀重點說明一下。除了電源開關,耳機上一般有三個鍵。如下所示:
它們每個都是多功能鍵,在不同的情況下有不同的功能。1號鍵的功能包括:開始播放音樂/停止插入音樂/接聽電話/掛斷電話;2號鍵的功能有:增加音量/上一曲;3號鍵的功能有 減小音量/下一曲。

注:暫不包括通話模式;其它型號藍牙耳機並不一定完全相同。
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"鏈接,打開后如下圖下載:
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._正常_播放音樂時按鍵
3.語音通話/以及語音通話時按鍵
注:對於單聲道耳機(默認只能接聽電話)通過某些軟件實現的播放音樂的原理是將「音樂的信號」通過「語音通話通道」傳輸給耳機的。耳機實質還是工作在「語音通話」模式下。
說一千道一萬,對於第三種情況下的非按鍵的按鍵如何檢測,且聽下回分解。;)
這里簡單推測一下原理,第3種情況下"按鍵"是被包括在通話語音信號中的,應該是直接被Phone應用解析並進行了相應操作。Android4.2以上的版本中會有一個內置的無界面的應用程序名字叫Bluetooth.apk,它是Android系統對中藍牙設備支持的核心,所有的規范(profile)都是通過它來解析的。所以要研究一下它和Phone應用之間做了什么見不得人的勾當才能知道如何。 ;)
當然簡單一點,也可以通過監聽音量變化也實現曲線監聽等等,不過這個不是我研究的重點。
另外一點是 對於單聲道耳機按鍵研究 目前也只能是挖的一個坑。什么時候埋暫時不好說。
先寫到這里 (語音通話時“按鍵”處理過程)
文字描述:已經找到處理過程,和推測的一致。Bluetooth解析出特定的“按鍵”后直接進行處理,沒有向外界通知什么。根據高亮的英文也能猜測出含意。第一張圖是語音通話時的各種“按鍵”事件,第二張圖是對“撥號/重撥”鍵的處理。高亮出是重撥時獲取通話記錄中最后一個號碼。如果可以訪問Google那么你也可以直接在線查看我截圖的這兩段代碼片段。HeadsetStateMachine.java(另:我是基於4.2.2分析的),這是簡單的分析過程,對於如何在APP中監聽,下回再說。
語音通話相關參考文檔:
1.GSM 07.07_V5.0.pdf
2. Bluetooth.apk源碼 hfp