zoukankan      html  css  js  c++  java
  • Android 4.1 Music 通知栏的音乐控制

    本文根据原生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.                 mIsSupposedToBePlaying = false;  
    8.                 notifyChange(PLAYSTATE_CHANGED);  
    9.                 saveBookmarkIfNeeded();  
    10.             }  
    11.         }  
    12.     }  
    13.       
    14.     private void gotoIdleState(boolean isStopForeground) {  
    15.         mDelayedStopHandler.removeCallbacksAndMessages(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.             String cmd = intent.getStringExtra("command");  
    6.             MusicUtils.debugLog("mIntentReceiver.onReceive " + action + " / " + cmd);  
    7.             if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {  
    8.                 gotoNext(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.                     pause(false);  
    15.                     updateNotification();  
    16.                     /*End: */  
    17.                     mPausedByTransientLossOfFocus = false;  
    18.                 } else {  
    19.                     play();  
    20.                 }  
    21.             } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {  
    22.                 /*Begin: modified  */  
    23.                 pause(false);  
    24.                 updateNotification();  
    25.                 /*End:*/  
    26.                 mPausedByTransientLossOfFocus = 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.         RemoteViews views = 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.             views.setTextViewText(R.id.artistalbum, 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.         Notification status = 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.         status.contentIntent = PendingIntent.getActivity(this0,  
    47.                 new Intent("com.android.music.PLAYBACK_VIEWER")  
    48.                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0);  
    49.         startForeground(PLAYBACKSERVICE_STATUS, status);  
    50.     }  

    添加的点击事件函数:

    1. /*Begin:  modify  利用MediaPlaybackService 现有的广播监听 实现播放控制 */  
    2.     //上一首,  
    3.     private PendingIntent pre_PendingIntent(){  
    4.         Intent intent = new Intent(PREVIOUS_ACTION);  
    5.         PendingIntent pendingIntent = PendingIntent.getBroadcast(this0, intent, 0);  
    6.          return pendingIntent;  
    7.     }  
    8.     //暂停开始   
    9.     private PendingIntent pause_PendingIntent(){  
    10.         Intent intent = new Intent(TOGGLEPAUSE_ACTION);  
    11.         PendingIntent pendingIntent = PendingIntent.getBroadcast(this0, intent, 0);  
    12.          return pendingIntent;  
    13.     }  
    14.     //下一首   
    15.     private PendingIntent next_PendingIntent(){  
    16.         Intent intent = new Intent(NEXT_ACTION);  
    17.         PendingIntent pendingIntent = PendingIntent.getBroadcast(this0, 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.                 mIsSupposedToBePlaying = 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.            String cmd = intent.getStringExtra("command");  
    6.            MusicUtils.debugLog("mIntentReceiver.onReceive " + action + " / " + cmd);  
    7.            Log.e(LOGTAG, "  mIntentReceiver   action = "+action+"   cmd ="+cmd+"===");  
    8.            if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {  
    9.                gotoNext(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.                    pause(false);  
    17.                    updateNotification();  
    18.                    /*End: modified*/  
    19.                    mPausedByTransientLossOfFocus = false;  
    20.                } else {  
    21.                    play();  
    22.                }  
    23.                                ... 
  • 相关阅读:
    java map使用比较
    mysql无法启动问题 Found option without preceding group in config file
    B站freecoder的计算机基础讲解
    周问题记录
    使用baksmali及smali修改apk并打包
    安卓APP动态调试-IDA实用攻略
    IDA远程调试 在内存中dump Dex文件
    关于ARM的B,BL跳转指令
    IDA 远程调试 Android so
    IDA远程调试so库JNI_Onload函数
  • 原文地址:https://www.cnblogs.com/chengliu/p/4130630.html
Copyright © 2011-2022 走看看