android中microphone耳机按ios导航条中间按钮的按钮会发出什么广播

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&转载请注明出处:
&&&&&&&&&& &在Android中并没有定义MediaButtonReceive这个广播类,MediaButtonReceive只是作为一种通俗的命名方式来响应
&& 插入耳机后,点击耳机上的按钮(名称:MEDIA_BUTTON)接受该广播事件的类。所有该MEDIA_BUTTON的按下我们就简称
&& 为MEDIA_BUTTON广播吧。
&&&&&&&&&&&
&&&&&&&&&& 顾名思义:它显然是一个广播接收器类(BroadbcastReceiver),那么它就具备了BroadbcastReceiver类的使用方式,
&& 但是,因为它需要通过AudioManager对象注册,所以它有着自己的独特之处(否则我也不会单独拿出来分析,- -),后面我们
&&&会慢慢的讲解。
&&&&&&&&点击MEDIA_BUTTON发送的Intent Action 为:
&&&&&&&&&&&&&&&&&&&&&& &ACTION_MEDIA_BUTTON& ="android.intent.action.MEDIA_BUTTON"
&&&&&&&&Intent 附加值为(Extra)点击MEDIA_BUTTON的按键码&:&&&&
&&&&&&&&&&&&&&&&&&&&&&& //获得KeyEvent对象
&&&&&&&&&&&&&&&&&&&&&&&&KeyEvent keyEvent = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
&&&&&&&&&&&&&&&&&&&&& & //获得Action
&&&&&&&&&&&&&&&&&&& &&&&String intentAction = intent.getAction() ;
AudioManager对象注册MEDIA_BUTTON广播的方法原型为:
&&&public voidregisterMediaButtonEventReceiver(eventReceiver)
&&&&&&&&& Register a component to be the&sole receiverof MEDIA_BUTTON intents
&&&&&&&&&&Parameters:&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&eventReceiver& :&identifier of a BroadcastReceiver that will receive the media button intent. This broadcast receiver
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& must be&declared in the application manifest.
&& 从注释可知以下两点:
&&&&&&1、&在AudioManager对象注册一个MediaoButtonRecevie,使它成为MEDIA_BUTTON的唯一接收器(这很重要,
&&&&&&&&&&我们会放在后面讲解)&& 也就是说只有我能收到,其他的都收不到这个广播了,否则的话大家都收到会照成一定的混乱;
&&&&& 2、& &该广播必须在AndroidManifest.xml文件中进行声明,否则就监听不到该MEDIA_BUTTON广播了。
下面我们就简单的写一个MediaButtonReceiver类,并且在AndroidManifest.xml定义
1、& 自定义的MediaButtonReceiver 广播类
package&com.qin.&&
import&android.content.BroadcastR&&
import&android.content.C&&
import&android.content.I&&
import&android.util.L&&
import&android.view.KeyE&&
public&class&MediaButtonReceiver&extends&BroadcastReceiver&{&&
&&&&private&static&String&TAG&=&"MediaButtonReceiver";&&
&&&&@Override&&
&&&&public&void&onReceive(Context&context,&Intent&intent)&{&&
&&&&&&&&&&
&&&&&&&&String&intentAction&=&intent.getAction();&&
&&&&&&&&&&
&&&&&&&&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();&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&StringBuilder&sb&=&new&StringBuilder();&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&if&(KeyEvent.KEYCODE_MEDIA_NEXT&==&keyCode)&{&&
&&&&&&&&&&&&&&&&sb.append("KEYCODE_MEDIA_NEXT");&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&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());&&
&&&&&&&&}&&
& 2、& 在AndroidManifest.xml声明我们定义的广播类。
&&receiver&android:name="MediaButtonReceiver"&&&
&&&intent-filter&&&&
&&&&&&&&&action&android:name="android.intent.action.MEDIA_BUTTON"&&/action&&&
&&&/intent-filter&&&
&/receiver&&&
&&&&&&& &在模拟器上,我们可以手动构造MEDA_BUTTON的广播,并且将它发送出去(后面会介绍)。
&&&&& && 如果有真机测试的话,按下MEDIA_BUTTON是可以接受到MEDIA_BUTTON广播的,如果没有接受到,请关闭所有应用
&& 程序,在观察效果。
& 继续我们的下一步分析:
&&&&&&&& 前面我们说明通过registerMediaButtonEventReceiver(eventReceiver)方法注册时,使它成为MEDIA_BUTTON的
&&&& 唯一&接收器。这个唯一是怎么实现的呢? 我们在源码中,一步步追本溯源,相信一定可以找到答案,知道这&唯一&是
&&& 怎么来的。
第一步、&& 为AudioManager注册一个MediaButtonReceiver() ;
AudioManager&mAudioManager&=(AudioManager)getSystemService(Context.AUDIO_SERVICE);&&&&&
ComponentName&&mbCN&=&new&ComponentName(getPackageName(),MediaButtonReceiver.class.getName());&&
mAudioManager.registerMediaButtonEventReceiver(mbCN);&&
mAudioManager.unregisterMediaButtonEventReceiver(mbCN);&&
&&&&&& &MediaButtonReceiver就是我们用来接收MEDIA_BUTTON的广播类,下面为了叙述方便和直观上得体验,我直接使用
&&&&ComponentName类来替代真正的MediaoButtonReceiver广播类。
&& 说明 接下来分析的文件路径全部在&& frameworks/base/media/java/android/media/ 下
&第二步、&进入AudioManager.java进行查看 ,发现如下方法:
public&void&registerMediaButtonEventReceiver(ComponentName&eventReceiver)&{&&
&&&&&&&IAudioService&service&=&getService();&&
&&&&&&try&{&&
&&&&&&&&&&
&&&&&&&&&&service.registerMediaButtonEventReceiver(eventReceiver);&&
&&&&&&}&catch&(RemoteException&e)&{&&
&&&&&&&&&&Log.e(TAG,&"Dead&object&in&registerMediaButtonEventReceiver"+e);&&
public&void&unregisterMediaButtonEventReceiver(ComponentName&eventReceiver)&{&&
&&&&&&IAudioService&service&=&getService();&&&&
&&&&&&try&{&&
&&&&&&&&&&
&&&&&&&&&&service.unregisterMediaButtonEventReceiver(eventReceiver);&&
&&&&&&}&catch&(RemoteException&e)&{&&
&&&&&&&&&&Log.e(TAG,&"Dead&object&in&unregisterMediaButtonEventReceiver"+e);&&
&&找到getService()方法,其实现为:
&&private&static&IAudioService&getService()&&
&&&&&&&&&&&&&&&&&
&&&&&&&&if&(sService&!=&null)&{&&
&&&&&&&&&&&&return&sS&&
&&&&&&&}&&
&&&&&&&&&&
&&&&&&&&IBinder&b&=&ServiceManager.getService(Context.AUDIO_SERVICE);&&
&&&&&&&&sService&=&IAudioService.Stub.asInterface(b);&&
&&&&&&&return&sS&&
&&&&}&&&&&&
&&&&&&&&&private&static&IAudioService&sS&&&
&&&&&&&& 我们知道了AudiaoManager只不过是一个傀儡,所有的方法都是由IAudioService 对象去实现的,通过它的构造方式,
&&可以知道它应该是有AIDL文件形成的Binder机制,&sService只是客户端对象,那么它的服务端对象在什么地方呢?
&&也就是继承了IAudioService.Stub桩的类。
第三步、接下来我们需要找到该IAudioService.aidl文件和真正的服务端对象&&
&& IAudioService.aidl定义如下:
package&android.&&
import&ponentN&&
import&android.media.IAudioFocusD&&
interface&IAudioService&{&&
&&&&void&adjustVolume(int&direction,&int&flags);&&
&&&&void&adjustSuggestedStreamVolume(int&direction,&int&suggestedStreamType,&int&flags);&&
&&&&void&adjustStreamVolume(int&streamType,&int&direction,&int&flags);&&&&&&&&&&
&&&&void&setStreamVolume(int&streamType,&int&index,&int&flags);&&&&&&&&&&
&&&&void&setStreamSolo(int&streamType,&boolean&state,&IBinder&cb);&&&&&&&&&&&&
&&&&void&setStreamMute(int&streamType,&boolean&state,&IBinder&cb);&&&&&&&&
&&&&int&getStreamVolume(int&streamType);&&&&&&&&&&
&&&&int&getStreamMaxVolume(int&streamType);&&&&&&&&&
&&&&void&setRingerMode(int&ringerMode);&&&&&&&&&&
&&&&int&getRingerMode();&&
&&&&void&setVibrateSetting(int&vibrateType,&int&vibrateSetting);&&&&&&&&&&
&&&&int&getVibrateSetting(int&vibrateType);&&&&&&&&&&
&&&&boolean&shouldVibrate(int&vibrateType);&&
&&&&void&setMode(int&mode,&IBinder&cb);&&
&&&&int&getMode();&&
&&&&oneway&void&playSoundEffect(int&effectType);&&&&&&&&
&&&&oneway&void&playSoundEffectVolume(int&effectType,&float&volume);&&
&&&&boolean&loadSoundEffects();&&&&&&&
&&&&oneway&void&unloadSoundEffects();&&
&&&&oneway&void&reloadAudioSettings();&&
&&&&void&setSpeakerphoneOn(boolean&on);&&
&&&&boolean&isSpeakerphoneOn();&&
&&&&void&setBluetoothScoOn(boolean&on);&&
&&&&boolean&isBluetoothScoOn();&&
&&&&int&requestAudioFocus(int&mainStreamType,&int&durationHint,&IBinder&cb,&IAudioFocusDispatcher&l,&String&clientId);&&
&&&&int&abandonAudioFocus(IAudioFocusDispatcher&l,&String&clientId);&&&&&&&&&&
&&&&void&unregisterAudioFocusClient(String&clientId);&&
&&&&void&registerMediaButtonEventReceiver(in&ComponentName&eventReceiver);&&&&&
&&&&void&unregisterMediaButtonEventReceiver(in&ComponentName&eventReceiver);&&&&
&&&&void&startBluetoothSco(IBinder&cb);&&
&&&&void&stopBluetoothSco(IBinder&cb);&&
&&&& & 真正的服务端对象就是继承了 IAudioService.Stub 桩的类,AudioService就是该服务端对象,其实AudioManager的
&&所有操作都是由AudioService来实现的,它才是真正的老大。
第五步、&& AudioService.java
public&class&AudioService&extends&IAudioService.Stub&{&&
&&&&public&void&registerMediaButtonEventReceiver(ComponentName&eventReceiver)&{&&
&&&&&&&&Log.i(TAG,&"&&Remote&Control&&&registerMediaButtonEventReceiver()&for&"&+&eventReceiver);&&
&&&&&&&&synchronized(mRCStack)&{&&
&&&&&&&&&&&&
&&&&&&&&&&&&pushMediaButtonReceiver(eventReceiver);&&
&&&&&&&&}&&
&&&&private&static&class&RemoteControlStackEntry&{&&
&&&&&&&&public&ComponentName&mReceiverC&&
&&&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&public&RemoteControlStackEntry()&{&&
&&&&&&&&}&&
&&&&&&&&public&RemoteControlStackEntry(ComponentName&r)&{&&
&&&&&&&&&&&&mReceiverComponent&=&r;&&
&&&&&&&&}&&
&&&&private&Stack&RemoteControlStackEntry&&mRCStack&=&new&Stack&RemoteControlStackEntry&();&&
&&&private&void&pushMediaButtonReceiver(ComponentName&newReceiver)&{&&
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&if&(!mRCStack.empty()&&&&mRCStack.peek().mReceiverComponent.equals(newReceiver))&{&&
&&&&&&&&&&&&return;&&
&&&&&&&&}&&
&&&&&&&&&&
&&&&&&&&Iterator&RemoteControlStackEntry&&stackIterator&=&mRCStack.iterator();&&
&&&&&&&&&&
&&&&&&&&while(stackIterator.hasNext())&{&&
&&&&&&&&&&RemoteControlStackEntry&rcse&=&(RemoteControlStackEntry)stackIterator.next();&&
&&&&&&&&&&&&
&&&&&&&&&&&&if(rcse.mReceiverComponent.equals(newReceiver))&{&&
&&&&&&&&&&&&&&&&mRCStack.remove(rcse);&&
&&&&&&&&&&&&&&&&break;&&
&&&&&&&&&&&&}&&
&&&&&&&&}&&
&&&&&&&&mRCStack.push(new&RemoteControlStackEntry(newReceiver));&&
小结一下:&
&&&&&&&& 栈(mRCStack)维护了所有CompoentName对象,对每个CompoentName对象,保证它有且仅有一个,
&&&& 新注册的CompoentName对象永远处于栈顶&&&&
&我们看下取消注册的方法:
public&void&unregisterMediaButtonEventReceiver(ComponentName&eventReceiver)&{&&
&&&&Log.i(TAG,&"&&Remote&Control&&&unregisterMediaButtonEventReceiver()&for&"&+&eventReceiver);&&
&&&&synchronized(mRCStack)&{&&
&&&&&&&&&&&
&&&&&&&&removeMediaButtonReceiver(eventReceiver);&&
private&void&removeMediaButtonReceiver(ComponentName&newReceiver)&{&&
&&&&Iterator&RemoteControlStackEntry&&stackIterator&=&mRCStack.iterator();&&
&&&&while(stackIterator.hasNext())&{&&
&&&&&&&&&&&
&&&&&&&&RemoteControlStackEntry&rcse&=&(RemoteControlStackEntry)stackIterator.next();&&
&&&&&&&&&&
&&&&&&&&if(rcse.mReceiverComponent.equals(newReceiver))&{&&
&&&&&&&&&&&&mRCStack.remove(rcse);&&
&&&&&&&&&&&&break;&&
&&&&&&&&}&&
&& &&&& &&通过对前面的学习,我们知道了AudioManager内部利用一个栈来管理包括加入和移除ComponentName对象,
&&& 新的疑问来了?这个MEDIA_BUTTON广播是如何分发的呢 ?
&&&&&&&&& 其实,AudioService.java文件中也存在这么一个MediaoButtonReceiver的广播类,它为系统广播接收器,即用来接收
& 系统的MEDIA_BUTTON广播,当它接收到了这个MEDIA_BUTTON广播&&&,它会对这个广播进行进一步处理,这个处理过程
&& 就是我们需要的弄清楚。
MediaButtonBroadcastReceiver 内部类如下:
private&class&MediaButtonBroadcastReceiver&extends&BroadcastReceiver&{&&
&&&&@Override&&
&&&&public&void&onReceive(Context&context,&Intent&intent)&{&&
&&&&&&&&&&
&&&&&&&&String&action&=&intent.getAction();&&
&&&&&&&&&&
&&&&&&&&if&(!Intent.ACTION_MEDIA_BUTTON.equals(action))&{&&
&&&&&&&&&&&&return;&&
&&&&&&&&}&&
&&&&&&&&KeyEvent&event&=&(KeyEvent)&intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);&&
&&&&&&&&if&(event&!=&null)&{&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&if&((getMode()&==&AudioSystem.MODE_IN_CALL)&||(getMode()&==&AudioSystem.MODE_RINGTONE))&{&&
&&&&&&&&&&&&&&&&return;&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&synchronized(mRCStack)&{&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&if&(!mRCStack.empty())&{&&
&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&Intent&targetedIntent&=&new&Intent(Intent.ACTION_MEDIA_BUTTON);&&
&&&&&&&&&&&&&&&&&&&&targetedIntent.putExtras(intent.getExtras());&&
&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&targetedIntent.setComponent(mRCStack.peek().mReceiverComponent);&&
&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&abortBroadcast();&&
&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&context.sendBroadcast(targetedIntent,&null);&&
&&&&&&&&&&&&&&&&}&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&}&&
&&&&&&&&}&&
&总结一下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
package&com.qin.&&
import&android.content.BroadcastR&&
import&android.content.C&&
import&android.content.I&&
import&android.util.L&&
import&android.view.KeyE&&
public&class&China_MBReceiver&extends&BroadcastReceiver&&{&&
&&&&private&static&String&TAG&=&"China_MBReceiver"&;&&
&&&&@Override&&
&&&&public&void&onReceive(Context&context,&Intent&intent)&{&&
&&&&&&&&&&
&&&&&&&&String&intentAction&=&intent.getAction()&;&&
&&&&&&&&&&
&&&&&&&&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();&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&StringBuilder&sb&=&new&StringBuilder();&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&if(KeyEvent.KEYCODE_MEDIA_NEXT&==&keyCode){&&
&&&&&&&&&&&&&&&&sb.append("KEYCODE_MEDIA_NEXT");&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&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());&&
&&&&&&&&&&&&&&
&&&&&&&&}&&
&&&&&&&&&&
&&&2 、England_MBReceiver.java同于China_MBRreceiver&,打印Log TAG= "England_MBReceiver"
&& 3、在AndroidManifest.xml文件定义:
&strong&&&&receiver&android:name=".China_MBReceiver"&&&
&&&&&&&&&&&intent-filter&&&&
&&&&&&&&&&&&&&&&&action&android:name="android.intent.action.MEDIA_BUTTON"&&/action&&&
&&&&&&&&&&&/intent-filter&&&
&&&&&&&&&/receiver&&&
&&&&&&&&&&
&&&&&&&&&&receiver&android:name=".Enaland_MBReceiver"&&&
&&&&&&&&&&&intent-filter&&&&
&&&&&&&&&&&&&&&&&action&android:name="android.intent.action.MEDIA_BUTTON"&&/action&&&
&&&&&&&&&&&/intent-filter&&&
&&&&&&&&&/receiver&&/strong&&&
4、MainActivity .java&我们通过手动构造一个MEDIA_BUTTON广播去查看我们的MediaButtonReceiver类的打印信息。
package&com.qin.&&
import&android.app.A&&
import&ponentN&&
import&android.content.C&&
import&android.content.I&&
import&android.media.AudioM&&
import&android.os.B&&
import&android.view.KeyE&&
public&class&MainActivity&extends&Activity&{&&
&&&&@Override&&
&&&&public&void&onCreate(Bundle&savedInstanceState)&{&&
&&&&&&&&super.onCreate(savedInstanceState);&&
&&&&&&&&setContentView(R.layout.main);&&
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&Intent&mbIntent&=&new&Intent(Intent.ACTION_MEDIA_BUTTON);&&
&&&&&&&&&&
&&&&&&&&KeyEvent&keyEvent&=&new&KeyEvent&(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_HEADSETHOOK)&;&&
&&&&&&&&&&
&&&&&&&&mbIntent.putExtra(Intent.EXTRA_KEY_EVENT,&keyEvent);&&
&&&&&&&&&&
&&&&&&&&sendBroadcast(mbIntent);&&
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&AudioManager&mAudioManager&=&(AudioManager)getSystemService(Context.AUDIO_SERVICE);&&
&&&&&&&&&&
&&&&&&&&ComponentName&chinaCN&=&new&ComponentName(getPackageName(),China_MBReceiver.class.getName());&&
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&mAudioManager.registerMediaButtonEventReceiver(chinaCN);&&
&&&&protected&void&onDestroy(){&&
&&&&&&&&super.onDestroy()&;&&
&&&&&&&&AudioManager&mAudioManager&=&(AudioManager)getSystemService(Context.AUDIO_SERVICE);&&
&&&&&&&&ComponentName&chinaCN&=&new&ComponentName(getPackageName(),China_MBReceiver.class.getName());&&
&&&&&&&&&&
&&&&&&&&mAudioManager.unregisterMediaButtonEventReceiver(chinaCN);&&
& &&&& 值得注意的一点时,当我们为一个应用程序注册了MediaoButtonReceiver时,在程序离开时,我们需要取消该
& MediaoButtonReceiver的注册,在onDestroy()调用unregisterMediaButtonEventReceiver()方法就OK,这样应用程序之间
& 的交互就更具逻辑性了。
Views(...) Comments()Android 适配问题集锦(3)
1、Android耳机插拔检测原理
2、Android耳机插拔检测具体实现
3、真机上的适配问题
澳大利亚悉尼市新南威尔士大学的一名男生在课堂上看色情片,不料耳机没有插好,变成了现场直播。
如果在手机上看电影时,当你插上耳机,音乐却从扬声器里响了起来,这未免会更加尴尬了。
1、Android耳机插拔检测原理
Android系统在耳机插入和拔出的时候会发送广播,通过
Broadcast Receiver 监听“android.intent.action.HEADSET_PLUG” 这个Intent来判断耳机是否插拔。
0代表拔出,1代表插入
字符串,代表headset的类型
microphone
1代表这个headset有麦克风,0则没有
2、Android耳机插拔检测具体实现
在Android4.0以上的版本,耳机插拔检测的源文件位于frameworks/base/services/java/com/android/server/WiredAccessoryObserver.java;(4.1及以上是WiredAccessoryManager.java;在android4.0以前是HeadsetObserver.java)顾名思义,它主要是用来检测有线的设备连接状态。
Android耳机插拔检测流程图
我们重点来看一下WiredAccessoryObserver。
WiredAccessoryObserver继承自UEventObserver(Android耳机插拔可以有两个机制实现:InputEvent和UEvent),从该文件的路径可以得知,这个类位于service目录,应该是在android系统服务初始化的时候实例化的,在这个类的构造方法中,注册了一个广播接收器用来接收系统启动完毕的广播。
WiredAccessoryObserver工作流程图
在收到这个广播之后:先执行init()函数,在这个函数中判断要检测的设备是否已经处于连接状态(比如开机之前就已经插上),如果已经连接上就调用updateState立即向系统上报。然后调用startObserving函数监测文件节点路径是否有状态变化,这个函数位于他的父类UEventObserver.java中。在之前建立好的监测中,如果kernel层有uevent事件发送上来则会去匹配这个路径字符串,如果匹配成功会调用在WiredAccessoryObserver重载的onUEvent函数,从event string中解析出devPath, name和state的值,然后继续调用updateState进行处理,在updateState中会对设备的类型进行进一步的分析之后调用update上报,在update中,会往handler中发送一个消息,将耳机的状态报告给Audio系统。之后由AudioService在sendDeviceConnectionIntent函数中向系统广播耳机已经插入的ACTION_HEADSET_PLUG广播,同时会通知AudioPolicy做audio通路切换的工作。
3、真机上的适配问题
(1)在HuaWei T8833上播放音乐,在插入耳机之后耳机和扬声器都会有声音;
updateState中需要进行update操作。
通过反编译HuaWei T8833 Framework层WiredAccessoryObserver,我们发现了问题的原因;
HDMI状态改变时未进行update操作,也就是没有向系统进行设备连接状态的通知,导致了在插入耳机之后耳机和扬声器都会有声音。
(2)在小米 2S上如果想实现PTT语音消息的功能,播放语音时你可能这样做:
使用Audio进行扬声器播放的时候,当插入耳机时声音并未按预期的由耳机输出,而依旧使用的扬声器进行播放。如果您也是这样做的,那么我们建议您在这台机型上将MODE_IN_CALL与STREAM_MUSIC配对或者将SpeakerphoneOn设置为false,从而让程序具有兼容性。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:195070次
积分:3358
积分:3358
排名:第6897名
原创:140篇
转载:32篇
评论:32条
(1)(3)(1)(2)(6)(1)(2)(1)(2)(3)(1)(6)(18)(8)(17)(2)(1)(20)(1)(10)(4)(5)(57)}

我要回帖

更多关于 笔记本键盘中间的按钮 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信