Android 4.1 Music 通知栏的音乐控制
1 原生Music 暂停的时候,会删除通知栏上的通知。
2 原生Music 通知栏不能控制音乐,比如下一首,上一首,暂停/播放。
一 解决思路:
1 接到暂停广播时,只暂停,不去除通知。
/packages/apps/Music/src/com/android/music/MediaPlaybackService.java中
调用的 stopForeground(true)方法控制去除通知
2 自定义音乐通知,添加按钮事件。
/packages/apps/Music/src/com/android/music/MediaPlaybackService.java中
updateNotification()方法中自定义Notification,关键对RemoteViews 的理解
二 修改后效果图:
三 详细代码
1 接到暂停广播时,只暂停,不去除通知
源代码 采取的策略是 只要暂停就去除通知,这就会造成一个问题就是,当播放视频的时候音乐播放器接受到暂停的广播,于是消除了通知栏。
1.1 添加暂停 不消除通知的方法 pause(boolean isStopForeground)
- private void pause(boolean isStopForeground) {
- synchronized(this) {
- mMediaplayerHandler.removeMessages(FADEUP);
- if (isPlaying()) {
- mPlayer.pause();
- gotoIdleState(isStopForeground);
- mIsSupposedToBePlaying = false;
- notifyChange(PLAYSTATE_CHANGED);
- saveBookmarkIfNeeded();
- }
- }
- }
- private void gotoIdleState(boolean isStopForeground) {
- mDelayedStopHandler.removeCallbacksAndMessages(null);
- Message msg = mDelayedStopHandler.obtainMessage();
- mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
- //此方法控制消除通知
- stopForeground(isStopForeground);
- }
- private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- String cmd = intent.getStringExtra("command");
- MusicUtils.debugLog("mIntentReceiver.onReceive " + action + " / " + cmd);
- if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
- gotoNext(true);
- } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
- prev();
- } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
- if (isPlaying()) {
- /*Begin: modified */
- pause(false);
- updateNotification();
- /*End: */
- mPausedByTransientLossOfFocus = false;
- } else {
- play();
- }
- } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
- /*Begin: modified */
- pause(false);
- updateNotification();
- /*End:*/
- mPausedByTransientLossOfFocus = false;
- } else if (CMDPLAY.equals(cmd)) {
- ...
2 Music 音乐通知控制
2.1 通知的布局文件 /packages/apps/Music/res/layout/statusbar.xml
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_vertical">
- <!-- 图标 -->
- <ImageView
- android:id="@+id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:padding="4dip" >
- </ImageView>
- </LinearLayout>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <!-- 音乐名 -->
- <TextView
- android:id="@+id/trackname"
- style="@android:style/TextAppearance.StatusBar.EventContent.Title"
- android:layout_width="80dip"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:ellipsize="marquee"
- android:focusable="true"
- android:singleLine="true" />
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
- <!-- 上一首 -->
- <ImageButton
- android:id="@+id/statusbar_prev"
- style="@android:style/MediaButton.Previous"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true" />
- <!-- 暂停/播放 -->
- <ImageButton
- android:id="@+id/statusbar_pause"
- style="@android:style/MediaButton.Pause"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true" />
- <!-- 下一首 -->
- <ImageButton
- android:id="@+id/statusbar_next"
- style="@android:style/MediaButton.Next"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:gravity="right" />
- </RelativeLayout>
- </LinearLayout>
- <!-- 专辑信息,歌手 -->
- <TextView
- android:id="@+id/artistalbum"
- style="@android:style/TextAppearance.StatusBar.EventContent"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:ellipsize="end"
- android:maxLines="2"
- android:scrollHorizontally="true" />
- </LinearLayout>
- </LinearLayout>
2.2 通知栏控制:
/packages/apps/Music/src/com/android/music/MediaPlaybackService.java中
updateNotification()为发送的通知代码,在这里面修改
- private void updateNotification() {
- //RemoteViews未自定义布局, R.layout.statusbar 为通知的布局文件
- RemoteViews views = new RemoteViews(getPackageName(), R.layout.statusbar);
- views.setImageViewResource(R.id.icon, R.drawable.stat_notify_musicplayer);
- if (getAudioId() < 0) {
- // streaming
- views.setTextViewText(R.id.trackname, getPath());
- views.setTextViewText(R.id.artistalbum, null);
- } else {
- String artist = getArtistName();
- views.setTextViewText(R.id.trackname, getTrackName());
- if (artist == null || artist.equals(MediaStore.UNKNOWN_STRING)) {
- artist = getString(R.string.unknown_artist_name);
- }
- String album = getAlbumName();
- if (album == null || album.equals(MediaStore.UNKNOWN_STRING)) {
- album = getString(R.string.unknown_album_name);
- }
- views.setTextViewText(R.id.artistalbum,
- getString(R.string.notification_artist_album, artist, album)
- );
- }
- Notification status = new Notification();
- /*Begin: modified 添加修改代码*/
- //status_icon 为状态栏图标,R.id.statusbar_pause 为通知 的 暂停/开始按钮
- int status_icon = R.drawable.ic_appwidget_music_play;
- //根据播放状态,来决定 暂停/开始 图标
- if(isPlaying()){
- views.setImageViewResource(R.id.statusbar_pause, R.drawable.ic_appwidget_music_pause);
- }else{
- views.setImageViewResource(R.id.statusbar_pause, R.drawable.ic_appwidget_music_play);
- status_icon = R.drawable.ic_appwidget_music_pause;
- }
- // 给通知栏 上一首 按钮 添加点击事件
- views.setOnClickPendingIntent(R.id.statusbar_prev, pre_PendingIntent());
- //给通知栏 暂停/开始 按钮 添加点击事件
- views.setOnClickPendingIntent(R.id.statusbar_pause, pause_PendingIntent());
- //给通知栏 下一首 按钮 添加点击事件
- views.setOnClickPendingIntent(R.id.statusbar_next, next_PendingIntent());
- /*End: */
- status.contentView = views;
- status.flags |= Notification.FLAG_ONGOING_EVENT;
- status.icon = status_icon;
- status.contentIntent = PendingIntent.getActivity(this, 0,
- new Intent("com.android.music.PLAYBACK_VIEWER")
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0);
- startForeground(PLAYBACKSERVICE_STATUS, status);
- }
添加的点击事件函数:
- /*Begin: modify 利用MediaPlaybackService 现有的广播监听 实现播放控制 */
- //上一首,
- private PendingIntent pre_PendingIntent(){
- Intent intent = new Intent(PREVIOUS_ACTION);
- PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
- return pendingIntent;
- }
- //暂停开始
- private PendingIntent pause_PendingIntent(){
- Intent intent = new Intent(TOGGLEPAUSE_ACTION);
- PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
- return pendingIntent;
- }
- //下一首
- private PendingIntent next_PendingIntent(){
- Intent intent = new Intent(NEXT_ACTION);
- PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
- return pendingIntent;
- }
- /*end: */
为了实现暂停/开始按钮通知栏图标显示与音乐播放 的一致 改了以下两个地方:
其一 play() 方法中 将 updateNotification() 放在了
if (!mIsSupposedToBePlaying) {
mIsSupposedToBePlaying = true;
notifyChange(PLAYSTATE_CHANGED);
}
之后
- public void play() {
- ...
- if (!mIsSupposedToBePlaying) {
- mIsSupposedToBePlaying = true;
- notifyChange(PLAYSTATE_CHANGED);
- }
- updateNotification();
- ...
- }
- private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- String cmd = intent.getStringExtra("command");
- MusicUtils.debugLog("mIntentReceiver.onReceive " + action + " / " + cmd);
- Log.e(LOGTAG, " mIntentReceiver action = "+action+" cmd ="+cmd+"===");
- if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
- gotoNext(true);
- } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
- prev();
- } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
- if (isPlaying()) {
- /*Begin: 开始修改*/
- // pause(false); 暂停时不消除通知栏
- pause(false);
- updateNotification();
- /*End: modified*/
- mPausedByTransientLossOfFocus = false;
- } else {
- play();
- }
- ...