本文根据原生Android 4.1.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)


1. private void pause(boolean isStopForeground) {  
2. synchronized(this) {  
3.             mMediaplayerHandler.removeMessages(FADEUP);  
4. if (isPlaying()) {  
5.                 mPlayer.pause();  
6.                 gotoIdleState(isStopForeground);  
7. false;  
8.                 notifyChange(PLAYSTATE_CHANGED);  
9.                 saveBookmarkIfNeeded();  
10.             }  
11.         }  
12.     }  
13.       
14. private void gotoIdleState(boolean isStopForeground) {  
15. null);  
16.         Message msg = mDelayedStopHandler.obtainMessage();  
17.         mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);  
18. //此方法控制消除通知  
19.         stopForeground(isStopForeground);  
20.     }

1.2 接收暂停广播的时候将pause()方法换为:pause(false)

    1. private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {  
    2. @Override  
    3. public void onReceive(Context context, Intent intent) {  
    4.             String action = intent.getAction();  
    5. "command");  
    6. "mIntentReceiver.onReceive " + action + " / " + cmd);  
    7. if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {  
    8. true);  
    9. else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {  
    10.                 prev();  
    11. else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {  
    12. if (isPlaying()) {  
    13. /*Begin: modified  */  
    14. false);  
    15.                     updateNotification();  
    16. /*End: */  
    17. false;  
    18. else {  
    19.                     play();  
    20.                 }  
    21. else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {  
    22. /*Begin: modified  */  
    23. false);  
    24.                 updateNotification();  
    25. /*End:*/  
    26. false;  
    27. else if (CMDPLAY.equals(cmd)) {  
    28.                               ...

    2 Music 音乐通知控制 

    2.1 通知的布局文件 /packages/apps/Music/res/layout/statusbar.xml

      1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
      2. android:layout_width="match_parent"  
      3. android:layout_height="wrap_content"  
      4. android:orientation="horizontal" >  
      5.   
      6. <LinearLayout  
      7. xmlns:android="http://schemas.android.com/apk/res/android"  
      8. android:layout_width="wrap_content"  
      9. android:layout_height="wrap_content"  
      10. android:orientation="horizontal"   
      11. android:layout_gravity="center_vertical">  
      12. <!-- 图标 -->  
      13. <ImageView  
      14. android:id="@+id/icon"  
      15. android:layout_width="wrap_content"  
      16. android:layout_height="wrap_content"  
      17. android:gravity="center"  
      18. android:padding="4dip" >  
      19. </ImageView>  
      20. </LinearLayout>  
      21.   
      22. <LinearLayout  
      23. android:layout_width="match_parent"  
      24. android:layout_height="wrap_content"  
      25. android:orientation="vertical" >  
      26.   
      27. <LinearLayout  
      28. android:layout_width="match_parent"  
      29. android:layout_height="wrap_content"  
      30. android:orientation="horizontal" >  
      31. <!-- 音乐名 -->  
      32. <TextView  
      33. android:id="@+id/trackname"  
      34. style="@android:style/TextAppearance.StatusBar.EventContent.Title"  
      35. android:layout_width="80dip"  
      36. android:layout_height="wrap_content"  
      37. android:layout_gravity="left"  
      38. android:ellipsize="marquee"  
      39. android:focusable="true"  
      40. android:singleLine="true" />  
      41.   
      42. <RelativeLayout  
      43. android:layout_width="match_parent"  
      44. android:layout_height="match_parent" >  
      45. <!-- 上一首 -->  
      46. <ImageButton  
      47. android:id="@+id/statusbar_prev"  
      48. style="@android:style/MediaButton.Previous"  
      49. android:layout_width="wrap_content"  
      50. android:layout_height="wrap_content"  
      51. android:layout_alignParentLeft="true" />  
      52. <!-- 暂停/播放 -->  
      53. <ImageButton  
      54. android:id="@+id/statusbar_pause"  
      55. style="@android:style/MediaButton.Pause"  
      56. android:layout_width="wrap_content"  
      57. android:layout_height="wrap_content"  
      58. android:layout_centerHorizontal="true" />  
      59. <!-- 下一首 -->  
      60. <ImageButton  
      61. android:id="@+id/statusbar_next"  
      62. style="@android:style/MediaButton.Next"  
      63. android:layout_width="wrap_content"  
      64. android:layout_height="wrap_content"  
      65. android:layout_alignParentRight="true"  
      66. android:gravity="right" />  
      67. </RelativeLayout>  
      68. </LinearLayout>  
      69. <!-- 专辑信息,歌手 -->  
      70. <TextView  
      71. android:id="@+id/artistalbum"  
      72. style="@android:style/TextAppearance.StatusBar.EventContent"  
      73. android:layout_width="wrap_content"  
      74. android:layout_height="wrap_content"  
      75. android:layout_gravity="left"  
      76. android:ellipsize="end"  
      77. android:maxLines="2"  
      78. android:scrollHorizontally="true" />  
      79. </LinearLayout>  
      80.   
      81. </LinearLayout>


      2.2  通知栏控制:

      /packages/apps/Music/src/com/android/music/MediaPlaybackService.java中

       updateNotification()为发送的通知代码,在这里面修改

      1. private void updateNotification() {  
      2. //RemoteViews未自定义布局,   R.layout.statusbar 为通知的布局文件  
      3. new RemoteViews(getPackageName(), R.layout.statusbar);  
      4.         views.setImageViewResource(R.id.icon, R.drawable.stat_notify_musicplayer);  
      5. if (getAudioId() < 0) {  
      6. // streaming  
      7.             views.setTextViewText(R.id.trackname, getPath());  
      8. null);  
      9. else {  
      10.             String artist = getArtistName();  
      11.             views.setTextViewText(R.id.trackname, getTrackName());  
      12. if (artist == null || artist.equals(MediaStore.UNKNOWN_STRING)) {  
      13.                 artist = getString(R.string.unknown_artist_name);  
      14.             }  
      15.             String album = getAlbumName();  
      16. if (album == null || album.equals(MediaStore.UNKNOWN_STRING)) {  
      17.                 album = getString(R.string.unknown_album_name);  
      18.             }  
      19.   
      20.             views.setTextViewText(R.id.artistalbum,  
      21.                     getString(R.string.notification_artist_album, artist, album)  
      22.                     );  
      23.         }  
      24. new Notification();  
      25. /*Begin: modified 添加修改代码*/  
      26. //status_icon 为状态栏图标,R.id.statusbar_pause 为通知 的 暂停/开始按钮  
      27. int status_icon = R.drawable.ic_appwidget_music_play;  
      28. //根据播放状态,来决定 暂停/开始 图标  
      29. if(isPlaying()){  
      30.             views.setImageViewResource(R.id.statusbar_pause, R.drawable.ic_appwidget_music_pause);   
      31. else{  
      32.             views.setImageViewResource(R.id.statusbar_pause, R.drawable.ic_appwidget_music_play);  
      33.             status_icon = R.drawable.ic_appwidget_music_pause;  
      34.          }  
      35. // 给通知栏 上一首 按钮 添加点击事件    
      36.         views.setOnClickPendingIntent(R.id.statusbar_prev, pre_PendingIntent());  
      37. //给通知栏 暂停/开始 按钮 添加点击事件   
      38.         views.setOnClickPendingIntent(R.id.statusbar_pause, pause_PendingIntent());  
      39. //给通知栏 下一首 按钮 添加点击事件  
      40.         views.setOnClickPendingIntent(R.id.statusbar_next, next_PendingIntent());  
      41. /*End:  */  
      42.            
      43.         status.contentView = views;  
      44.         status.flags |= Notification.FLAG_ONGOING_EVENT;  
      45.         status.icon = status_icon;  
      46. this, 0,  
      47. new Intent("com.android.music.PLAYBACK_VIEWER")  
      48. 0);  
      49.         startForeground(PLAYBACKSERVICE_STATUS, status);  
      50.     }

      添加的点击事件函数:

        1. /*Begin:  modify  利用MediaPlaybackService 现有的广播监听 实现播放控制 */  
        2. //上一首,  
        3. private PendingIntent pre_PendingIntent(){  
        4. new Intent(PREVIOUS_ACTION);  
        5. this, 0, intent, 0);  
        6. return pendingIntent;  
        7.     }  
        8. //暂停开始   
        9. private PendingIntent pause_PendingIntent(){  
        10. new Intent(TOGGLEPAUSE_ACTION);  
        11. this, 0, intent, 0);  
        12. return pendingIntent;  
        13.     }  
        14. //下一首   
        15. private PendingIntent next_PendingIntent(){  
        16. new Intent(NEXT_ACTION);  
        17. this, 0, intent, 0);  
        18. return pendingIntent;  
        19.     }  
        20.       
        21. /*end:  */

        为了实现暂停/开始按钮通知栏图标显示与音乐播放 的一致 改了以下两个地方:

        其一 play()  方法中 将  updateNotification() 放在了

        if (!mIsSupposedToBePlaying) {
        
                        mIsSupposedToBePlaying = true;
        
                        notifyChange(PLAYSTATE_CHANGED);
        
                    }

        之后


        1. public void play() {  
        2.             ...  
        3. if (!mIsSupposedToBePlaying) {  
        4. true;  
        5.                 notifyChange(PLAYSTATE_CHANGED);  
        6.             }  
        7. updateNotification();  
        8.           ...  
        9. }

        其二:当接受到 暂停/开始  事件的 广播后,如果 暂停音乐,则调用updateNotification()更新方法

          1. private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {  
          2. @Override  
          3. public void onReceive(Context context, Intent intent) {  
          4.            String action = intent.getAction();  
          5. "command");  
          6. "mIntentReceiver.onReceive " + action + " / " + cmd);  
          7. "  mIntentReceiver   action = "+action+"   cmd ="+cmd+"===");  
          8. if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {  
          9. true);  
          10. else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {  
          11.                prev();  
          12. else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {  
          13. if (isPlaying()) {  
          14. /*Begin: 开始修改*/  
          15. // pause(false); 暂停时不消除通知栏  
          16. false);  
          17.                    updateNotification();  
          18. /*End: modified*/  
          19. false;  
          20. else {  
          21.                    play();  
          22.                }  
          23.                                ...