標籤:android線控 audiomanager 耳機按鍵 mediabuttonreceiver 耳機按鍵監聽
轉載請註明出處:http://blog.csdn.net/fengyuzhengfan/article/details/46461253
當耳機的媒體按鍵被單擊後,Android系統會發出一個廣播,該廣播的攜帶者一個Action名為MEDIA_BUTTON的Intent。監聽該廣播便可以擷取手機的耳機媒體按鍵的單擊事件。
在Android中有個AudioManager類,該類會維護MEDIA_BUTTON廣播的分發,所以要實現耳機按鍵監聽需要向AudioManager註冊一個用於接收耳機按鍵單擊事件的接收器:
AudioManager audioManager = (AudioManager)context .getSystemService(Context.AUDIO_SERVICE);ComponentName name = newComponentName(context.getPackageName(), MediaButtonReceiver.class.getName());audioManager.registerMediaButtonEventReceiver(name);
該方法的原型為:
publicvoid registerMediaButtonEventReceiver (PendingIntent eventReceiver)
Added in API level 18
Registera component to be the sole receiver of MEDIA_BUTTON intents. This is like registerMediaButtonEventReceiver(android.content.ComponentName), but allows the buttons to go to any PendingIntent. Note that you shouldonly use this form if you know you will continue running for the full timeuntil unregistering the PendingIntent.
Parameters
eventReceiver |
target that will receive media button intents. The PendingIntent will be sent an ACTION_MEDIA_BUTTON event when a media button action occurs, with EXTRA_KEY_EVENT added and holding the key code of the media button that was pressed. |
從API注釋中可知:
1、 在AudioManager對象註冊一個MediaoButtonRecevie,使它成為MEDIA_BUTTON的唯一接收器,也就是說只有我能收到,其他的都收不到這個廣播了,否則的話大家都收到會照成一定的混亂;
2、該廣播必須在AndroidManifest.xml檔案中進行聲明,否則就監聽不到該MEDIA_BUTTON廣播了。
注,因為當我們註冊了AudioManager媒體按鍵的接收器,並且該接收器是媒體按鍵的唯一接收器,所以要在不使用按鍵監聽的時候取消該註冊:
AudioManager audioManager = (AudioManager)context .getSystemService(Context.AUDIO_SERVICE);ComponentName name = newComponentName(context.getPackageName(), MediaButtonReceiver.class.getName());audioManager.unregisterMediaButtonEventReceiver(name);
當耳機媒體鍵發生單擊事件的時候Android系統會發出兩次廣播,第一次是按鍵按下去的時候,第二次是鬆開按鍵的時候,為了能夠準確的獲知使用者單擊了幾次媒體鍵,我們只需要在按鍵鬆開的時候處理單擊事件即可:
KeyEvent keyEvent = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); //獲得KeyEvent對象if(keyEvent.getAction()== KeyEvent.ACTION_UP){//在這裡處理單擊事件}
下面就分別講解一下為了實現線控效果所用到的幾個類:
1. 耳機線控管理工具類HeadSetUtil:
package com.jph.lc;import android.content.ComponentName;import android.content.Context;import android.media.AudioManager;import android.util.Log;/** * 耳機線控管理工具類 單例 * @author JPH * @date 2015-6-9 下午4:03:45 */public class HeadSetUtil {private static HeadSetUtil headSetUtil;private OnHeadSetListener headSetListener = null;public static HeadSetUtil getInstance() {if (headSetUtil == null) {headSetUtil = new HeadSetUtil();}return headSetUtil;}/** * 設定耳機單擊雙擊監聽介面 必須在open前設定此介面,否則設定無效 * @param headSetListener */public void setOnHeadSetListener(OnHeadSetListener headSetListener) {this.headSetListener = headSetListener;}/** * 為MEDIA_BUTTON 意圖註冊接收器(註冊開啟耳機線控監聽, 請務必在設定介面監聽之後再調用此方法,否則介面無效) * @param context */public void open(Context context) {if(headSetListener==null){throw new IllegalStateException("please set headSetListener");}AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);ComponentName name = new ComponentName(context.getPackageName(),MediaButtonReceiver.class.getName());audioManager.registerMediaButtonEventReceiver(name);Log.i("ksdinf", "open");}/** * 關閉耳機線控監聽 * @param context */public void close(Context context) {AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);ComponentName name = new ComponentName(context.getPackageName(),MediaButtonReceiver.class.getName());audioManager.unregisterMediaButtonEventReceiver(name);}/** * 刪除耳機單機雙擊監聽介面 */public void delHeadSetListener() {this.headSetListener = null;}/** * 擷取耳機單擊雙擊介面 * * @return */protected OnHeadSetListener getOnHeadSetListener() {return headSetListener;}/** * 耳機按鈕單雙擊監聽 */public interface OnHeadSetListener {/** * 單擊觸發,主線程。 此介面真正觸發是在單擊操作1秒後 因為需要判斷1秒內是否仍監聽到點擊,有的話那就是雙擊了 */public void onClick();/** * 雙擊觸發,此介面在主線程,可以放心使用 */public void onDoubleClick();/** * 三連擊 */public void onThreeClick();}} 該類主要負責媒體按鍵接收器的註冊和自訂媒體按鍵回調監聽器的設定。該類中包含一個OnHeadSetListener介面,該介面中的onClick(),onDoubleClick(),onThreeClick()三個方法分別會在單擊事件,雙擊事件,以及三連擊事件發生時被回調。需要指出的是,單擊和雙擊事件會有1秒的延遲,這是因為在這1秒內需要監聽是否還有單擊發生的原因,當然這1s也不是絕對的,你也可以根據實際的業務需要自訂事件。在下面講解的這個類中將會解開酷狗線控的原理。
2.耳機媒體按鍵廣播接收器MediaButtonReceiver:
package com.jph.lc;import java.util.Timer;import java.util.TimerTask;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.os.Handler;import android.os.Message;import android.util.Log;import android.view.KeyEvent;import com.jph.lc.HeadSetUtil.OnHeadSetListener;/** * MEDIA_BUTTON耳機媒體按鍵廣播接收器 * @author JPH * @Date2015-6-9 下午8:35:40 */public class MediaButtonReceiver extends BroadcastReceiver{private Timer timer = null;private OnHeadSetListener headSetListener = null;private static MTask myTimer = null;/**單擊次數**/private static int clickCount;public MediaButtonReceiver(){timer = new Timer(true);this.headSetListener = HeadSetUtil.getInstance().getOnHeadSetListener();}@Overridepublic void onReceive(Context context, Intent intent) {Log.i("ksdinf", "onReceive"); String intentAction = intent.getAction() ; if(Intent.ACTION_MEDIA_BUTTON.equals(intentAction)){ KeyEvent keyEvent = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); //獲得KeyEvent對象 if(headSetListener != null){ try { if(keyEvent.getAction() == KeyEvent.ACTION_UP){ if (clickCount==0) {//單擊 clickCount++; myTimer = new MTask(); timer.schedule(myTimer,1000);}else if (clickCount==1) {//雙擊clickCount++;}else if (clickCount==2) {//三連擊clickCount=0;myTimer.cancel();headSetListener.onThreeClick();} }} catch (Exception e) {} } } abortBroadcast();//終止廣播(不讓別的程式收到此廣播,免受幹擾) }/** * 定時器,用於延遲1秒,判斷是否會發生雙擊和三連擊 */class MTask extends TimerTask{@Overridepublic void run() {try {if (clickCount==1) {mhHandler.sendEmptyMessage(1);}else if (clickCount==2) {mhHandler.sendEmptyMessage(2);}clickCount=0;} catch (Exception e) {// TODO: handle exception}}};/** * 此handle的目的主要是為了將介面在主線程中觸發 * ,為了安全起見把介面放到主線程觸發 */Handler mhHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);if(msg.what==1){//單擊headSetListener.onClick();}else if (msg.what==2) {//雙擊headSetListener.onDoubleClick();}else if (msg.what==3) {//三連擊headSetListener.onThreeClick();}}};} 該類主要負責接收系統發出的媒體案例的單擊事件,並對單擊事件做相應的處理以達到單擊,雙擊,三連擊的效果。需要指出的是該類在執行個體化的時候會擷取OnHeadSetListener監聽器,所以要在調用HeadSetUtil類的open方法用之前設定OnHeadSetListener,否則將不會對媒體按鍵事件做處理。
該類中有個名為Mtask的內部類,該內部類是一個定時任務,該任務會在指定的時間裡分析是否會發生雙擊和三連擊。
另外,該類中還有一個myHandler對象,該對象是為了將回調監聽發生在UI線程中,以方便UI的更新。
3.監聽器的使用類MainActivity:
package com.jph.lc;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.widget.TextView;import com.jph.lc.HeadSetUtil.OnHeadSetListener;/** * 耳機線控執行個體,藍芽耳機按鈕監聽(仿酷狗線控效果) * @author JPH * @Date2015-6-10 上午9:49:02 */public class MainActivity extends Activity {TextView txt = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);txt = (TextView) findViewById(R.id.text);HeadSetUtil.getInstance().setOnHeadSetListener(headSetListener);HeadSetUtil.getInstance().open(this);}@Overrideprotected void onDestroy() {super.onDestroy();HeadSetUtil.getInstance().close(this);}OnHeadSetListener headSetListener = new OnHeadSetListener() {@Overridepublic void onDoubleClick() {txt.setText("雙擊");Log.i("ksdinf", "雙擊");}@Overridepublic void onClick() {txt.setText("單擊");Log.i("ksdinf", "單擊");}@Overridepublic void onThreeClick() {txt.setText("三連擊");Log.i("ksdinf", "三連擊");}};}
該類中舉要介紹了媒體按鍵監聽的使用。
源碼下載:http://download.csdn.net/detail/fengyuzhengfan/8797357
GitHub:https://github.com/crazycodeboy/HeadSetControl
Android耳機線控詳解,藍芽耳機按鈕監聽(仿酷狗線控效果)