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 f
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
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
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);
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;
}
}
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.