Media Session Compat not showing Lockscreen controls on Pre-Lollipop
Solution 1
Finally I figured a solution for this. Thanks to @ianhanniballake & @user1549672
- Add Audio Focus as suggested by @ianhanniballake
- Add Music Intent
BroadcastReceiver
can be found if searched on Google & also on Official Android Docs - Write the
setupMediaSession()
given in my question above -
VERY IMPORTANT Mention the
Flags
properly - Write
MediaSessionCallbacks
also available above -
VERY IMPORTANT Update the
MediaSession
onMediaPlayer#onPause()
,MediaPlayer#onStart()
& finally when new song is played (also includes next & previous played) mentioned by @user1549672 - Release the
MediaSession
object inonDestory()
Well that's all, most of the material (code) is available above. This question took couple of months to solve, finally it's done.
Solution 2
While not strictly required for MediaSession
, RemoteControlClient
used on API14-19 devices, does require audio focus and it is 100% strongly recommended for all media playback.
Adding lines such as:
AudioManager audioManager = (AudioManager)
getSystemService(Context.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(this,
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (result != AudioManager.AUDIOFOCUS_GAIN) {
return; //Failed to gain audio focus
}
Before playing any media should gain audio focus and show controls.
Solution 3
Finally I got an answer to your's and my problem .Issue is you need to specify actions (mMediaSessionCompat.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE) even while updating mediasession. So your code should now look like
private void updateMediaSessionMetaData() {
int playState = mPlaying
? PlaybackStateCompat.STATE_PLAYING
: PlaybackStateCompat.STATE_PAUSED;
mMediaSessionCompat.setMetadata(new MediaMetadataCompat.Builder()
.putString(MediaMetadata.METADATA_KEY_ARTIST, getArtist())
.putString(MediaMetadata.METADATA_KEY_ALBUM, getAlbum())
.putString(MediaMetadata.METADATA_KEY_TITLE, getSongTitle())
.putLong(MediaMetadata.METADATA_KEY_DURATION, duration())
.putLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER, mSongPosn)
.putLong(MediaMetadata.METADATA_KEY_NUM_TRACKS, songs.size())
.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, albumArt)
.build());
mMediaSessionCompat.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(playState, position(), 1.0f)
.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE| PlaybackStateCompat.ACTION_SKIP_TO_NEXT|PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS).build());
UPDATE : Added code for MediaCallback & Receiver
private final class MediaSessionCallback extends MediaSessionCompat.Callback {
@Override
public void onPlay() {
pausePlayer();
}
@Override
public void onPause() {
pausePlayer();
}
public void onSeekTo(long pos) {
seek(pos);
}
@Override
public void onSkipToNext() {
playNext();
}
@Override
public void onSkipToPrevious() {
playPrev();
}
}
Receiver :
public class MusicIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(
android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
Intent intent1 = new Intent(MusicService.ACTION_PAUSE);
intent1.setClass(context,
com.xyz.service.MusicService.class);
// send an intent to our MusicService to telling it to pause the
// audio
context.startService(intent1);
} else if (intent.getAction().equals(Intent.ACTION_MEDIA_BUTTON)) {
KeyEvent keyEvent = (KeyEvent) intent.getExtras().get(
Intent.EXTRA_KEY_EVENT);
if (keyEvent.getAction() != KeyEvent.ACTION_DOWN)
return;
switch (keyEvent.getKeyCode()) {
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
Intent intentToggle = new Intent(
MusicService.ACTION_TOGGLE_PLAYBACK);
intentToggle.setClass(context,
com.xyz.service.MusicService.class);
context.startService(intentToggle);
break;
case KeyEvent.KEYCODE_MEDIA_PLAY:
Intent intentPlay = new Intent(MusicService.ACTION_PLAY);
intentPlay.setClass(context,
com.xyz.service.MusicService.class);
context.startService(intentPlay);
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
Intent intentPause = new Intent(MusicService.ACTION_PAUSE);
intentPause.setClass(context,
com.xyz.service.MusicService.class);
context.startService(intentPause);
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
Intent intentNext = new Intent(MusicService.ACTION_NEXT);
intentNext.setClass(context,
com.xyz.service.MusicService.class);
context.startService(intentNext);
break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
Intent intentPrev = new Intent(MusicService.ACTION_PREV);
intentPrev.setClass(context,
com.xyz.service.MusicService.class);
context.startService(intentPrev);
break;
default:
break;
}
}
}
}
Akshay Chordiya
Tech Enthusiast who likes learning new tools, platforms, frameworks and a bunch of similar things. I love working on Android and it's my niche, one of the reason being it helps to build something which helps me. My Short Story I got involved in Computers by playing with them, tweaking and breaking the hardware and software. I started development and coding with Symbian Operation System (Now Deprecated). Later completing my Engineering during which I learned lots of new languages, frameworks, and basically a lot about Computers. Let's look at stats Platform Android Programming Languages Kotlin (Favorite) Java (Also Java 8) Java EE HTML 5 Python Go JavaScript C and C++ (I don't like them much though :-P) Framework Django Spring Boot Databases MySQL Postgres Oracle 11g Hadoop 1 MongoDB (Basic) Complete Story Part 1: Back to Basics I worked on Symbian which got deprecated. Then I started learning Java, C++ and C to create some cool simple software(s) to make my life easier using the Desktop Machine. Slowly I started feeling that there would be lots of people who might make use of my softwares designed but I was immature at that time and didn't have internet at home. My Work on Symbian Part 2: Joining College and Falling in Love with Android I started with Computer Engineering where I got to learn Databases like MySQL, Mongo and Hadoop, Java-EE and few small things and make more better software to help people out. But I wanted to do something more hence I started learning Android individually. I started with Android app development without having Internet at my home. Currently it's been more than 3.5 years since I started. My goal is to make my life easier and then my first useful app Automaton Locker Play Store link, it is on Play Store with more than 1 Lakh downloads. I got lots of help from XDA-Developers too and I fell in love with Android :) Part 3: Continued Making great Android apps I didn't stop with my first app. I made lots of quality apps and I'm always backed by my friends even I've never met some of them in real. Jair Music Player is one of them and now it has more than 300K+ downloads. All my apps on Play Store Part 4: Continue my Passion the entire Life This part is coming soon so stay connected ;)
Updated on June 03, 2022Comments
-
Akshay Chordiya almost 2 years
I'm using
MediaSessionCompat
from AppCompat Support Library Revision 22. And on Lollipop I'm getting notification & also the background of lockscreen is the album art. And everything works cool.While on Pre-Lollipop devices, the music controls on lockscreen are not at all shown. It's weird & I tried everything but it doesn't show up, not even the background changes.
I hope someone has solution to this issue.
Note:
RemoteControlClient
used to work on Lollipop & KitKat/** * Initializes the remote control client */ private void setupMediaSession() { /* Activate Audio Manager */ mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); ComponentName mRemoteControlResponder = new ComponentName(getPackageName(), MediaButtonReceiver.class.getName()); final Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); mediaButtonIntent.setComponent(mRemoteControlResponder); mMediaSessionCompat = new MediaSessionCompat(getApplication(), "JairSession", mRemoteControlResponder, null); mMediaSessionCompat.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); PlaybackStateCompat playbackStateCompat = new PlaybackStateCompat.Builder() .setActions( PlaybackStateCompat.ACTION_SEEK_TO | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS | PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_STOP ) .setState( isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED, getCurrentPosition(), 1.0f) .build(); mMediaSessionCompat.setPlaybackState(playbackStateCompat); mMediaSessionCompat.setCallback(mMediaSessionCallback); mMediaSessionCompat.setSessionActivity(retrievePlaybackActions(5)); mMediaSessionCompat.setActive(true); updateMediaSessionMetaData(); mTransportController = mMediaSessionCompat.getController().getTransportControls();
Here's the
updateMediaSessionMetaData()
:/** * Updates the lockscreen controls, if enabled. */ private void updateMediaSessionMetaData() { MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder(); builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, getArtistName()); builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, getAlbumName()); builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, getTrackName()); builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, getDuration()); builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, MusicUtils.getArtwork(this, getAlbumID(), true)); mMediaSessionCompat.setMetadata(builder.build());
}
The Media Session Callback methods
private final MediaSessionCompat.Callback mMediaSessionCallback = new MediaSessionCompat.Callback() { @Override public boolean onMediaButtonEvent(Intent mediaButtonEvent) { final String intentAction = mediaButtonEvent.getAction(); if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intentAction)) { if (PrefUtils.isHeadsetPause(getBaseContext())) { Log.d(LOG_TAG, "Headset disconnected"); pause(); } } else if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) { final KeyEvent event = mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); if (event == null) return super.onMediaButtonEvent(mediaButtonEvent); final int keycode = event.getKeyCode(); final int action = event.getAction(); final long eventTime = event.getEventTime(); if (event.getRepeatCount() == 0 && action == KeyEvent.ACTION_DOWN) { switch (keycode) { case KeyEvent.KEYCODE_HEADSETHOOK: if (eventTime - mLastClickTime < DOUBLE_CLICK) { playNext(mSongNumber); mLastClickTime = 0; } else { if (isPlaying()) pause(); else resume(); mLastClickTime = eventTime; } break; case KeyEvent.KEYCODE_MEDIA_STOP: mTransportController.stop(); break; case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: if (isMediaPlayerActive()) { if (isPlaying()) mTransportController.pause(); else mTransportController.play(); } break; case KeyEvent.KEYCODE_MEDIA_NEXT: mTransportController.skipToNext(); break; case KeyEvent.KEYCODE_MEDIA_PREVIOUS: mTransportController.skipToPrevious(); break; case KeyEvent.KEYCODE_MEDIA_PAUSE: mTransportController.pause(); break; case KeyEvent.KEYCODE_MEDIA_PLAY: mTransportController.play(); break; } } } return super.onMediaButtonEvent(mediaButtonEvent); } @Override public void onPlay() { super.onPlay(); resume(); } @Override public void onPause() { super.onPause(); pause(); } @Override public void onSkipToNext() { super.onSkipToNext(); playNext(mSongNumber); } @Override public void onSkipToPrevious() { super.onSkipToPrevious(); playPrevious(mSongNumber); } @Override public void onSeekTo(long pos) { super.onSeekTo(pos); seekTo(pos); } @Override public void onStop() { super.onStop(); pause(); commitMusicData(); updatePlayingUI(STOP_ACTION); stopSelf(); } };
Media Button Receiver Manifest Entry
<!-- Media button receiver --> <receiver android:name=".receiver.MediaButtonReceiver" > <intent-filter> <action android:name="android.intent.action.MEDIA_BUTTON" /> <action android:name="android.media.AUDIO_BECOMING_NOISY" /> </intent-filter> </receiver>
I'm trying since couple of weeks to solve this issue with no success, and in desperate need of help.
Edit: A tutorial or example of MediaSessionCompat would also be fine
-
Akshay Chordiya almost 9 yearsI'm already using it, but I was using it below
MediaSessionCompat
, I shifted theAudioManager
code above it. Yet it doesn't seem to work on Emulator -
ianhanniballake almost 9 yearsYou'll need to include a lot more code in your question then, ideally your entire service and your Manifest entry for the Media Button Receiver
-
Siju almost 9 yearsFacing the same issue. Can anyone help please?
-
Akshay Chordiya almost 9 years@RisingUp I felt, I'm the only one facing this issue. Hopefully we solve it
-
ianhanniballake almost 9 yearsYour code is working fine for me on an API 16 emulator - check out this super minimal example that shows lock screen controls for me.
-
Akshay Chordiya almost 9 years@ianhanniballake I'll check your minimal code, hope it work
-
Akshay Chordiya almost 9 years@ianhanniballake I'll check your minimal code, hope it work. BTW is any permission in Manifest required?
-
ianhanniballake almost 9 years@Aky - the only ones I had was
INTERNET
andACCESS_NETWORK_STATE
for downloading the mp3 I was testing with - I stripped even that out of the example (there's actually no playback at all in the example - just simulated). I did note that things in general worked much better on a real device than the emulator, so perhaps the emulator just isn't any good at testing these type of things. -
Akshay Chordiya almost 9 years@ianhanniballake I'm playing with your minimal example, I don't know but I'm damn pissed by this issue
-
Akshay Chordiya almost 9 years@ianhanniballake @RisingUp Mainly I don't understand, how come it works on
Lollipop
& not onPre-Lollipop
-
ianhanniballake almost 9 yearsHave you tried it on a real device? You may be chasing ghosts and emulator issues.
-
Akshay Chordiya almost 9 years@ianhanniballake I sometimes usually try on real device but when I don't get real device I try on emulator, the minimal example was tested on Emulator & I'm planning to test it on Real Device
-
Akshay Chordiya almost 9 years@ianhanniballake Any solution?
-
ianhanniballake almost 9 years@Aky - since the sample I provided works, the problem is with your code. Can you include any parts of your code that differ from the sample provided?
-
Akshay Chordiya almost 9 years@ianhanniballake You suggest me what should I attach? Because I have added most of the things required.
-
Akshay Chordiya almost 9 yearsI tested on real device without using track number & number tracks unfortunately it didn't work again.
-
Siju almost 9 years@Aky Did you .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE both while setting up Mediasession & updating media session both?
-
Akshay Chordiya almost 9 yearsI'll check that out, but are you using
MediaStyle
for Notification -
Akshay Chordiya almost 9 yearsIs that the reason why 'MediaSessionCompat' is not working on Pre Lollipop
-
Siju almost 9 yearsIt still works. Just try my code and tell me if you get stuck.
-
Siju almost 9 yearsCan you put your whole service,receiver & related code in pastebin or something. Let me check your code on my device.
-
Siju almost 9 yearsTry this one .I have modified your code to remove some unnecessary stuffs. pastebin.com/Kut7JEYa
-
Akshay Chordiya almost 9 yearsI'm glad, I'll try it out & let you know
-
Akshay Chordiya almost 9 yearsI tested it & didn't work. I'll perform few more tests for sure results. PS Used real device
-
Siju almost 9 yearsI wonder what's going wrong. I would suggest you to break code into small snippets and test functionality one by one.
-
Akshay Chordiya almost 9 yearsOhhkay, I'll try that too
-
user1549672 almost 9 yearsthe simple example that ianhanniballake posted worked for me!
-
Akshay Chordiya almost 9 years@user1549672 Superb, I'm yet stuck with this issue & have less time
-
SAVVY almost 7 yearsbro how you are displaying the lock scree media controller
-
Akshay Chordiya almost 7 years@SAVVY I think this piece of line tells the Android OS to show music controls on the lockscreen.
mMediaSessionCompat.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
-
SAVVY almost 7 yearsbhai can you tell me where I am doing wrong I am not getting lock screen stackoverflow.com/questions/45251734/…
-
SAVVY over 6 yearsbro I followed what you said but dont know where I am making mistake bounty is onn but still no ans hope you may guide me
-
SAVVY over 6 yearsBro i am able to get the lockscreen but it show only play pause button how i can show the next and previous button any advice?
-
Akshay Chordiya over 6 years@SAVVY Great. To show other buttons you need to set actions using
mMediaSessionCompat.setPlaybackState(new PlaybackStateCompat.Builder() .setState(playState, position(), 1.0f) .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE| PlaybackStateCompat.ACTION_SKIP_TO_NEXT|PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS).build());
-
Vipul Chauhan over 5 years@Akshay Chordiya as i see above and your answer it is difficult to implement this so if it is possible so can you please provide complete answer it will very helpful for me PLEASE SHARE YOUR ANSWER HERE stackoverflow.com/questions/54595575/… thaks in advance
-
Vipul Chauhan about 5 yearscan you please provide me the full code i am stuck from last month on this and unable to handle some problems like How to get mediasession callbacks? What is the hierarchy to set all things like mediasession, callbacks, AudioFocus, PlaybackStatus? also i don't know how and why we use playbackstatus