Java Android Media Player (notification)
Solution 1:
You should follow this old google mediaplayer sample (Use this commit if the master version crashes for you) if you want to keep using the MediaPlayer.
But If you don't mind using ExoPlayer, then you should instead follow this new one, since ExoPlayer can already take care of part of the notification stuff.
But so in these sample projects you can see that:
- It's not as simple as just a notification, it also ties into people pressing on a play button on their headset etc.
- You really need a service for this, to bind to the notification, to handle the action.MEDIA_BUTTON intents.
Minimal code for adding such a notification with a MediaSession and Service with the MediaPlayer (so not ExoPlayer) like you are using would look something like this: Add the media compat libraries to your apps' build gradle:
dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation "androidx.media:media:1.1.0"
}
Then create a class for creating the Notification:
package com.radiomedia.a1liferadio;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import androidx.media.app.NotificationCompat.MediaStyle;
import androidx.media.session.MediaButtonReceiver;
/**
* Keeps track of a notification and updates it automatically for a given MediaSession. This is
* required so that the music service don't get killed during playback.
*/publicclassMediaNotificationManager {
publicstaticfinalintNOTIFICATION_ID=412;
privatestaticfinalStringTAG= MediaNotificationManager.class.getSimpleName();
privatestaticfinalStringCHANNEL_ID="com.example.android.musicplayer.channel";
privatestaticfinalintREQUEST_CODE=501;
privatefinal MediaSessionService mService;
privatefinal NotificationCompat.Action mPlayAction;
privatefinal NotificationCompat.Action mPauseAction;
privatefinal NotificationManager mNotificationManager;
publicMediaNotificationManager(MediaSessionService musicContext) {
mService = musicContext;
mNotificationManager =
(NotificationManager) mService.getSystemService(Service.NOTIFICATION_SERVICE);
mPlayAction =
newNotificationCompat.Action(
R.drawable.ic_play,
"play",
MediaButtonReceiver.buildMediaButtonPendingIntent(
mService,
PlaybackStateCompat.ACTION_PLAY));
mPauseAction =
newNotificationCompat.Action(
R.drawable.ic_pause,
"pause",
MediaButtonReceiver.buildMediaButtonPendingIntent(
mService,
PlaybackStateCompat.ACTION_PAUSE));
// Cancel all notifications to handle the case where the Service was killed and// restarted by the system.
mNotificationManager.cancelAll();
}
publicvoidonDestroy() {
Log.d(TAG, "onDestroy: ");
}
public NotificationManager getNotificationManager() {
return mNotificationManager;
}
public Notification getNotification(MediaMetadataCompat metadata,
@NonNull PlaybackStateCompat state,
MediaSessionCompat.Token token) {
booleanisPlaying= state.getState() == PlaybackStateCompat.STATE_PLAYING;
MediaDescriptionCompatdescription= metadata.getDescription();
NotificationCompat.Builderbuilder=
buildNotification(state, token, isPlaying, description);
return builder.build();
}
private NotificationCompat.Builder buildNotification(@NonNull PlaybackStateCompat state,
MediaSessionCompat.Token token,
boolean isPlaying,
MediaDescriptionCompat description) {
// Create the (mandatory) notification channel when running on Android Oreo.if (isAndroidOOrHigher()) {
createChannel();
}
NotificationCompat.Builderbuilder=newNotificationCompat.Builder(mService, CHANNEL_ID);
builder.setStyle(
newMediaStyle()
.setMediaSession(token)
.setShowActionsInCompactView(0)
// For backwards compatibility with Android L and earlier.
.setShowCancelButton(true)
.setCancelButtonIntent(
MediaButtonReceiver.buildMediaButtonPendingIntent(
mService,
PlaybackStateCompat.ACTION_STOP)))
.setColor(ContextCompat.getColor(mService, R.color.colorPrimary))
.setSmallIcon(R.drawable.ic_play)
// Pending intent that is fired when user clicks on notification.
.setContentIntent(createContentIntent())
// Title - Usually Song name.
.setContentTitle(description.getTitle())
// When notification is deleted (when playback is paused and notification can be// deleted) fire MediaButtonPendingIntent with ACTION_PAUSE.
.setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(
mService, PlaybackStateCompat.ACTION_PAUSE));
builder.addAction(isPlaying ? mPauseAction : mPlayAction);
return builder;
}
// Does nothing on versions of Android earlier than O.@RequiresApi(Build.VERSION_CODES.O)privatevoidcreateChannel() {
if (mNotificationManager.getNotificationChannel(CHANNEL_ID) == null) {
// The user-visible name of the channel.CharSequencename="MediaSession";
// The user-visible description of the channel.Stringdescription="MediaSession and MediaPlayer";
intimportance= NotificationManager.IMPORTANCE_LOW;
NotificationChannelmChannel=newNotificationChannel(CHANNEL_ID, name, importance);
// Configure the notification channel.
mChannel.setDescription(description);
mChannel.enableLights(true);
// Sets the notification light color for notifications posted to this// channel, if the device supports this feature.
mChannel.setLightColor(Color.RED);
mChannel.enableVibration(true);
mChannel.setVibrationPattern(
newlong[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
mNotificationManager.createNotificationChannel(mChannel);
Log.d(TAG, "createChannel: New channel created");
} else {
Log.d(TAG, "createChannel: Existing channel reused");
}
}
privatebooleanisAndroidOOrHigher() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
}
private PendingIntent createContentIntent() {
IntentopenUI=newIntent(mService, MainActivity.class);
openUI.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
return PendingIntent.getActivity(
mService, REQUEST_CODE, openUI, PendingIntent.FLAG_CANCEL_CURRENT);
}
}
Then Create a Service class that handles playback and the notification button presses:
package com.radiomedia.a1liferadio;
import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.os.SystemClock;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.view.KeyEvent;
import androidx.annotation.Nullable;
publicclassMediaSessionServiceextendsService {
public MediaPlayer mediaPlayer;
publicstaticfinalStringTAG="MediaSessionService";
publicstaticfinalintNOTIFICATION_ID=888;
private MediaNotificationManager mMediaNotificationManager;
private MediaSessionCompat mediaSession;
@OverridepublicvoidonCreate() {
super.onCreate();
mediaPlayer = newMediaPlayer();
mMediaNotificationManager = newMediaNotificationManager(this);
mediaSession = newMediaSessionCompat(this, "SOME_TAG");
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mediaSession.setCallback(newMediaSessionCompat.Callback() {
@OverridepublicvoidonPlay() {
mediaPlayer.start();
}
@OverridepublicvoidonPause() {
mediaPlayer.pause();
}
});
Notificationnotification=
mMediaNotificationManager.getNotification(
getMetadata(), getState(), mediaSession.getSessionToken());
startForeground(NOTIFICATION_ID, notification);
}
public MediaMetadataCompat getMetadata() {
MediaMetadataCompat.Builderbuilder=newMediaMetadataCompat.Builder();
builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, "artist");
builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, "title");
builder.putLong(
MediaMetadataCompat.METADATA_KEY_DURATION, mediaPlayer.getDuration()
);
return builder.build();
}
private PlaybackStateCompat getState() {
longactions= mediaPlayer.isPlaying() ? PlaybackStateCompat.ACTION_PAUSE : PlaybackStateCompat.ACTION_PLAY;
intstate= mediaPlayer.isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED;
final PlaybackStateCompat.BuilderstateBuilder=newPlaybackStateCompat.Builder();
stateBuilder.setActions(actions);
stateBuilder.setState(state,
mediaPlayer.getCurrentPosition(),
1.0f,
SystemClock.elapsedRealtime());
return stateBuilder.build();
}
@OverridepublicintonStartCommand(Intent intent, int flags, int startId) {
if ("android.intent.action.MEDIA_BUTTON".equals(intent.getAction())) {
KeyEventkeyEvent= (KeyEvent) intent.getExtras().get("android.intent.extra.KEY_EVENT");
if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PAUSE) {
mediaPlayer.pause();
} else {
mediaPlayer.start();
}
}
returnsuper.onStartCommand(intent, flags, startId);
}
@Nullable@Overridepublic IBinder onBind(Intent intent) {
returnnull;
}
}
Update your manifest for declaring the service and sending the action.MEDIA_BUTTON intent to it.
<serviceandroid:name=".MediaSessionService"android:enabled="true"android:exported="true"><intent-filter><actionandroid:name="android.intent.action.MEDIA_BUTTON"/></intent-filter></service><receiverandroid:name="androidx.media.session.MediaButtonReceiver"><intent-filter><actionandroid:name="android.intent.action.MEDIA_BUTTON"/></intent-filter></receiver>
This MediaButtonReceiver above is needed for pre-OREO devices, it will forward the event to the service on those platforms.
Then start the service from your main activity.
ContextCompat.startForegroundService(
MainActivity.this.getApplicationContext(),
new Intent(MainActivity.this.getApplicationContext(), MediaSessionService.class));
Things still to do here are making your main activity send actions to your service or the player in the service somehow, updating the notification and service state on a change, but you should be able to get something working with this code and figure out the rest from the google sample code.
Solution 2:
There are two scenarios :
First
if you want to play song in background you should have to start a forground service. forground service is with notification .(pass the seekbar position, play pause state, playlist or video url to service).
After you creating custome notification with media controls whatever you want
you have to add a media player to service also pass your parameters like position , play pause state to service player that it play from your previous state of activity player.
on click of notification you have to do same parameters pass to activity .
Second
Start forground service with attaching a player and bind the activity to it, and handle all controls from notification and activity at the same time.
you can pass player controls to notfication in sense of froground service to start and play song in background .
you can use preference or tinydb for best performance in getting parameters to pass in first case.
Post a Comment for "Java Android Media Player (notification)"