Android中MediaButtonReceiver广播监听器的机制分析(3)

通过对前面的学习,我们知道了AudioManager内部利用一个栈来管理包括加入和移除ComponentName对象,

    新的疑问来了?这个MEDIA_BUTTON广播是如何分发的呢 ?

 
         其实,AudioService.java文件中也存在这么一个MediaoButtonReceiver的广播类,它为系统广播接收器,即用来接收

  系统的MEDIA_BUTTON广播,当它接收到了这个MEDIA_BUTTON广播   ,它会对这个广播进行进一步处理,这个处理过程

   就是我们需要的弄清楚。

MediaButtonBroadcastReceiver 内部类如下:

[java]

private class MediaButtonBroadcastReceiver extends BroadcastReceiver {       @Override       public void onReceive(Context context, Intent intent) {           //获得action ,系统MEDIA_BUTTON广播来了            String action = intent.getAction();           //action不正确 直接返回            if (!Intent.ACTION_MEDIA_BUTTON.equals(action)) {               return;           }         //获得KeyEvent对象            KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);           if (event != null) {               // if in a call or ringing, do not break the current phone app behavior                // TODO modify this to let the phone app specifically get the RC focus                //      add modify the phone app to take advantage of the new API                //来电或通话中,不做处理直接返回                if ((getMode() == AudioSystem.MODE_IN_CALL) ||(getMode() == AudioSystem.MODE_RINGTONE)) {                   return;               }               synchronized(mRCStack) {                   //栈不为空                    if (!mRCStack.empty()) {                       // create a new intent specifically aimed at the current registered listener                        //构造一个Intent对象 ,并且赋予Action和KeyEvent                        Intent targetedIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);                       targetedIntent.putExtras(intent.getExtras());                       //指定该处理Intent的对象为栈顶ComponentName对象的广播类                            targetedIntent.setComponent(mRCStack.peek().mReceiverComponent);                       // trap the current broadcast                        // 终止系统广播                             abortBroadcast();                       //Log.v(TAG, " Sending intent" + targetedIntent);                        //手动发送该广播至目标对象去处理,该广播不再是系统发送的了                            context.sendBroadcast(targetedIntent, null);                   }                   //假设栈为空,那么所有定义在AndroidManifest.xml的监听MEDIA_BUTTON的广播都会处理,                    //在此过程中如果有任何应用程注册了registerMediaButton 该广播也会立即终止                }           }       }   }  

 

 总结一下MEDIA_BUTTON广播: 

    

         AudioManager也就是AudioService服务端对象内部会利用一个栈来管理所有ComponentName对象,所有对象有且仅有一个,

   注册的ComponentName总是会位于栈顶。

         当系统发送MEDIA_BUTTON,系统MediaButtonBroadcastReceiver 监听到系统广播,它会做如下处理:

                 1、 如果栈为空,则所有注册了该Action的广播都会接受到,因为它是由系统发送的。
                 2、 如果栈不为空,那么只有栈顶的那个广播能接受到MEDIA_BUTTON的广播,手动发送了MEDIA_BUTTON

                      广播,并且指定了目标对象(栈顶对象)去处理该MEDIA_BUTTON 。

 下面分析一下KeyEvent对象里的KeyCode按键,可能的按键码有:


       1、KeyEvent.KEYCODE_MEDIA_NEXT
       2、KeyEvent.KEYCODE_HEADSETHOOK
       3、KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE(已废除,等同于KEYCODE_HEADSETHOOK)
       4、KeyEvent.KEYCODE_MEDIA_PREVIOUS
       5、KeyEvent.KEYCODE_MEDIA_STOP
   
    PS : 在我的真机测试中,按下MEDIA_BUTTON只有KEYCODE_HEADSETHOOK可以打印出来了。

下面给出一个小DEMO检验一下我们之前所做的一切,看看MEDIA_BUTTON是如何处理分发广播的。

编写两个MediaButtonReceiver类用来监听MEDIA_BUTTON广播:

  1 、China_MBReceiver.java

[java]

package com.qin.mediabutton;      import android.content.BroadcastReceiver;   import android.content.Context;   import android.content.Intent;   import android.util.Log;   import android.view.KeyEvent;      public class China_MBReceiver extends BroadcastReceiver  {          private static String TAG = "China_MBReceiver" ;       @Override       public void onReceive(Context context, Intent intent) {           //获得Action             String intentAction = intent.getAction() ;           //获得KeyEvent对象            KeyEvent keyEvent = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);                      Log.i(TAG, "Action ---->"+intentAction + "  KeyEvent----->"+keyEvent.toString());                      if(Intent.ACTION_MEDIA_BUTTON.equals(intentAction)){               //获得按键字节码                int keyCode = keyEvent.getKeyCode() ;               //按下 / 松开 按钮                int keyAction = keyEvent.getAction() ;               //获得事件的时间                long downtime = keyEvent.getEventTime();                              //获取按键码 keyCode                 StringBuilder sb = new StringBuilder();               //这些都是可能的按键码 , 打印出来用户按下的键                if(KeyEvent.KEYCODE_MEDIA_NEXT == keyCode){                   sb.append("KEYCODE_MEDIA_NEXT");               }               //说明:当我们按下MEDIA_BUTTON中间按钮时,实际出发的是 KEYCODE_HEADSETHOOK 而不是 KEYCODE_MEDIA_PLAY_PAUSE                if(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ==keyCode){                   sb.append("KEYCODE_MEDIA_PLAY_PAUSE");               }               if(KeyEvent.KEYCODE_HEADSETHOOK == keyCode){                   sb.append("KEYCODE_HEADSETHOOK");               }               if(KeyEvent.KEYCODE_MEDIA_PREVIOUS ==keyCode){                   sb.append("KEYCODE_MEDIA_PREVIOUS");               }               if(KeyEvent.KEYCODE_MEDIA_STOP ==keyCode){                   sb.append("KEYCODE_MEDIA_STOP");               }               //输出点击的按键码                Log.i(TAG, sb.toString());                          }                  }      }    

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wygggg.html