10

I had gone through Lock-screen Widget documentation, i implemented it but this is not what automatically place on main Lock Window. I searching for solution which provide Media Control over Main Lock-screen window (in Jelly Bean and above) like Google Play Music Application.

Have Look on Google Play Music Lock which obviously is not Lock Screen widget.

enter image description here

Tofeeq Ahmad
  • 11,935
  • 4
  • 61
  • 87

3 Answers3

15

Have you checked RemoteControlClient? it is used for the Android Music Remote control even if the App is in Lock mode.(same like image you have attached)

Please check RemoteControlClient

Just call below method while you receiver command action for Play,Pause,Next and previous of the Song track.

  private void lockScreenControls() {

    // Use the media button APIs (if available) to register ourselves for media button
    // events

    MediaButtonHelper.registerMediaButtonEventReceiverCompat(mAudioManager, mMediaButtonReceiverComponent);
    // Use the remote control APIs (if available) to set the playback state
    if (mRemoteControlClientCompat == null) {
        Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
        intent.setComponent(mMediaButtonReceiverComponent);
        mRemoteControlClientCompat = new RemoteControlClientCompat(PendingIntent.getBroadcast(this /*context*/,0 /*requestCode, ignored*/, intent /*intent*/, 0 /*flags*/));
        RemoteControlHelper.registerRemoteControlClient(mAudioManager,mRemoteControlClientCompat);
    }
    mRemoteControlClientCompat.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
    mRemoteControlClientCompat.setTransportControlFlags(
            RemoteControlClient.FLAG_KEY_MEDIA_PAUSE |
            RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS |
            RemoteControlClient.FLAG_KEY_MEDIA_NEXT |
            RemoteControlClient.FLAG_KEY_MEDIA_STOP);

  //update remote controls
    mRemoteControlClientCompat.editMetadata(true)
            .putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, "NombreArtista")
            .putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, "Titulo Album")
            .putString(MediaMetadataRetriever.METADATA_KEY_TITLE, nombreCancion)
            //.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION,playingItem.getDuration())
                    // TODO: fetch real item artwork
            .putBitmap(RemoteControlClientCompat.MetadataEditorCompat.METADATA_KEY_ARTWORK, getAlbumArt())
            .apply();
    }
}

MediaButtonHelper Class

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.content.ComponentName;
import android.media.AudioManager;
import android.util.Log;

/**
 * Class that assists with handling new media button APIs available in API level 8.
 */
public class MediaButtonHelper {
    // Backwards compatibility code (methods available as of API Level 8)
    private static final String TAG = "MediaButtonHelper";

    static {
        initializeStaticCompatMethods();
    }

    static Method sMethodRegisterMediaButtonEventReceiver;
    static Method sMethodUnregisterMediaButtonEventReceiver;

    static void initializeStaticCompatMethods() {
        try {
            sMethodRegisterMediaButtonEventReceiver = AudioManager.class.getMethod(
                    "registerMediaButtonEventReceiver",
                    new Class[] { ComponentName.class });
            sMethodUnregisterMediaButtonEventReceiver = AudioManager.class.getMethod(
                    "unregisterMediaButtonEventReceiver",
                    new Class[] { ComponentName.class });
        } catch (NoSuchMethodException e) {
            // Silently fail when running on an OS before API level 8.
        }
    }

    public static void registerMediaButtonEventReceiverCompat(AudioManager audioManager,
            ComponentName receiver) {
        if (sMethodRegisterMediaButtonEventReceiver == null)
            return;

        try {
            sMethodRegisterMediaButtonEventReceiver.invoke(audioManager, receiver);
        } catch (InvocationTargetException e) {
            // Unpack original exception when possible
            Throwable cause = e.getCause();
            if (cause instanceof RuntimeException) {
                throw (RuntimeException) cause;
            } else if (cause instanceof Error) {
                throw (Error) cause;
            } else {
                // Unexpected checked exception; wrap and re-throw
                throw new RuntimeException(e);
            }
        } catch (IllegalAccessException e) {
            Log.e(TAG, "IllegalAccessException invoking registerMediaButtonEventReceiver.");
            e.printStackTrace();
        }
    }

    @SuppressWarnings("unused")
    public static void unregisterMediaButtonEventReceiverCompat(AudioManager audioManager,
            ComponentName receiver) {
        if (sMethodUnregisterMediaButtonEventReceiver == null)
            return;

        try {
            sMethodUnregisterMediaButtonEventReceiver.invoke(audioManager, receiver);
        } catch (InvocationTargetException e) {
            // Unpack original exception when possible
            Throwable cause = e.getCause();
            if (cause instanceof RuntimeException) {
                throw (RuntimeException) cause;
            } else if (cause instanceof Error) {
                throw (Error) cause;
            } else {
                // Unexpected checked exception; wrap and re-throw
                throw new RuntimeException(e);
            }
        } catch (IllegalAccessException e) {
            Log.e(TAG, "IllegalAccessException invoking unregisterMediaButtonEventReceiver.");
            e.printStackTrace();
        }
    }
}

Please also check this developer app given for how to integrate RemoteControlClient: Random Music Player However UI for the RemoteControlClient defer as per the device you can not updates its UI to your own but you have control to show and display the component and control of the Music app.

Update

Above mentioned class is deprecated now. So please check with Media Session for that and update accordingly.

halfer
  • 19,824
  • 17
  • 99
  • 186
Shreyash Mahajan
  • 23,386
  • 35
  • 116
  • 188
  • 1
    Thanks for this code ! but can you give us a full tutorial on how to do this ! – satyres Jan 21 '15 at 15:17
  • RemoteController is deprecated, any link to newer tutorial? – WideFide Mar 18 '16 at 16:51
  • I am getting `can't resolve MediaButtonHelper` error. Please suggest how to remove this error – Anand Savjani Jan 06 '17 at 11:52
  • 1
    @AnandSavjani added MediaButtonHelper class in answer. Please update it as per your need. :) – Shreyash Mahajan Jan 07 '17 at 08:02
  • some of these methods are deprecated now please check the link and provide answer please 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:59
  • Please do not rollback good edits, iDroid Explorer. I believe [you have been notified of this before](https://stackoverflow.com/q/52272225). You are welcome to edit my material, as long as the changes are good, and they are not retaliatory in nature. My door is always open if you want an amenable discussion about editing. – halfer Aug 12 '19 at 09:33
  • @halfer I found that you keep editing the answers and question asked/answered by me. It seems like, you are intensively doing this. Every 2-3 days, I can see the changes in my questions or answers. I would like to know the reason behind that. my door are also open to discuss on it. – Shreyash Mahajan Aug 13 '19 at 07:23
  • Hi @iDroidExplorer. I [gave an explanation here](https://chat.stackoverflow.com/transcript/197853), was that useful? – halfer Aug 20 '19 at 21:01
2

RemoteControlClient was what you were looking for, but now it's deprecated and has been replaced with MediaSession.

The docs are here: https://developer.android.com/reference/android/media/session/MediaSession.html

eremzeit
  • 4,055
  • 3
  • 30
  • 32
0

If your media controls are working good in notification and media control is already displayed on lock screen but not functional then you can follow this code to start working of the media controls(Play, pause, next, previous) on lock screen :-

private MediaSessionCompat mMediaSessionCompat;  
private AudioManager audioManager;

Call below method in onCreate of your service class:

private void RegisterRemoteClient() {
    audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    assert audioManager != null;
    audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
            AudioManager.AUDIOFOCUS_GAIN);

    ComponentName mRemoteControlResponder = new ComponentName(getPackageName(),
            NotificationBroadcast.class.getName());


    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
            )
            .build();
    mMediaSessionCompat.setPlaybackState(playbackStateCompat);
    mMediaSessionCompat.setCallback(mMediaSessionCallback);
    mMediaSessionCompat.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
}

Now create this callback in service class:

private MediaSessionCompat.Callback mMediaSessionCallback = new MediaSessionCompat.Callback() {

    @Override
    public void onPlay() {
        super.onPlay();
        mMediaSessionCompat.setActive(true);
        Log.d("dvmMediaSessionCompat ","onPlay");
        if (PlayerConstants.SONG_PAUSED){
            Controls.playControl(getApplicationContext());
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.d("dvmMediaSessionCompat ","onPause");
        if (!PlayerConstants.SONG_PAUSED){
            Controls.pauseControl(getApplicationContext());
        }
        else
            Controls.playControl(getApplicationContext());


    }
    @Override
    public void onSkipToQueueItem(long queueId) {

    }

    @Override
    public void onSeekTo(long position) {

    }

    @Override
    public void onStop() {
        Log.d("dvmMediaSessionCompat ","onStop");
    }

    @Override
    public void onSkipToNext() {
        Log.d("dvmMediaSessionCompat ","onSkipToNext");
        Controls.nextControl(getApplicationContext());
    }

    @Override
    public void onSkipToPrevious() {
        Log.d("dvmMediaSessionCompat ","onSkipToPrevious");
        Controls.previousControl(getApplicationContext());
    }

};

That's what I have done and controls are started working, I was just forgot to add setCallback on my MediaSessionCompat instance, that's why my controls was not working. But now it's working perfectly.

Note: Controls.nextControl(context) this is the method in which I have added my own functionality to switch the song, you can replace that with your logic.

halfer
  • 19,824
  • 17
  • 99
  • 186
Rahul Kamble
  • 202
  • 2
  • 3