I'm trying to use MediaSessionCompat in order to add lock screen player controls and meta data for my app. Everything I tried doesn't work. The lock screen doesn't show any controls or meta data while playing. Please see my current code below and any help is appreciated.
StreamService.java:
public class StreamService extends Service implements MediaPlayer.OnCuePointReceivedListener, MediaPlayer.OnStateChangedListener,
MediaPlayer.OnInfoListener, AudioManager.OnAudioFocusChangeListener {
private WifiManager.WifiLock wifiLock;
private static String LOG_TAG = "StreamService";
public static final String BROADCAST_PLAYER_STATE = "com.test.BROADCAST_PLAYER_STATE";
public static final String BROADCAST_PLAYER_META = "com.test.BROADCAST_PLAYER_META";
public static final String BROADCAST_PLAYER_ALBUM = "com.test.BROADCAST_PLAYER_ALBUM";
public static final int NOTIFICATION_ID = 999999;
private MediaSessionCompat mediaSession;
private boolean audioInterrupted = false;
public StreamService() {
}
@Override
public void onCreate(){
super.onCreate();
setupMediaPlayer();
setupMediaSession();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public boolean onUnbind(Intent intent){
releasePlayer();
return false;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
private void setupMediaPlayer() {
// Recreate player
Bundle playerSettings = (BrandedApplication.getContext().getmTritonPlayer() == null) ? null : BrandedApplication.getContext().getmTritonPlayer().getSettings();
Bundle inputSettings = createPlayerSettings();
if (!Utility.bundleEquals(inputSettings, playerSettings)) {
releasePlayer();
createPlayer(inputSettings);
}
// Start the playback
play();
}
private void setupMediaSession() {
ComponentName receiver = new ComponentName(getPackageName(), RemoteReceiver.class.getName());
mediaSession = new MediaSessionCompat(this, "StreamService", receiver, null);
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PAUSED, 0, 0)
.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE)
.build());
mediaSession.setMetadata(new MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, "Test Artist")
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, "Test Album")
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Test Track Name")
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, 10000)
.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART,
BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
//.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, "Test Artist")
.build());
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.requestAudioFocus(new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
// Ignore
}
}, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
mediaSession.setActive(true);
}
synchronized private void play() {
audioInterrupted = false;
BrandedApplication.getContext().getmTritonPlayer().play();
if(wifiLock != null) {
wifiLock.acquire();
}
if(mediaSession != null) {
mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PLAYING, 0, 1.0f)
.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE).build());
}
}
synchronized private void stop() {
BrandedApplication.getContext().getmTritonPlayer().stop();
if(wifiLock != null) {
wifiLock.release();
}
if(mediaSession != null) {
mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PAUSED, 0, 0.0f)
.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE).build());
}
}
private void createPlayer(Bundle settings)
{
BrandedApplication.getContext().setmTritonPlayer(new TritonPlayer(this, settings));
wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
.createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
BrandedApplication.getContext().getmTritonPlayer().setOnCuePointReceivedListener(this);
BrandedApplication.getContext().getmTritonPlayer().setOnInfoListener(this);
BrandedApplication.getContext().getmTritonPlayer().setOnStateChangedListener(this);
}
protected void releasePlayer() {
if (BrandedApplication.getContext().getmTritonPlayer() != null) {
if(BrandedApplication.getContext().isPlaying()) {
stop();
}
BrandedApplication.getContext().getmTritonPlayer().release();
BrandedApplication.getContext().setmTritonPlayer(null);
}
stopForeground(true);
}
protected Bundle createPlayerSettings() {
// Player Settings
Bundle settings = new Bundle();
// AAC
settings.putString(TritonPlayer.SETTINGS_STATION_MOUNT, getResources().getString(R.string.station_stream_mount) + "AAC");
// MP3
//settings.putString(TritonPlayer.SETTINGS_STATION_MOUNT, mountID);
settings.putString(TritonPlayer.SETTINGS_STATION_BROADCASTER, getResources().getString(R.string.app_name));
settings.putString(TritonPlayer.SETTINGS_STATION_NAME, getResources().getString(R.string.app_name));
return settings;
}
@Override
public void onCuePointReceived(MediaPlayer mediaPlayer, Bundle bundle) {
//System.out.println("TRITON PLAYER BUNDLE " + bundle);
String trackName = "";
String artistName = "";
if(bundle != null) {
if(bundle.containsKey("cue_title") && bundle.containsKey("track_artist_name")) {
if (!bundle.getString("cue_title").isEmpty()) {
trackName = bundle.getString("cue_title");
}
if (!bundle.getString("track_artist_name").isEmpty()) {
artistName = bundle.getString("track_artist_name");
}
}
}
// broadcast out the meta data
Intent i = new Intent(BROADCAST_PLAYER_META);
i.putExtra("trackName", trackName);
i.putExtra("artistName", artistName);
sendBroadcast(i);
// send notification and start as foreground service
PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(getApplicationContext(), MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.drawable.logo);
String tickerString = "";
String contentString = "Playing";
if(!artistName.isEmpty() && !trackName.isEmpty()) {
tickerString = artistName + " - " + trackName;
contentString += ": " + artistName + " - " + trackName;
}
Intent pauseIntent = new Intent(BROADCAST_PLAYER_PAUSE);
PendingIntent pausePendingIntent = PendingIntent.getBroadcast(this, 0, pauseIntent, 0);
NotificationCompat.Builder notification = new NotificationCompat.Builder(this)
.setContentTitle(getResources().getString(R.string.app_name))
.setTicker(tickerString)
.setContentText(contentString)
.setSmallIcon(R.drawable.ic_launcher)
//.setAutoCancel(true)
//.setLargeIcon(
// Bitmap.createScaledBitmap(icon, 128, 128, false))
.addAction(R.drawable.ic_media_pause, "Pause", pausePendingIntent)
.setContentIntent(pi)
.setStyle(new android.support.v7.app.NotificationCompat.MediaStyle()
//.setShowActionsInCompactView(0)
.setMediaSession(mediaSession.getSessionToken()))
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setOngoing(true);
//notification.setPriority(Notification.PRIORITY_MIN);
notification.setPriority(Notification.PRIORITY_DEFAULT);
startForeground(NOTIFICATION_ID, notification.build());
}
@Override
public void onInfo(MediaPlayer mediaPlayer, int i, int i1) {
}
@Override
public void onStateChanged(MediaPlayer mediaPlayer, int state) {
Log.i(LOG_TAG, "onStateChanged: " + TritonPlayer.debugStateToStr(state));
// broadcast out the player state
Intent i = new Intent(BROADCAST_PLAYER_STATE);
i.putExtra("state", state);
sendBroadcast(i);
}
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
// resume playback
System.out.println("AUDIO FOCUS GAIN");
if(audioInterrupted) {
audioInterrupted = false;
if (BrandedApplication.getContext().getmTritonPlayer() == null) {
setupMediaPlayer();
} else if (!BrandedApplication.getContext().isPlaying()) {
setupMediaPlayer();
}
}
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
case AudioManager.AUDIOFOCUS_LOSS:
System.out.println("AUDIO FOCUS LOSS");
// Lost focus for an unbounded amount of time: stop playback and release media player
if (BrandedApplication.getContext().isPlaying()) {
audioInterrupted = true;
releasePlayer();
}
break;
}
}
@Override
public void onDestroy() {
System.out.println("SERVICE STOPPED");
releasePlayer();
mediaSession.release();
}
}
And here's RemoteReceiver.java:
public class RemoteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (event != null && event.getAction() == KeyEvent.ACTION_DOWN) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
context.startService(new Intent(context, StreamService.class));
break;
}
}
}
}
}
Okay, from the additional information you provided, I believe I know what the issue is. In Android 5.0 Lock Screen Controls were removed. They are now implemented via the Notification API. So try adding the following to your notification builder.
notification.setStyle(new NotificationCompat.MediaStyle()
.setShowActionsInCompactView(0)
.setMediaSession(mediaSession));
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
That should place it on your lock screen. I would also suggest changing the Notification.PRIORITY_DEFAULT
as well as include an action to your notification otherwise you won't be able to control the playback.