25

I know that this topic has been already discussed here, here and here, and the answer seems to be that it is not possible.

But I recently installed Spotify in my Nexus 4 (4.4.2), and it seems to be possible. When I listen a song in Spotify the lock screen background change with the cover of the album that I'm listening (see screenshots).

My theory was: when the phone is locked they change the phone wallpaper with the album cover in order to change also the lock screen background, then they set back the previous one when the phone is unlocked. But this is not how they do it, because in the permissions list of Spotify there is no "android.permission.SET_WALLPAPER"... :(

How do they do it? Some theory?

Screenshot lock screen Screenshot lock screen

Nifhel
  • 2,013
  • 2
  • 26
  • 39

6 Answers6

12

Edit: The solution below only works for applications that have registered itself as a media controller, so apps that don't play audio can't/shouldn't use this mechanism to change the lockscreen wallpaper.


It can be done using RemoteControlClient, part of Android since ICS. If you want a working example, download VLC for Android and check out org.videolan.vlc.AudioService:

This part of the code is to intercept media controls.

/**
 * Set up the remote control and tell the system we want to be the default receiver for the MEDIA buttons
 * @see http://android-developers.blogspot.fr/2010/06/allowing-applications-to-play-nicer.html
 */
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public void setUpRemoteControlClient() {
    Context context = VLCApplication.getAppContext();
    AudioManager audioManager = (AudioManager)context.getSystemService(AUDIO_SERVICE);

    if(Util.isICSOrLater()) {
        audioManager.registerMediaButtonEventReceiver(mRemoteControlClientReceiverComponent);

        if (mRemoteControlClient == null) {
            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
            mediaButtonIntent.setComponent(mRemoteControlClientReceiverComponent);
            PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(context, 0, mediaButtonIntent, 0);

            // create and register the remote control client
            mRemoteControlClient = new RemoteControlClient(mediaPendingIntent);
            audioManager.registerRemoteControlClient(mRemoteControlClient);
        }

        mRemoteControlClient.setTransportControlFlags(
                RemoteControlClient.FLAG_KEY_MEDIA_PLAY |
                RemoteControlClient.FLAG_KEY_MEDIA_PAUSE |
                RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS |
                RemoteControlClient.FLAG_KEY_MEDIA_NEXT |
                RemoteControlClient.FLAG_KEY_MEDIA_STOP);
    } else if (Util.isFroyoOrLater()) {
        audioManager.registerMediaButtonEventReceiver(mRemoteControlClientReceiverComponent);
    }
}

This part is to update artwork, among other info:

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void updateRemoteControlClientMetadata() {
    if(!Util.isICSOrLater()) // NOP check
        return;

    if (mRemoteControlClient != null) {
        MetadataEditor editor = mRemoteControlClient.editMetadata(true);
        editor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, getCurrentMedia().getAlbum());
        editor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, getCurrentMedia().getArtist());
        editor.putString(MediaMetadataRetriever.METADATA_KEY_GENRE, getCurrentMedia().getGenre());
        editor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, getCurrentMedia().getTitle());
        editor.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, getCurrentMedia().getLength());
        editor.putBitmap(MetadataEditor.BITMAP_KEY_ARTWORK, getCover());
        editor.apply();
    }
}
Kai
  • 15,284
  • 6
  • 51
  • 82
1

For me, the most instructive example was Random Music Player, mentioned in documentation about Android 4.0 APIs:

"For a sample implementation, see the Random Music Player, which provides compatibility logic such that it enables the remote control client on Android 4.0 devices while continuing to support devices back to Android 2.1."

In addition, I converted text to bitmap to have text as album art.

Community
  • 1
  • 1
Juuso Ohtonen
  • 8,826
  • 9
  • 65
  • 98
1

Well, after trying some ways, I have a simple code here; Try using this method;

private void updateMetaData() {
    mediaSession =new MediaSessionCompat(context,"BXPlayer");

    Bitmap cover = BitmapFactory.decodeResource(context.getResources(),
            R.drawable.cover2); 

   mediaSession.setMetadata(new MediaMetadataCompat.Builder()
            .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, cover)
            .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, mSelectedSong.getArtist())
            .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, mSelectedSong.getAlbum())
            .putString(MediaMetadataCompat.METADATA_KEY_TITLE, mSelectedSong.getTitle())
            .build());
}

then in your notification you need to set style to android.support.v4.media.app.NotificationCompat.MediaStyle() and set the media session token to use the current metadata. Check this snippet below;

builder.setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
            .setShowActionsInCompactView(0, 1, 2)
    .setMediaSession(mediaSession.getSessionToken()));
    return builder.build();

To work, you must include implementation "com.android.support:support-v4:$latest_version" in your app build.gradle And boom! you are good to go.

Carlos Anyona
  • 641
  • 1
  • 7
  • 17
  • mediasession.getSessionToken actually i don't understand how to set this type of notification please check the link https://stackoverflow.com/questions/54633202/how-to-set-mediaplayer-notification-with-mediasession-and-notificationcompat-med?noredirect=1#comment96070177_54633202 – Vipul Chauhan Feb 12 '19 at 12:57
  • @VipulChauhan, I migrated my project to Kotlin but I have recreated a code that covers what you have asked in the other quiz. please check this code here: https://github.com/carloscj6/MusicPlayerService/blob/master/MediaPlayerService.java. – Carlos Anyona Feb 12 '19 at 16:02
  • your code is too hard to understand for new developer please can you provide proper explanation for the code like.... Where to use the methods? How to show and handle actions? Thanks in advance – Vipul Chauhan Feb 13 '19 at 07:26
  • 1
    @VipulChauhan Since I migrated my initial project to Kotlin, I have coded another in Java and uploaded the whole source code here: https://github.com/carloscj6/SampleMusicPlayer also I am working on publishing a tutorial in detail. I hope that will help you a lot. Cheers!! – Carlos Anyona Feb 14 '19 at 00:55
  • okay and thanks alot @Carlos Anyona may be it will definitely help me – Vipul Chauhan Feb 14 '19 at 08:00
  • @VipulChauhan, I am done you can check here https://revosleap.com/2019/02/14/making-simple-music-player/ for more detailed instructions. – Carlos Anyona Feb 14 '19 at 12:31
  • Thanks @Carlos Anyona your project is too good it helped me so much. My problem is not completely solved but I will – Vipul Chauhan Feb 16 '19 at 09:41
  • Always glad to help @VipulChauhan, Please submit an issue on github on what you want to be covered and I will do it. – Carlos Anyona Feb 16 '19 at 10:16
  • it is work for me but not solve my problem completely like it requires minimum sdk 21, it is still not show controls on lock screen, not changing the background of lock screen please add some code for the sdk problem – Vipul Chauhan Feb 16 '19 at 10:50
0

So here is the new "official docs"

At the bottom it describes the lock screen details

https://developer.android.com/guide/topics/media-apps/working-with-a-media-session.html#maintain-state

As an alternative, once I understood all the terms and jargon, this tutorial helped me outline the general structure for the MediaSessionCompat services.

https://code.tutsplus.com/tutorials/background-audio-in-android-with-mediasessioncompat--cms-27030

Finally, there is an API for lock screen wallpaper in Nougat and greater. Why this is not support lib is beyond me at this time.

JoshuaTree
  • 1,211
  • 14
  • 19
0

as explained here the key is to to pass a MediaMetadata object to your MediaSession. If these terms seems alien to you it's best to start the linked tutorial from the top.

I found the .putBitmap(MediaMetadata.METADATA_KEY_ART, bitmap) line to be the one that is taken to load the image to the lockscreen background. But be sure to populate .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, bitmap)as well.

Sameer J
  • 226
  • 3
  • 13
0

I know this is late but perfect answer is still required. So to set lock screen background in Android (like Spotify do) we have to perform following steps.

1. set media session active mSession.setActive(true). if session is not active so it is not gona show.

2. set playback state

playBackStateBuilder = new PlaybackStateCompat.Builder()
            .setActions(PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_SKIP_TO_NEXT
                    | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
                    | PlaybackStateCompat.ACTION_STOP | PlaybackStateCompat.ACTION_PLAY_PAUSE);`

`mSession.setPlaybackState(playBackStateBuilder.setState(PlaybakStateCompate.STATE_PLAYING, 0, 0).build());

Note: lock screen image is showed when first playback state is set to playing then it can be switch to other states

3. set meta data

mSession.setMetadata(new MediaMetadataCompat.Builder()
                .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title)
                .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist)
                .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
                .build());

here KEY_ALBUM_ART is required because this is the image which is shown on lock screen.

By setting above three things it had showed on my galaxy device but not on pixels devices so for that follow last point.

4. show notification with media style

NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, CHANNEL_ID);
    builder.setStyle(
            new androidx.media.app.NotificationCompat.MediaStyle()
    );
    
    mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(121, builder.build());
Chetan Pawar
  • 404
  • 3
  • 4