转载请注明出处: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耳机线控详解,蓝牙耳机按钮监听(仿酷狗线控效果)相关推荐

  1. android 回退函数,详解React Native监听Android回退按键与程序化退出应用

    详解React Native监听Android回退按键与程序化退出应用 发布时间:2020-09-29 09:25:52 来源:脚本之家 阅读:137 作者:lqh 详解React Native监听A ...

  2. 回退监听android,详解React Native监听Android回退按键与程序化退出应用

    详解React Native监听Android回退按键与程序化退出应用 前言 我们知道Android回退按键,会控制页面返回, 并且退出应用并非真正意义退出,仍在后台运行,所以在某些场景下需要监控an ...

  3. iptables防火墙详解及使用layer7阻止qq,酷狗,等P2P软件

    iptables防火墙详解及使用layer7阻止qq,酷狗,等P2P软件   防火墙其实就是一个加固主机或者网络安全的一个设备或者软件而已,通过防火墙可以隔离风险区域与安全区域的连接,同时不会妨碍风险 ...

  4. Android插件化开发指南——实践之Activity转场效果(仿酷狗音乐启动页)

    文章目录 1. 前言 2. Activity退出动画 2.1 简单使用 2.2 overridePendingTransition 3. 后记 1. 前言 在Android插件化开发指南--2.15 ...

  5. android酷狗下拉,Android 仿酷狗滑动控件实现 流畅运行

    最近又浏览了一遍github上的开源项目,有感于大神们的强大,所以想搞搞像kugou那样左右滑动的侧滑菜单控件. 打开移动设备的kugou软件,看了下整体效果,就知道了,我们要实现一个左侧主页,右侧菜 ...

  6. 【iOS-Cocos2d游戏开发之五】【1】多触点与触屏事件详解(单一监听、事件分发)...

    本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/iphone-cocos2d/450.html ...

  7. 【iOS-Cocos2d游戏开发之五】多触点与触屏事件详解(单一监听、事件分发)

    李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/iphone-cocos2d/450.html------- ...

  8. 【iOS-Cocos2d游戏开发之五】【2】多触点与触屏事件详解(单一监听、事件分发)...

    那么大概介绍了监听事件后,那么触屏中最关心的就应该是多触点啦: //-----获取多点触摸 NSSet *allTouches = [event allTouches]; UITouch *touch ...

  9. android layout_width 属性,android:layout_weight属性详解

    在android开发中LinearLayout很常用,LinearLayout的内控件的android:layout_weight在某些场景显得非常重要,比如我们需要按比例显示.android并没用提 ...

最新文章

  1. html5日期不联动下拉框,下拉框联动问题 赋值时候失效
  2. ubuntu建立向windows一样的快捷方式
  3. 没有足够的值_元丰通宝值多少钱吗?市场价值如何?有没有足够的收藏空间?...
  4. Struts2.3.4.1 + Spring3.1.2 + Hibernate4.1.6整合
  5. Your Potential. Our Passion
  6. 量子计算机迷宫,工程杰作诞生可编程的光学量子计算机
  7. mysql优化表空间_MySQL 优化笔记
  8. vue树形权限菜单_Vue.js 递归组件实现树形菜单(实例分享)
  9. 九度oj 题目1028:继续畅通工程
  10. 设置EntityFramework中decimal类型数据精度
  11. onfigure: error: cannot find install-sh, install.sh, or shtool in
  12. python 直方图的绘制方法全解_5种方法教你用Python玩转histogram直方图
  13. Tomcat7与Tomcat8的差异详细对比
  14. 简单计算器代码(含加减乘除取余5个操作)
  15. java摄像头_Java实现 海康摄像头抓拍图像
  16. 基于JAVA健康生活网站计算机毕业设计源码+系统+mysql数据库+lw文档+部署
  17. Arno,第一个NFV开源平台
  18. 解决click事件在移动端操作延迟300ms问题和点击时穿透问题
  19. 2021 年 8 月全国程序员薪酬出炉:北京18904元位居榜首
  20. php角colspan=,PHPWord生成word实现table合并(colspan和rowspan)

热门文章

  1. 二级建造师和一级建造师考试到底难不难和考什么
  2. unity 图片变纯色填充 变色
  3. 员工管理 Mybatis-Plus的分页插件
  4. aspmaker学习手记
  5. python中reversed用法_Python中reversed函数有哪些功能呢?
  6. 【2022省选模拟】麻烦的杂货店——线段树
  7. 操作系统--文件管理知识整理(学秃liao)
  8. 程序员招募接私活 ,外包众包接单方法‘
  9. c语言变量定义位置区别,C语言中变量定义的位置(C89和C99的区别)
  10. 013 Dealing with Label Quality Disparity in Federated Learning(联邦学习中标签质量差异的处理)