android对媒体按键,比如上一首,下一首,播放,暂停,快进,快退等。当然,也包括耳机上的按键,拨打电话,接听电话,挂断电话等。本篇来讲述android如何传递媒体按键的。
4167 case KeyEvent.KEYCODE_HEADSETHOOK:
4168 case KeyEvent.KEYCODE_MUTE:
4169 case KeyEvent.KEYCODE_MEDIA_STOP:
4170 case KeyEvent.KEYCODE_MEDIA_NEXT:
4171 case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
4172 case KeyEvent.KEYCODE_MEDIA_REWIND:
4173 case KeyEvent.KEYCODE_MEDIA_RECORD:
4174 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
4175 case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
(之前的流程,参考android按键处理)
PhoneWindowManager.java里接口dispatchUnhandledKey负责处理下层报过来的按键。调用interceptFallback。interceptFallback调用interceptKeyBeforeQueueing。
interceptKeyBeforeQueueing接口根据按键类型,做不同的处理,比如著名的power键也是在这处理的。这里只关注媒体按键,处理媒体按键,发送了一个消息给自己:
4182 mBroadcastWakeLock.acquire();
4183 Message msg = mHandler.obtainMessage(
MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK,
4184 new KeyEvent(event));
4185 msg.setAsynchronous(true);
4186 msg.sendToTarget();
后边用dispatchMediaKeyWithWakeLock处理这个消息,实际调用了dispatchMediaKeyWithWakeLockToAudioService接口,4309 void dispatchMediaKeyWithWakeLockToAudioService(KeyEvent event) {
4310 if (ActivityManagerNative.isSystemReady()) {
4311 IAudioService audioService = getAudioService();
4312 if (audioService != null) {
4313 try {
4314
audioService.dispatchMediaKeyEventUnderWakelock(event);
4315 } catch (RemoteException e) {
4316 Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
4317 }
4318 }
调用了AudioService的dispatchMediaKeyEventUnderWakelock。
AudioService.java里dispatchMediaKeyEventUnderWakelock接口,调用了mMediaFocusControl.dispatchMediaKeyEventUnderWakelock。
MediaFocusControl.java的dispatchMediaKeyEventUnderWakelock接口调用了,filterMediaKeyEvent接口,处理媒体按键。
746 private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { 747 // sanity check on the incoming key event
先判断是不是媒体按键。
748 if (!isValidMediaKeyEvent(keyEvent)) {
749 Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
750 return;
751 }
如果有telephony相关的锁,优先处理把事件给telephony来处理。
752 // event filtering for telephony
753 synchronized(mRingingLock) {
754 synchronized(mRCStack) {
755 if ((mMediaReceiverForCalls != null) &&
756 (mIsRinging || (mAudioService.getMode() == AudioSystem.MODE_IN_CALL))) {
757 dispatchMediaKeyEventForCalls(keyEvent, needWakeLock);
758 return;
759 }
760 }
761 }
如果telephony没处理,先判断是不是语音按键,不是就调用dispatchMediaKeyEvent
762 // event filtering based on voice-based interactions
763 if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) {
764 filterVoiceInputKeyEvent(keyEvent, needWakeLock);
765 } else {
766 dispatchMediaKeyEvent(keyEvent, needWakeLock);
767 }
768 }
dispatchMediaKeyEvent接口,
先准备了一个Intent:
801 private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
802 if (needWakeLock) {
803 mMediaEventWakeLock.acquire();
804 }
805 Intent keyIntent = new Intent(Intent. ACTION_MEDIA_BUTTON , null);
806 keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
之后判断是否有专门关注媒体按键的客户端,有就调用。
807 synchronized(mRCStack) {
808 if (!mRCStack.empty()) {
809 // send the intent that was registered by the client
810 try {
811 mRCStack.peek().
mMediaIntent.send(mContext,
812 needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/,
813 keyIntent, this, mEventHandler);
没有就广播了,这样大家都能收到了。
824 final long ident = Binder.clearCallingIdentity();
825 try {
826 mContext.
sendOrderedBroadcastAsUser(keyIntent,
UserHandle.ALL,
827 null, mKeyEventDone,
828 mEventHandler, Activity.RESULT_OK, null, null);
registerRemoteControlClient 注册远程控制客户端,所谓远程控制,实际上就是寄生的界面,同时用receiver处理媒体按键的一种播放形式,比如后台的音乐。
registerMediaButtonIntent注册媒体按键,用于获取和处理媒体按键。
registerMediaButtonEventReceiverForCalls注册通话媒体按键处理。
(1) 处理耳机按键
根据实现,我们知道,有2种方法:
--1-- 关心Intent.ACTION_MEDIA_BUTTON
--2-- 其实也是关心Intent.ACTION_MEDIA_BUTTON,不过更加复杂一点,用到:
MediaButtonEventReceiver。
(2) 如何阻止music应用在耳机按键按下后自动播放音乐
我们知道,music应用启动MediaPlaybackService后注册了一个RemoteControlClient以及MediaButtonEventReceiver。这就意味着,我们如果是关心Intent.ACTION_MEDIA_BUTTON的话,是拿不到耳机按键的,会被music应用截掉。
所以我们只能也注册一个MediaButtonEventReceiver了。