今天在研究Android中实现Android 4.2.2源码中的Music应用的源码,关于通过耳机按键控制音乐播放的实现,有点好奇,就仔细分析了一下源码,

主要由MediaButtonIntentReceiver 这个类来实现。


在AndroidManifest.xml中有如下Receiver的注册:

        <receiver android:name="com.huawei.imax.music.MediaButtonIntentReceiver" >            <intent-filter>                <action android:name="android.intent.action.MEDIA_BUTTON" />                <action android:name="android.media.AUDIO_BECOMING_NOISY" />            </intent-filter>        </receiver>


其实关键是对这两个ACTION的监控:

android.intent.action.MEDIA_BUTTON的说明如下,从注释看,就是媒体按键被按下后,通过Intent.EXTRA_KEY_EVENT 中带上触发此事件的具体按钮事件

   /**     * Broadcast Action:  The "Media Button" was pressed.  Includes a single     * extra field, {@link #EXTRA_KEY_EVENT}, containing the key event that     * caused the broadcast.     */    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)    public static final String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON";


android.intent.action.AUDIO_BECOMING_NOISY的说明如下(自己翻译的,大概这个意思),

从注释看,当音频变得“吵闹”,比如耳机拔出,或者A2DP音频通道(比如通过蓝牙音箱播放音乐就是一种A2DP的应用场景)断开,

音频系统将会自动将音频转到自带的

    /**     * Broadcast intent, a hint for applications that audio is about to become     * 'noisy' due to a change in audio outputs. For example, this intent may     * be sent when a wired headset is unplugged, or when an A2DP audio     * sink is disconnected, and the audio system is about to automatically     * switch audio route to the speaker. Applications that are controlling     * audio streams may consider pausing, reducing volume or some other action     * on receipt of this intent so as not to surprise the user with audio     * from the speaker.     */    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)    public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";


MediaButtonIntentReceiver 的关键实现如下:

public class MediaButtonIntentReceiver extends BroadcastReceiver{    ...        @Override    public void onReceive(Context context, Intent intent)    {        String intentAction = intent.getAction();        if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intentAction))        {            Intent i = new Intent(context, MediaPlaybackService.class);            i.setAction(MediaPlaybackService.SERVICECMD);            i.putExtra(MediaPlaybackService.CMDNAME,                    MediaPlaybackService.CMDPAUSE);            context.startService(i);        }        else if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction))        {            KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);                        if (event == null)            {                return;            }                        int keycode = event.getKeyCode();            int action = event.getAction();            long eventtime = event.getEventTime();                        // single quick press: pause/resume.             // double press: next track            // long press: start auto-shuffle mode.                        String command = null;            switch (keycode)            {                case KeyEvent.KEYCODE_MEDIA_STOP:                    command = MediaPlaybackService.CMDSTOP;                    break;                case KeyEvent.KEYCODE_HEADSETHOOK:                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:                    command = MediaPlaybackService.CMDTOGGLEPAUSE;                    break;                case KeyEvent.KEYCODE_MEDIA_NEXT:                    command = MediaPlaybackService.CMDNEXT;                    break;                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:                    command = MediaPlaybackService.CMDPREVIOUS;                    break;                case KeyEvent.KEYCODE_MEDIA_PAUSE:                    command = MediaPlaybackService.CMDPAUSE;                    break;                case KeyEvent.KEYCODE_MEDIA_PLAY:                    command = MediaPlaybackService.CMDPLAY;                    break;            }


通过接收此事件的广播,想进行什么操作,完全看你的业务需求了。


一开始以为耳机插拔,是通过ACTION_HEADSET_PLUG这个Action来控制,但Music并没有监听此事件,

    /**     * Broadcast Action: Wired Headset plugged in or unplugged.     *     * <p>The intent will have the following extra values:     * <ul>     *   <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>     *   <li><em>name</em> - Headset type, human readable string </li>     *   <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li>     * </ul>     * </ul>     */    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)    public static final String ACTION_HEADSET_PLUG =            "android.intent.action.HEADSET_PLUG";

自己测试了一下,在AndroidManifest.xml中静态注册,是不会生效的,为啥?

一个很简单的解释,如果你的应用还没有运行,这时插入耳机,系统如何把这个消息给这个应用?

因此,"android.intent.action.HEADSET_PLUG"只能通过动态注册来接收此广播消息。


如果让MediaButtonIntentReceiver 还接收"android.intent.action.HEADSET_PLUG"的广播消息,

则MediaButtonIntentReceiver会先收到"android.media.AUDIO_BECOMING_NOISY" 这个消息,然后才会收到"android.intent.action.HEADSET_PLUG"这个消息?

为什么这样,代码层面还没有分析,后面抽空再研究下Android源码。


更多相关文章

  1. Hello World
  2. 使用Python开发Android应用程序:第一节 在手机上配置Python运行环
  3. Android(安卓)神兵利器Dagger2使用详解(四)Scope注解的使用及源码
  4. 【Android】Android(安卓)4.2源码下载(ubuntu 12.10)
  5. Android常用代码之普通及系统权限静默安装APK
  6. Android必备:Android应用程序组成
  7. Android(安卓)体系结构介绍
  8. 【Android(安卓)应用开发】Android资源文件 - 使用资源存储字符
  9. Android--应用开发3(Android(安卓)layout XML属性)

随机推荐

  1. Android(安卓)-- The Manifest File
  2. android代码库之执行Shell命令或者脚本
  3. Android中Activity组件详解
  4. Android(安卓)EditText截获与监听输入事
  5. Android(安卓)图片大小超过预算的VM:java.
  6. Android(安卓)TimeUtil
  7. android ACTION_BOOT_COMPLETED接收不到
  8. android初学者的探索之路(Android音乐播放
  9. 高仿大众点评商家列表
  10. 介绍几本初学Android资料和教材——选对