package com.kure.musicplayer; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.widget.RemoteViews; import com.kure.musicplayer.activities.ActivityNowPlaying; import com.kure.musicplayer.model.Song; /** * Specific way to stick an on-going message on the system * with the current song I'm playing. * * This is a rather complicated set of functions because * it interacts with a great deal of the Android API. * Read with care. * * Thanks: * * - Gave me a complete example on how to add a custom * action to a button click on the Notification: * http://stackoverflow.com/a/21927248 */ public class NotificationMusic extends NotificationSimple { /** * Reference to the context that notified. */ Context context = null; /** * Reference to the service we're attached to. */ Service service = null; /** * Used to create and update the same notification. */ Notification.Builder notificationBuilder = null; /** * Custom appearance of the notification, also updated. */ RemoteViews notificationView = null; /** * Used to actually broadcast the notification. * Depends on the Activity that originally called * the nofitication. */ NotificationManager notificationManager = null; /** * Sends a system notification with a song's information. * * If the user clicks the notification, will be redirected * to the "Now Playing" Activity. * * If the user clicks on any of the buttons inside it, * custom actions will be executed on the * `NotificationButtonHandler` class. * * @param context Activity that calls this function. * @param service Service that calls this function. * Required so the Notification can * run on the background. * @param song Song which we'll display information. * * @note By calling this function multiple times, it'll * update the old notification. */ public void notifySong(Context context, Service service, Song song) { if (this.context == null) this.context = context; if (this.service == null) this.service = service; // Intent that launches the "Now Playing" Activity Intent notifyIntent = new Intent(context, ActivityNowPlaying.class); notifyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // Letting the Intent be executed later by other application. PendingIntent pendingIntent = PendingIntent.getActivity (context, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT); // Setting our custom appearance for the notification notificationView = new RemoteViews(kMP.packageName, R.layout.notification); // Manually settings the buttons and text // (ignoring the defaults on the XML) notificationView.setImageViewResource(R.id.notification_button_play, R.drawable.pause); notificationView.setImageViewResource(R.id.notification_button_skip, R.drawable.skip); notificationView.setTextViewText(R.id.notification_text_title, song.getTitle()); notificationView.setTextViewText(R.id.notification_text_artist, song.getArtist()); // On the notification we have two buttons - Play and Skip // Here we make sure the class `NotificationButtonHandler` // gets called when user selects one of those. // // First, building the play button and attaching it. Intent buttonPlayIntent = new Intent(context, NotificationPlayButtonHandler.class); buttonPlayIntent.putExtra("action", "togglePause"); PendingIntent buttonPlayPendingIntent = PendingIntent.getBroadcast(context, 0, buttonPlayIntent, 0); notificationView.setOnClickPendingIntent(R.id.notification_button_play, buttonPlayPendingIntent); // And now, building and attaching the Skip button. Intent buttonSkipIntent = new Intent(context, NotificationSkipButtonHandler.class); buttonSkipIntent.putExtra("action", "skip"); PendingIntent buttonSkipPendingIntent = PendingIntent.getBroadcast(context, 0, buttonSkipIntent, 0); notificationView.setOnClickPendingIntent(R.id.notification_button_skip, buttonSkipPendingIntent); // Finally... Actually creating the Notification notificationBuilder = new Notification.Builder(context); notificationBuilder.setContentIntent(pendingIntent) .setSmallIcon(R.drawable.ic_launcher_white) .setTicker("kMP: Playing '" + song.getTitle() + "' from '" + song.getArtist() + "'") .setOngoing(true) .setContentTitle(song.getTitle()) .setContentText(song.getArtist()) .setContent(notificationView); Notification notification = notificationBuilder.build(); notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); // notificationManager.notify(NOTIFICATION_ID, notification); // Sets the notification to run on the foreground. // (why not the former commented line?) service.startForeground(NOTIFICATION_ID, notification); } /** * Called when user clicks the "play/pause" button on the on-going system Notification. */ public static class NotificationPlayButtonHandler extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { kMP.musicService.togglePlayback(); } } /** * Called when user clicks the "skip" button on the on-going system Notification. */ public static class NotificationSkipButtonHandler extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { kMP.musicService.next(true); kMP.musicService.playSong(); } } /** * Updates the Notification icon if the music is paused. */ public void notifyPaused(boolean isPaused) { if ((notificationView == null) || (notificationBuilder == null)) return; int iconID = ((isPaused)? R.drawable.play : R.drawable.pause); notificationView.setImageViewResource(R.id.notification_button_play, iconID); notificationBuilder.setContent(notificationView); // notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); // Sets the notification to run on the foreground. // (why not the former commented line?) service.startForeground(NOTIFICATION_ID, notificationBuilder.build()); } /** * Cancels this notification. */ public void cancel() { service.stopForeground(true); notificationManager.cancel(NOTIFICATION_ID); } /** * Cancels all sent notifications. */ public static void cancelAll(Context c) { NotificationManager manager = (NotificationManager)c.getSystemService(Context.NOTIFICATION_SERVICE); manager.cancelAll(); } }