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)
- privatevoid pause(boolean isStopForeground) {
- synchronized(this) {
- mMediaplayerHandler.removeMessages(FADEUP);
- if (isPlaying()) {
- mPlayer.pause();
- gotoIdleState(isStopForeground);
- mIsSupposedToBePlaying = false;
- notifyChange(PLAYSTATE_CHANGED);
- saveBookmarkIfNeeded();
- }
- }
- }
- private
- mDelayedStopHandler.removeCallbacksAndMessages(null);
- Message msg = mDelayedStopHandler.obtainMessage();
- mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
- //此方法控制消除通知
- stopForeground(isStopForeground);
- }
- private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
- @Override
- publicvoid 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);
- } elseif (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
- prev();
- } elseif (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
- if (isPlaying()) {
- /*Begin: modified */
- pause(false);
- updateNotification();
- /*End: */
- mPausedByTransientLossOfFocus = false;
- } else {
- play();
- }
- } elseif (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
- /*Begin: modified */
- pause(false);
- updateNotification();
- /*End:*/
- mPausedByTransientLossOfFocus = false;
- } elseif (CMDPLAY.equals(cmd)) {
- ...
2 Music 音樂通知控制
2.1 通知的佈局檔案 /packages/apps/Music/res/layout/statusbar.xml
- <LinearLayoutxmlns: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()為傳送的通知程式碼,在這裡面修改
- privatevoid 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);
}
之後
- publicvoid play() {
- ...
- if (!mIsSupposedToBePlaying) {
- mIsSupposedToBePlaying = true;
- notifyChange(PLAYSTATE_CHANGED);
- }
- updateNotification();
- ...
- }
- private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
- @Override
- publicvoid 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);
- } elseif (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
- prev();
- } elseif (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
- if (isPlaying()) {
- /*Begin: 開始修改*/
- // pause(false); 暫停時不消除通知欄
- pause(false);
- updateNotification();
- /*End: modified*/
- mPausedByTransientLossOfFocus = false;
- } else {
- play();
- }
- ...