Use MediaStyle Notification on Lollipop

fixes  #543
This commit is contained in:
daniel oeh 2015-01-02 00:01:53 +01:00
parent c33081b909
commit d697fab7eb
2 changed files with 135 additions and 5 deletions

View File

@ -749,7 +749,7 @@ public class PlaybackService extends Service {
final int smallIcon = ClientConfig.playbackServiceCallbacks.getNotificationIconResource(getApplicationContext());
if (!isCancelled() &&
started == true &&
started &&
info.playable != null) {
String contentText = info.playable.getFeedTitle();
String contentTitle = info.playable.getEpisodeTitle();
@ -791,7 +791,7 @@ public class PlaybackService extends Service {
.setLargeIcon(icon)
.setSmallIcon(smallIcon)
.setPriority(UserPreferences.getNotifyPriority()); // set notification priority
if(newInfo.playerStatus == PlayerStatus.PLAYING){
if (newInfo.playerStatus == PlayerStatus.PLAYING) {
notificationBuilder.addAction(android.R.drawable.ic_media_pause, //pause action
getString(R.string.pause_label),
pauseButtonPendingIntent);
@ -800,11 +800,20 @@ public class PlaybackService extends Service {
getString(R.string.play_label),
playButtonPendingIntent);
}
if(UserPreferences.isPersistNotify()) {
if (UserPreferences.isPersistNotify()) {
notificationBuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel, // stop action
getString(R.string.stop_label),
stopButtonPendingIntent);
}
if (Build.VERSION.SDK_INT >= 21) {
notificationBuilder.setStyle(new Notification.MediaStyle()
.setMediaSession((android.media.session.MediaSession.Token) mediaPlayer.getSessionToken().getToken())
.setShowActionsInCompactView(0))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setColor(Notification.COLOR_DEFAULT);
}
notification = notificationBuilder.build();
} else {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(
@ -813,7 +822,7 @@ public class PlaybackService extends Service {
.setContentText(contentText).setOngoing(true)
.setContentIntent(pIntent).setLargeIcon(icon)
.setSmallIcon(smallIcon);
notification = notificationBuilder.getNotification();
notification = notificationBuilder.build();
}
startForeground(NOTIFICATION_ID, notification);
if (BuildConfig.DEBUG)

View File

@ -6,6 +6,9 @@ import android.media.AudioManager;
import android.media.RemoteControlClient;
import android.net.wifi.WifiManager;
import android.os.PowerManager;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.Pair;
@ -48,6 +51,10 @@ public class PlaybackServiceMediaPlayer {
private volatile PlayerStatus statusBeforeSeeking;
private volatile IPlayer mediaPlayer;
private volatile Playable media;
/**
* Only used for Lollipop notifications.
*/
private final MediaSessionCompat mediaSession;
private volatile boolean stream;
private volatile MediaType mediaType;
@ -89,6 +96,10 @@ public class PlaybackServiceMediaPlayer {
}
);
mediaSession = new MediaSessionCompat(context, TAG);
mediaSession.setCallback(sessionCallback);
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mediaPlayer = null;
statusBeforeSeeking = null;
pausedBecauseOfTransientAudiofocusLoss = false;
@ -181,6 +192,7 @@ public class PlaybackServiceMediaPlayer {
setPlayerStatus(PlayerStatus.INITIALIZING, media);
try {
media.loadMetadata();
mediaSession.setMetadata(getMediaSessionMetadata(media));
if (stream) {
mediaPlayer.setDataSource(media.getStreamUrl());
} else {
@ -211,6 +223,13 @@ public class PlaybackServiceMediaPlayer {
}
}
private MediaMetadataCompat getMediaSessionMetadata(Playable p) {
MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, p.getEpisodeTitle());
builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle());
return builder.build();
}
/**
* Resumes playback if the PSMP object is in PREPARED or PAUSED state. If the PSMP object is in an invalid state.
@ -603,6 +622,9 @@ public class PlaybackServiceMediaPlayer {
if (mediaPlayer != null) {
mediaPlayer.release();
}
if (mediaSession != null) {
mediaSession.release();
}
releaseWifiLockIfNecessary();
}
@ -666,6 +688,16 @@ public class PlaybackServiceMediaPlayer {
return new PSMPInfo(playerStatus, media);
}
/**
* Returns a token to this object's MediaSession. The MediaSession should only be used for notifications
* at the moment.
*
* @return The MediaSessionCompat.Token object.
*/
public MediaSessionCompat.Token getSessionToken() {
return mediaSession.getSessionToken();
}
/**
* Sets the player status of the PSMP object. PlayerStatus and media attributes have to be set at the same time
* so that getPSMPInfo can't return an invalid state (e.g. status is PLAYING, but media is null).
@ -683,6 +715,45 @@ public class PlaybackServiceMediaPlayer {
this.playerStatus = newStatus;
this.media = newMedia;
PlaybackStateCompat.Builder sessionState = new PlaybackStateCompat.Builder();
int state;
if (playerStatus != null) {
switch (playerStatus) {
case PLAYING:
state = PlaybackStateCompat.STATE_PLAYING;
break;
case PREPARED:
case PAUSED:
state = PlaybackStateCompat.STATE_PAUSED;
break;
case STOPPED:
state = PlaybackStateCompat.STATE_STOPPED;
break;
case SEEKING:
state = PlaybackStateCompat.STATE_FAST_FORWARDING;
break;
case PREPARING:
case INITIALIZING:
state = PlaybackStateCompat.STATE_CONNECTING;
break;
case INITIALIZED:
case INDETERMINATE:
state = PlaybackStateCompat.STATE_NONE;
break;
case ERROR:
state = PlaybackStateCompat.STATE_ERROR;
break;
default:
state = PlaybackStateCompat.STATE_NONE;
break;
}
} else {
state = PlaybackStateCompat.STATE_NONE;
}
sessionState.setState(state, PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN, getPlaybackSpeed());
callback.statusChanged(new PSMPInfo(playerStatus, media));
}
@ -980,4 +1051,54 @@ public class PlaybackServiceMediaPlayer {
}
});
}
private final MediaSessionCompat.Callback sessionCallback = new MediaSessionCompat.Callback() {
@Override
public void onPlay() {
if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) {
resume();
} else if (playerStatus == PlayerStatus.INITIALIZED) {
setStartWhenPrepared(true);
prepare();
}
}
@Override
public void onPause() {
super.onPause();
if (playerStatus == PlayerStatus.PLAYING) {
pause(false, true);
}
if (UserPreferences.isPersistNotify()) {
pause(false, true);
} else {
pause(true, true);
}
}
@Override
public void onSkipToNext() {
super.onSkipToNext();
endPlayback();
}
@Override
public void onFastForward() {
super.onFastForward();
seekDelta(UserPreferences.getSeekDeltaMs());
}
@Override
public void onRewind() {
super.onRewind();
seekDelta(-UserPreferences.getSeekDeltaMs());
}
@Override
public void onSeekTo(long pos) {
super.onSeekTo(pos);
seekTo((int) pos);
}
};
}