线控耳机监听

当耳机的媒体按键被单击后,Android系统会发出一个广播,该广播的携带者一个Action名为MEDIA_BUTTON的Intent。监听该广播便可以获取手机的耳机媒体按键的单击事件。

在Android中有个AudioManager类,该类会维护MEDIA_BUTTON广播的分发,所以要实现耳机按键监听需要向AudioManager注册一个用于接收耳机按键单击事件的接收器:

 

?
1
2
3
4
5
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媒体按键的接收器,并且该接收器是媒体按键的唯一接收器,所以要在不使用按键监听的时候取消该注册:

 

?
1
2
3
AudioManager audioManager = (AudioManager)context    .getSystemService(Context.AUDIO_SERVICE);
ComponentName name = newComponentName(context.getPackageName(),    MediaButtonReceiver.class.getName());
audioManager.unregisterMediaButtonEventReceiver(name);

 

当耳机媒体键发生单击事件的时候Android系统会发出两次广播,第一次是按键按下去的时候,第二次是松开按键的时候,为了能够准确的获知用户单击了几次媒体键,我们只需要在按键松开的时候处理单击事件即可:

 

?
1
2
3
4
KeyEvent keyEvent = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); //获得KeyEvent对象
if(keyEvent.getAction()== KeyEvent.ACTION_UP){
//在这里处理单击事件
}

 

下面就分别讲解一下为了实现线控效果所用到的几个类:

1. 耳机线控管理工具类HeadSetUtil:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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();
    }
    @Override
    public 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{
            @Override
            public 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(){
        @Override
        public 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:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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;
    @Override
    protected 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);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        HeadSetUtil.getInstance().close(this);
    }
    OnHeadSetListener headSetListener = new OnHeadSetListener() {
        @Override
        public void onDoubleClick() {
            txt.setText(双击);
            Log.i(ksdinf, 双击);
        }
        @Override
        public void onClick() {
            txt.setText(单击);
            Log.i(ksdinf, 单击);
        }
        @Override
        public void onThreeClick() {
            txt.setText(三连击);
            Log.i(ksdinf, 三连击);
        }
    };
}

 

该类中举要介绍了媒体按键监听的使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/387955.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

当编程语言掌握在企业手中,是生机还是危机?

2019年4月,Java的收费时代来临了! Java是由Sun微系统公司在1995年推出的编程语言,2010年Oracle收购了Sun之后,Java的所有者也就自然变成了Oracle。2019年,Oracle宣布将停止Java 8更新的免费支持,未来Java的…

sql如何处理null值_如何正确处理SQL中的NULL值

sql如何处理null值前言 (Preface) A friend who has recently started learning SQL asked me about NULL values and how to deal with them. If you are new to SQL, this guide should give you insights into a topic that can be confusing to beginners.最近开始学习SQL的…

名言警句分享

“当你想做一件事,却无能为力的时候,是最痛苦的。”基拉大和转载于:https://www.cnblogs.com/yuxijun/p/9986489.html

文字创作类App分享-简书

今天我用Mockplus做了一套简书App的原型,这是一款文字创作类的App,用户通过写文、点赞等互动行为,提高自己在社区的影响力,打造个人品牌。我运用了Mockplus基础组件、交互组件、移动组件等多个组件库,简单拖拽&#xf…

数据可视化 信息可视化_动机可视化

数据可视化 信息可视化John Snow’s map of Cholera cases near London’s Broad Street.约翰斯诺(John Snow)在伦敦宽街附近的霍乱病例地图。 John Snow, “the father of epidemiology,” is famous for his cholera maps. These maps represent so many of our aspirations …

android 接听和挂断实现方式

转载▼标签: android 接听 挂断 it 分类: android应用技巧 参考:android 来电接听和挂断 支持目前所有版本 注意:android2.3版本及以上不支持下面的自动接听方法。 (会抛异常:java.lang.Securi…

Eclipse External Tool Configration Notepad++

Location: C:\Program Files\Notepad\notepad.exe Arguments:  ${resource_loc} 转载于:https://www.cnblogs.com/rgqancy/p/9987610.html

利用延迟关联或者子查询优化超多分页场景

2019独角兽企业重金招聘Python工程师标准>>> MySQL并不是跳过offset行,而是取offsetN行,然后返回放弃前offset行,返回N行,那当offset 特别大的时候,效率就非常的低下,要么控制返回的总页数&…

客户流失_了解客户流失

客户流失Big Data Analytics within a real-life example of digital music service数字音乐服务真实示例中的大数据分析 Customer churn is a key predictor of the long term success or failure of a business. It is the rate at which customers are leaving your busine…

Java 动态加载class 并反射调用方法

反射方法: public static void main(String[] args) throws Exception { File filenew File("D:/classtest");//类路径(包文件上一层) URL urlfile.toURI().toURL(); ClassLoader loadernew URLClassLoader(new URL[]{url});//创…

Nginx:Nginx limit_req limit_conn限速

简介 Nginx是一个异步框架的Web服务器,也可以用作反向代理,负载均衡器和HTTP缓存,最常用的便是Web服务器。nginx对于预防一些攻击也是很有效的,例如CC攻击,爬虫,本文将介绍限制这些攻击的方法,可…

快速数据库框架_快速学习新的数据科学概念的框架

快速数据库框架重点 (Top highlight)数据科学 (Data Science) Success in data science and software engineering depends on our ability to continuously learn new models and concepts.数据科学和软件工程的成功取决于我们不断学习新模型和概念的能力。 Both domains are…

Linux实战教学笔记12:linux三剑客之sed命令精讲

第十二节 linux三剑客之sed命令精讲 标签(空格分隔): Linux实战教学笔记-陈思齐 ---更多资料点我查看 1,前言 我们都知道,在Linux中一切皆文件,比如配置文件,日志文件,启动文件等等。…

activiti 为什么需要采用乐观锁?

乐观锁 为什么需要采用乐观锁? 由于activiti一个周期的transaction时间可能比较长,且同一流程实例中存在任务并发执行等场景。设计者将update、insert、delete事务性的操作推迟至command结束时完成,这样尽量降低锁冲突的概率,由…

Python实现三级菜单(字典和列表的使用)

menu { 北京: { 海淀: { 五道口: { soho: {}, 网易: {}, google: {} }, 中关村: { 爱奇艺: {}, 汽车之家: {}, 优酷: {} …

停止使用p = 0.05

How many of you use p0.05 as an absolute cut off? p ≥ 0.05 means not significant. No evidence. Nada. And then p < 0.05 great it’s significant. This is a crude way of using p-values, and hopefully I will convince you of this.你们中有多少人使用p 0.05作…

centos7系统根目录扩容

比如 点击了后 点击创建虚拟磁盘 选择一个 20G 然后启动虚拟机使用fdisk查看所有的磁盘 看是否新增了一个20G的硬盘 [rootlocalhost ~]# fdisk -l磁盘 /dev/sda&#xff1a;8589 MB, 8589934592 字节&#xff0c;16777216 个扇区 Units 扇区 of 1 * 512 512 bytes 扇区大小(…

instrumentation模拟很多activity的操作

android.app.Instrumentation好像原来是用来做测试的, 可以用来模拟很多activity的操作 主要代码如下 如果在文本框中输入24,或者25 点击按钮就能模拟音量加减键 键值可以查看android.view.KeyEvent [java] view plaincopy package com.qefee.testinstrumentation; import…

成像数据更好的展示_为什么更多的数据并不总是更好

成像数据更好的展示Over the past few years, there has been a growing consensus that the more data one has, the better the eventual analysis will be.在过去的几年中&#xff0c;越来越多的共识是&#xff0c;数据越多&#xff0c;最终的分析就越好。 However, just a…

支付宝架构

支付宝系统架构图如下&#xff1a; 支付宝架构文档有两个搞支付平台设计的人必须仔细揣摩的要点。 一个是账务处理。在记账方面&#xff0c;涉及到内外两个子系统&#xff0c;外部子系统是单边账&#xff0c;满足线上性能需求&#xff1b;内部子系统走复式记账&#xff0c;满足…