Media Player controls in Notification
Asked Answered
D

5

22

I have written complete Music Player to stream music from the web, but I don't know how to put media player controls in Notification and when the screen is Lock.

I am following this tutorial to show controls in the Notification bar, but still not getting How to use same functionality in my program, I have imported required classes like: NotificationService.java and Constants.java.

This is what I am getting in Notification Bar:

[Notification]

I am confused. Why I am not getting title of the song I am playing, why pause, prev and next buttons are not working etc ...

NotificationService.java:

public class NotificationService extends Service {

    Notification status;
    private final String LOG_TAG = "NotificationService";

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        if (intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION)) {
            showNotification();
            Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();  
        } else if (intent.getAction().equals(Constants.ACTION.PREV_ACTION)) {
            Toast.makeText(this, "Clicked Previous", Toast.LENGTH_SHORT).show();
            Log.i(LOG_TAG, "Clicked Previous");
        } else if (intent.getAction().equals(Constants.ACTION.PLAY_ACTION)) {
            Toast.makeText(this, "Clicked Play", Toast.LENGTH_SHORT).show();
            Log.i(LOG_TAG, "Clicked Play");
        } else if (intent.getAction().equals(Constants.ACTION.NEXT_ACTION)) {
            Toast.makeText(this, "Clicked Next", Toast.LENGTH_SHORT).show();
            Log.i(LOG_TAG, "Clicked Next");
        } else if (intent.getAction().equals(Constants.ACTION.STOPFOREGROUND_ACTION)) {
            Log.i(LOG_TAG, "Received Stop Foreground Intent");
            Toast.makeText(this, "Service Stoped", Toast.LENGTH_SHORT).show();
            stopForeground(true);
            stopSelf();
        }
        return START_STICKY;
    }

    private void showNotification() {
        // Using RemoteViews to bind custom layouts into Notification
        RemoteViews views = new RemoteViews(getPackageName(), R.layout.status_bar);
        RemoteViews bigViews = new RemoteViews(getPackageName(), R.layout.status_bar_expanded);

        // showing default album image
        views.setViewVisibility(R.id.status_bar_icon, View.VISIBLE);
        views.setViewVisibility(R.id.status_bar_album_art, View.GONE);
        bigViews.setImageViewBitmap(R.id.status_bar_album_art,
        Constants.getDefaultAlbumArt(this));
        Intent notificationIntent = new Intent(this, MusicPlayerActivity.class);
        notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
        | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
        Intent previousIntent = new Intent(this, NotificationService.class);
        previousIntent.setAction(Constants.ACTION.PREV_ACTION);
        PendingIntent ppreviousIntent = PendingIntent.getService(this, 0, previousIntent, 0);
        Intent playIntent = new Intent(this, NotificationService.class);
        playIntent.setAction(Constants.ACTION.PLAY_ACTION);
        PendingIntent pplayIntent = PendingIntent.getService(this, 0, playIntent, 0); 
        Intent nextIntent = new Intent(this, NotificationService.class);
        nextIntent.setAction(Constants.ACTION.NEXT_ACTION);
        PendingIntent pnextIntent = PendingIntent.getService(this, 0, nextIntent, 0); 
        Intent closeIntent = new Intent(this, NotificationService.class);
        closeIntent.setAction(Constants.ACTION.STOPFOREGROUND_ACTION);
        PendingIntent pcloseIntent = PendingIntent.getService(this, 0, closeIntent, 0);
        views.setOnClickPendingIntent(R.id.status_bar_play, pplayIntent);
        bigViews.setOnClickPendingIntent(R.id.status_bar_play, pplayIntent);
        views.setOnClickPendingIntent(R.id.status_bar_next, pnextIntent);
        bigViews.setOnClickPendingIntent(R.id.status_bar_next, pnextIntent);
        views.setOnClickPendingIntent(R.id.status_bar_prev, ppreviousIntent);
        bigViews.setOnClickPendingIntent(R.id.status_bar_prev, ppreviousIntent);
        views.setOnClickPendingIntent(R.id.status_bar_collapse, pcloseIntent);
        bigViews.setOnClickPendingIntent(R.id.status_bar_collapse, pcloseIntent);
        views.setImageViewResource(R.id.status_bar_play,
        R.drawable.apollo_holo_dark_pause);
        bigViews.setImageViewResource(R.id.status_bar_play,
        R.drawable.apollo_holo_dark_pause);
        views.setTextViewText(R.id.status_bar_track_name, "Song Title");
        bigViews.setTextViewText(R.id.status_bar_track_name, "Song Title");
        views.setTextViewText(R.id.status_bar_artist_name, "Artist Name");
        bigViews.setTextViewText(R.id.status_bar_artist_name, "Artist Name");
        bigViews.setTextViewText(R.id.status_bar_album_name, "Album Name");
        status = new Notification.Builder(this).build();
        status.contentView = views;
        status.bigContentView = bigViews;
        status.flags = Notification.FLAG_ONGOING_EVENT;
        status.icon = R.drawable.ic_launcher;
        status.contentIntent = pendingIntent;
        startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE, status);
        }   

}

Constants.java:

public class Constants {
    public interface ACTION {
        public static String MAIN_ACTION = "com.marothiatechs.customnotification.action.main";
        public static String INIT_ACTION = "com.marothiatechs.customnotification.action.init";
        public static String PREV_ACTION = "com.marothiatechs.customnotification.action.prev";
        public static String PLAY_ACTION = "com.marothiatechs.customnotification.action.play";
        public static String NEXT_ACTION = "com.marothiatechs.customnotification.action.next";
        public static String STARTFOREGROUND_ACTION = "com.marothiatechs.customnotification.action.startforeground";
        public static String STOPFOREGROUND_ACTION = "com.marothiatechs.customnotification.action.stopforeground";

    }

    public interface NOTIFICATION_ID {
        public static int FOREGROUND_SERVICE = 101;
    }

    public static Bitmap getDefaultAlbumArt(Context context) {
        Bitmap bm = null;
        BitmapFactory.Options options = new BitmapFactory.Options();
        try {
            bm = BitmapFactory.decodeResource(context.getResources(),
            R.drawable.default_album_art, options);
        } catch (Error ee) {
        } catch (Exception e) {
        }
    return bm;
    }
}

MusicPlayerActivity.java:

public class MusicPlayerActivity extends Activity {

// ....

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_music_player);
        mediaPlayer = new MediaPlayer();
        audiosArrayList = new ArrayList<MusicPlayer>();
        listview = (ListView) findViewById(R.id.list_slidermenu);

    // ...

        btnPlay.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View view) {
                try {
                    play();                    
                } catch (Exception exception){
                    Log.v("exception:play", exception.toString());
                }

            }
        });

        btnPause.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View view) {
                try {
                    pause();
                } catch (Exception exception){
                    Log.v("exception:pause", exception.toString());
                }

            }
        });

        btnNext.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View view) {
                try {
                    next();
                } catch (Exception exception){
                    Log.v("exception:next", exception.toString());
                }

            }
        });

        btnPrev.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View view) { 
                try {
                    prev();
                } catch (Exception exception){
                    Log.v("exception:pause", exception.toString());
                }
            }
        });
        new JSONAsyncTask().execute("http://myurl/json/musics.json");
        listview.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {

            if (mediaPlayer != null && mediaPlayer.isPlaying())
                try {
                    mediaPlayer.stop();
                } catch (Exception e) {

                }
            play();
        }
    });

    ......

    }

    // ...

    public void startService(View v) {
        Intent serviceIntent = new Intent(MusicPlayerActivity.this, NotificationService.class);
        serviceIntent.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
        startService(serviceIntent);
    }
Dolorous answered 28/12, 2015 at 4:55 Comment(1)
check this code github.com/googlesamples/android-UniversalMusicPlayerHoggard
I
8

try something like this (i used integers for actions):

intent.putExtra("action", ACTION_EXIT);
pendingIntent = PendingIntent.getService(this, intent.getIntExtra("action", 0), intent, PendingIntent.FLAG_UPDATE_CURRENT);

in public static PendingIntent getService (Context context, int requestCode, Intent intent, int flags) the requestCode must be unique.

Imogene answered 4/1, 2016 at 13:4 Comment(0)
H
3

You need to set a custom intent action, not the AudioPlayerBroadcastReceiver component class.

Create a Intent with custom action name like this

Intent switchIntent = new Intent("com.example.app.ACTION_PLAY");

Then, register the PendingIntent Broadcast receiver

PendingIntent pendingSwitchIntent = PendingIntent.getBroadcast(this, 100, switchIntent, 0);

Then, set a onClick for the play control, do similar custom action for other controls if required.

notificationView.setOnClickPendingIntent(R.id.btn_play_pause_in_notification, pendingSwitchIntent);

Next, register the custom action in AudioPlayerBroadcastReceiver like this

<receiver android:name="com.example.app.AudioPlayerBroadcastReceiver" >
    <intent-filter>
        <action android:name="com.example.app.ACTION_PLAY" />
    </intent-filter>
</receiver>

Finally, when play is clicked on Notification RemoteViews layout, you will receive the play action by the BroadcastReceiver

public class AudioPlayerBroadcastReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {

        String action = intent.getAction();

        if(action.equalsIgnoreCase("com.example.app.ACTION_PLAY")) {
            // do your stuff to play action;
        }
    }
}

EDIT: how to set the intent filter for Broadcast receiver registered in code

You can also set the Custom Action through Intent filter from code for the registered Broadcast receiver like this

    // instance of custom broadcast receiver
CustomReceiver broadcastReceiver = new CustomReceiver();

IntentFilter intentFilter = new IntentFilter();
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
// set the custom action
intentFilter.addAction("com.example.app.ACTION_PLAY");
// register the receiver
registerReceiver(broadcastReceiver, intentFilter); 

check this link for more info

https://www.binpress.com/tutorial/using-android-media-style-notifications-with-media-session-controls/165

Hiding answered 5/1, 2016 at 20:51 Comment(0)
M
2

Did you find a solution? I can explain to you with another code. It's a little bit similar, but I have modified it because I am playing a Streaming Audio. Let me know if you need some help.

I just want to share with you my showNotification() method

private void showNotification() {

    if (intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION)) {

        //Start IntentNotification
        Log.i(LOG_TAG, "Received Start Foreground Intent ");
        Intent notificationIntent = new Intent(ForegroundService.this, MainActivity.class);
        notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);

        //With this settings you can open the same Activity without recreate.
        //But you have to put in your AndroidManifest.xml the next line: to your Activity
        //activity android:name=".MainActivity" android:launchMode="singleInstance"

        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        //Intent for Play
        Intent playIntent = new Intent(this, ForegroundService.class);
        playIntent.setAction(Constants.ACTION.PLAY_ACTION);
        PendingIntent pplayIntent = PendingIntent.getService(this, 0, playIntent, 0);

        //Intent for Pause
        Intent pausaIntent = new Intent(this, ForegroundService.class);
        pausaIntent.setAction(Constants.ACTION.PAUSE_ACTION);
        PendingIntent pauseIntent = PendingIntent.getService(this, 0, pausaIntent, 0);

        //Intent for Close
        stopIntent = new Intent(this, ForegroundService.class);
        stopIntent.setAction(Constants.ACTION.CLOSE_ACTION);
        PendingIntent closeIntent = PendingIntent.getService(this, 0, stopIntent, 0);

        //Icon for your notification
        Bitmap icon = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);

        notifManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);


        PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0,
                new Intent(getApplicationContext(), MainActivity.class),
                PendingIntent.FLAG_UPDATE_CURRENT);

        // Build the notification object.
        mNotificationBuilder = new Notification.Builder(this)
                .setContentTitle("Thinking out Loud")
                .setContentText("Ed Sheeran")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
                .setContentIntent(pendingIntent)
                .setOngoing(true)
                .addAction(R.drawable.ic_play_service, "PLAY", pplayIntent) //you can set a specific icon
                .addAction(R.drawable.ic_pause_service, "PAUSE", pauseIntent) //you can set a specific icon
                .addAction(R.drawable.ic_close_service, "CLOSE", closeIntent);//you can set a specific icon

        startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE, mNotificationBuilder.build());

    } else if (intent.getAction().equals(Constants.ACTION.PLAY_ACTION)) {
        Log.i(LOG_TAG, "Clicked Play");

        //Click Play notification
    } else if (intent.getAction().equals(Constants.ACTION.PAUSE_ACTION)) {
        Log.i(LOG_TAG, "Clicked PAUSE");

        //This is for Pause
    } else if (intent.getAction().equals(Constants.ACTION.CLOSE_ACTION)) {
        Log.i(LOG_TAG, "Clicked Close");

        //This is for close the NotificationService
        stopForeground(true);

    } else if (intent.getAction().equals(Constants.ACTION.STOPFOREGROUND_ACTION)) {
        Log.i(LOG_TAG, "Received Stop Foreground Intent");
        stopForeground(true);

        //Stop Notification Service
        stopSelf();
    }
}

My Constants.class

public class Constants {
    public interface ACTION {
        public static String MAIN_ACTION = "action.main";
        public static String PREV_ACTION = "action.prev";
        public static String PLAY_ACTION = "action.play";
        public static String PAUSE_ACTION = "action.pause";
        public static String NEXT_ACTION = "action.next";
        public static String CLOSE_ACTION = "action.close";
        public static String STARTFOREGROUND_ACTION = "action.startforeground";
        public static String STOPFOREGROUND_ACTION = "action.stopforeground";
    }

    public interface NOTIFICATION_ID {
        public static int FOREGROUND_SERVICE = 101;
    }
}
Midweek answered 21/10, 2016 at 16:30 Comment(0)
P
0

All of you PendingIntents have same requestCode. That is the primary reason why other notification actions are not working.

Change request codes.

PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

PendingIntent ppreviousIntent = PendingIntent.getService(this, 1, previousIntent, 0);

PendingIntent pplayIntent = PendingIntent.getService(this, 2, playIntent, 0); 

PendingIntent pnextIntent = PendingIntent.getService(this, 3, nextIntent, 0); 

PendingIntent pcloseIntent = PendingIntent.getService(this, 4, closeIntent, 0);
Pressure answered 21/11, 2019 at 19:28 Comment(0)
D
0

To achieve this you need media session and notification builber as the following :

private void createMediaSession(){

    mediaSessionCompat = new MediaSessionCompat(this, "media session");

    stateBuilder = new PlaybackStateCompat.Builder()
            .setActions(
                    PlaybackStateCompat.ACTION_PLAY |
                            PlaybackStateCompat.ACTION_PAUSE |
                            PlaybackStateCompat.ACTION_PLAY_PAUSE |
                            PlaybackStateCompat.ACTION_SKIP_TO_NEXT |
                            PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
            );
    mediaSessionCompat.setMediaButtonReceiver(null);
    mediaSessionCompat.setPlaybackState(stateBuilder.build());
    mediaSessionCompat.setCallback(new MediaSessionCompat.Callback() {
        @Override
        public void onPlay() {
            super.onPlay();

            //write code to control your music
        }

        @Override
        public void onPause() {
            super.onPause();

            //write code to control your music
        }

        @Override
        public void onSkipToNext() {
            super.onSkipToNext();

            //write code to control your music
        }

        @Override
        public void onSkipToPrevious() {
            super.onSkipToPrevious();

            //write code to control your music
        }
    });

    mediaSessionCompat.setActive(true);
}

private void showNotification(){

    notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
    
    NotificationCompat.Action playPauseAction = new NotificationCompat.Action(
            icon, string,
            MediaButtonReceiver.buildMediaButtonPendingIntent(this,
                    PlaybackStateCompat.ACTION_PLAY_PAUSE)
    );


    PendingIntent contentPendingIntent = PendingIntent.getActivity(this,
            0, new Intent(this, MainActivity.class),0
    );

    notificationBuilder.setContentTitle("Song Title")
            .setSmallIcon(R.mipmap.ic_launcher_round)
            .setContentIntent(contentPendingIntent)
            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
            .addAction(playPauseAction)
            .setPriority(NotificationCompat.PRIORITY_MAX)
            .setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
                    .setMediaSession(mediaSessionCompat.getSessionToken())
                    .setShowActionsInCompactView(0));

    notificationManager =
            (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    notificationManager.notify(0, notificationBuilder.build());

}

finally you need to create a broadcast receiver as the following

public static class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        MediaButtonReceiver.handleIntent(mediaSessionCompat, intent);
    }
}

and you should add the following dependency in the gradle

implementation 'androidx.media:media:1.1.0'

now you're ready to call the showNotification() method wherever you want to show your notification. If you still having problems you can take a look at this tutorial for your reference

Dey answered 9/9, 2020 at 22:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.