今天在研究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. 【Android】Android 4.2源码下载(ubuntu 12.10)
  2. Android 神兵利器Dagger2使用详解(四)Scope注解的使用及源码分析
  3. Android开发资料推荐之20个Android游戏源码!
  4. Android新增音频流类型
  5. 分享20个Android游戏源码,希望大家喜欢哈!
  6. Android 海贼王连连看游戏源码
  7. 在服务器上使用 gradle 打包 android 源码
  8. android 关于图片的放大,缩小,旋转功能的实现(附源码)
  9. 将ffmpeg编译到android 源码

随机推荐

  1. 【PPT】The new (or the first?) build s
  2. (安卓初步)TextView
  3. 调用所有的 android activity 的实现
  4. 从 App 启动过程看 Android(安卓)10.0 Fr
  5. Android permission 权限类及中英文说明
  6. Android窗口跳转
  7. 深度详解Retrofit2使用(二)实践
  8. Android binder 实例
  9. android 的几个黄色警告解决办法
  10. 判断可用的intent和更改Drawable的透明度