本文转自:http://www.poemcode.net/2009/11/android_music/
Android 1.6的源码共包括了21个核心应用,分布在 package/apps下,其中 Music 应用提供了音乐播放功能,在各 GPhone 中差不多都能看到。但是这些核心应用本不属于 Framework,因此无法在 SDK Document 中看到其类和方法的说明,更无法在外部引入它们的类,Music也不例外。
工作中遇到这么一个应用场景:用户在文档阅读的 Activity 中,要能够控制音乐播放,包括:上一首、下一首、暂停和继续,以及获取正在播放的音乐的名称。由于无法引入 Music 应用的类,自然也就无法通过 API 直接实现这些功能。
查遍了 Dev Guide 和 Reference,也没有找到蛛丝马迹,于是索性直接进入到 Music 的源码探个究竟。经过初步的分析,将问题的焦点定位在 com.android.music.MediaPlaybackService 上,该类是个 Service 类,负责在后台播放音乐等工作。
该类声明并实例化了一个 BroadcastReceiver,并在 onCreate 中进行了注册,那么这个 BroadcastReceiver 到底接收哪些 Intent 呢?通过代码可以一目了然:
IntentFilter commandFilter =
new
IntentFilter(
)
;
commandFilter.addAction
(
SERVICECMD)
;
commandFilter.addAction
(
TOGGLEPAUSE_ACTION)
;
commandFilter.addAction
(
PAUSE_ACTION)
;
commandFilter.addAction
(
NEXT_ACTION)
;
commandFilter.addAction
(
PREVIOUS_ACTION)
;
registerReceiver(
mIntentReceiver, commandFilter)
;
找到上述代码中的常量声明,可以看出这些就是控制音乐播放的action name了。
public
static
final
String
SERVICECMD =
“com.android
.music
.musicservicecommand
”;
public
static
final
String
CMDNAME =
“command”;
public
static
final
String
CMDTOGGLEPAUSE =
“togglepause”;
public
static
final
String
CMDSTOP =
“stop”;
public
static
final
String
CMDPAUSE =
“pause”;
public
static
final
String
CMDPREVIOUS =
“previous”;
public
static
final
String
CMDNEXT =
“next”;
public
static
final
String
TOGGLEPAUSE_ACTION =
“com.android
.music
.musicservicecommand
.togglepause
”;
public
static
final
String
PAUSE_ACTION =
“com.android
.music
.musicservicecommand
.pause
”;
public
static
final
String
PREVIOUS_ACTION =
“com.android
.music
.musicservicecommand
.previous
”;
public
static
final
String
NEXT_ACTION =
“com.android
.music
.musicservicecommand
.next
”;
然后再回过头来看 BroadcastReceiver是如何处理这些 Intent 的,通过其 onCreate 方法可以看出控制音乐播放有两种方式。其一是设置 action name 为 SERVICECMD,然后通过 Intent 的 extra 设置 command,其值可以是 CMDTOGGLEPAUSE、CMDSTOP、CMDPAUSE、CMDPREVIOUS 或 CMDNEXT。
其二是设置 action name 为 TOGGLEPAUSE_ACTION、PAUSE_ACTION、PREVIOUS_ACTION 或 NEXT_ACTION。
看起来第二种方式更简洁,依此思路,逆向操作也就可以解决起初的问题了,如下代码演示了如何控制下一首:
Intent intent =
new
Intent (
”com.android
.music
.musicservicecommand
.next
”)
;
sendBroadcast(
intent)
;
如果我们在此基础上更深入一步,控制音乐播放的同时,我们还需要得到正在播放的音乐名称,这又该怎么实现呢?
Android Framework 提供了非常棒的 android.media,凡音乐播放都离不开 MediaPlayer,该类定义了七个内部类,其中 MediaPlayer.OnPreparedListener 是这么描述的:
Interface definition for a callback to be invoked when the media source is ready for playback.
媒体文件准备结束,准备播放时,Android 就会调用这个这个内部类,在 MediaPlaybackService 则是 notifyChange(String what) 方法进行处理:
private
void
notifyChange(
String
what)
{
Intent i =
new
Intent(
what)
;
i.putExtra
(
”id”, Integer
.valueOf
(
getAudioId(
)
)
)
;
i.putExtra
(
”artist”, getArtistName(
)
)
;
i.putExtra
(
”album”,getAlbumName(
)
)
;
i.putExtra
(
”track”, getTrackName(
)
)
;
sendBroadcast(
i)
;
// ……
}
那么在我们的应用当中,则需要创建 一个BroadcastReceiver,过滤对应的 action name,也就是常量 META_CHANGED 对应的值即可达到目标。
到了这里,回顾一下解决问题的过程,不由让人有些愤愤不平,为什么 Android 不把接口以文档的形式公布于众呢?真是“犹抱琵琶半遮面”。–或者它有公布,我没有看到?