Platform: Rockchip
OS: Android 6.0
Kernel: 3.10.92
When I was looking at the problem of automatic playback in the music background, I didn't know about this log, so I thought the log printed by default would have something to do with it.
ActivityManager: Start proc 978:com.android.music/u0a29 for broadcast com.android.music/.MediaButtonIntentReceiver
In fact, this is related to MediaButton.
In general, when you plug in your headset, if there are keys on it, the system will call music to play music when you press it. This function is just to receive and process the play/pause/next song via MediaButton IntentReceiver.
Definition:
Essentially, it is also a Broadcast Receiver with static definitions in the xml:
packages/apps/Music/AndroidManifest.xml
<receiver android:name="com.android.music.MediaButtonIntentReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
<action android:name="android.media.AUDIO_BECOMING_NOISY" />
</intent-filter>
</receiver>
Receive "android.intent.action.MEDIA_BUTTON" and "android.media.AUDIO_BECOMING_NOISY" actions.
The former handles key events, while the latter handles events such as headphone plugging (such as stopping playback when an event is received).Specific instructions are as follows:
Intent.java
/**
* 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";
AudioManager.java
/**
* 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";
Registration:
packages/apps/Music/src/com/android/music/MediaPlaybackService.java
public void onCreate() {
//Registration of MediaButton classes is implemented and managed through AudioManager
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
ComponentName rec = new ComponentName(getPackageName(),
MediaButtonIntentReceiver.class.getName());
//Register interface
mAudioManager.registerMediaButtonEventReceiver(rec);
}
Event handling:
packages/apps/Music/src/com/android/music/MediaButtonIntentReceiver.java
public class MediaButtonIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String intentAction = intent.getAction();
//Processing such as plugging and unplugging
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);
//Key Processing
} else if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
......
if (command != null) {
//Press Handle
if (action == KeyEvent.ACTION_DOWN) {
if (mDown) {
if ((MediaPlaybackService.CMDTOGGLEPAUSE.equals(command) ||
MediaPlaybackService.CMDPLAY.equals(command))
&& mLastClickTime != 0
&& eventtime - mLastClickTime > LONG_PRESS_DELAY) {
mHandler.sendMessage(
mHandler.obtainMessage(MSG_LONGPRESS_TIMEOUT, context));
}
} else if (event.getRepeatCount() == 0) {
......
}
if (isOrderedBroadcast()) {
abortBroadcast();
}
}
}
}
}
Priority principle:
Each application can register a Receiver like MediaButton, such as a cool dog and a system-owned music player. Which one should be called to play when a key is pressed?
Handling of older versions:
The behavior of the system is to use which app to play if it is registered late.
The principle is that the system stores all the currently registered MediaButtton Receivers in one stack, and the last registered Receviver will be placed at the top of the stack according to the FIFO principle.
If it's already registered, delete it before putting it on the top of the stack.
This part of the above functionality is implemented in AudioService.
New Version Processing:
Save with MediaSession, and when a key event occurs, decide which application to send by determining if the current application is playing and priority.
Registration process:
registerMediaButtonEventReceiver -> registerMediaButtonIntent -> helper.addMediaButtonListener ->
MediaButtonListener -> holder.mSession.setMediaButtonReceiver
Processing after the system receives the event:
sendMediaButtonEvent -> mSessionManager.dispatchMediaKeyEvent -> dispatchMediaKeyEvent(MediaSessionManager.java)
Reference resources:
Implementation of controlling music playback through headphone keys in Android
MediaButton of audio series - based on Android 7.0
Mechanism Analysis of MediaButtonReceiver Broadcast Monitor in Android
Add Headset button support to your Android application
Android Headphone Hook Key Function