Home | History | Annotate | Download | only in onemedia
      1 package com.android.onemedia;
      2 
      3 import android.annotation.NonNull;
      4 import android.annotation.Nullable;
      5 import android.app.Notification;
      6 import android.app.NotificationManager;
      7 import android.app.PendingIntent;
      8 import android.app.Service;
      9 import android.content.BroadcastReceiver;
     10 import android.content.ComponentName;
     11 import android.content.Context;
     12 import android.content.Intent;
     13 import android.content.IntentFilter;
     14 import android.graphics.Bitmap;
     15 import android.media.MediaDescription;
     16 import android.media.MediaMetadata;
     17 import android.media.session.MediaController;
     18 import android.media.session.MediaSession;
     19 import android.media.session.PlaybackState;
     20 import android.text.format.DateUtils;
     21 import android.util.Log;
     22 import android.util.SparseArray;
     23 
     24 import com.android.onemedia.playback.RequestUtils;
     25 
     26 /**
     27  * Keeps track of a notification and updates it automatically for a given
     28  * MediaSession.
     29  */
     30 public class NotificationHelper extends BroadcastReceiver {
     31     private static final String TAG = "NotificationHelper";
     32 
     33     private static final int NOTIFICATION_ID = 433; // John Cage, 1952
     34 
     35     private final Service mService;
     36     private final MediaSession mSession;
     37     private final MediaController mController;
     38     private final MediaController.TransportControls mTransportControls;
     39     private final SparseArray<PendingIntent> mIntents = new SparseArray<PendingIntent>();
     40 
     41     private PlaybackState mPlaybackState;
     42     private MediaMetadata mMetadata;
     43 
     44     private boolean mStarted = false;
     45 
     46     public NotificationHelper(Service service, MediaSession session) {
     47         mService = service;
     48         mSession = session;
     49         mController = session.getController();
     50         mTransportControls = mController.getTransportControls();
     51         String pkg = mService.getPackageName();
     52 
     53         mIntents.put(R.drawable.ic_pause, PendingIntent.getBroadcast(mService, 100, new Intent(
     54                 com.android.onemedia.playback.RequestUtils.ACTION_PAUSE).setPackage(pkg),
     55                 PendingIntent.FLAG_CANCEL_CURRENT));
     56         mIntents.put(R.drawable.ic_play_arrow, PendingIntent.getBroadcast(mService, 100,
     57                 new Intent(com.android.onemedia.playback.RequestUtils.ACTION_PLAY).setPackage(pkg),
     58                 PendingIntent.FLAG_CANCEL_CURRENT));
     59         mIntents.put(R.drawable.ic_skip_previous, PendingIntent.getBroadcast(mService, 100,
     60                 new Intent(com.android.onemedia.playback.RequestUtils.ACTION_PREV).setPackage(pkg),
     61                 PendingIntent.FLAG_CANCEL_CURRENT));
     62         mIntents.put(R.drawable.ic_skip_next, PendingIntent.getBroadcast(mService, 100,
     63                 new Intent(com.android.onemedia.playback.RequestUtils.ACTION_NEXT).setPackage(pkg),
     64                 PendingIntent.FLAG_CANCEL_CURRENT));
     65         mIntents.put(R.drawable.ic_fast_rewind, PendingIntent.getBroadcast(mService, 100,
     66                 new Intent(com.android.onemedia.playback.RequestUtils.ACTION_REW).setPackage(pkg),
     67                 PendingIntent.FLAG_CANCEL_CURRENT));
     68         mIntents.put(R.drawable.ic_fast_forward, PendingIntent.getBroadcast(mService, 100,
     69                 new Intent(com.android.onemedia.playback.RequestUtils.ACTION_FFWD).setPackage(pkg),
     70                 PendingIntent.FLAG_CANCEL_CURRENT));
     71     }
     72 
     73     /**
     74      * Posts the notification and starts tracking the session to keep it
     75      * updated. The notification will automatically be removed if the session is
     76      * destroyed before {@link #onStop} is called.
     77      */
     78     public void onStart() {
     79         mController.registerCallback(mCb);
     80         IntentFilter filter = new IntentFilter();
     81         filter.addAction(RequestUtils.ACTION_FFWD);
     82         filter.addAction(RequestUtils.ACTION_NEXT);
     83         filter.addAction(RequestUtils.ACTION_PAUSE);
     84         filter.addAction(RequestUtils.ACTION_PLAY);
     85         filter.addAction(RequestUtils.ACTION_PREV);
     86         filter.addAction(RequestUtils.ACTION_REW);
     87         mService.registerReceiver(this, filter);
     88 
     89         mMetadata = mController.getMetadata();
     90         mPlaybackState = mController.getPlaybackState();
     91 
     92         mStarted = true;
     93         // The notification must be updated after setting started to true
     94         updateNotification();
     95     }
     96 
     97     /**
     98      * Removes the notification and stops tracking the session. If the session
     99      * was destroyed this has no effect.
    100      */
    101     public void onStop() {
    102         mStarted = false;
    103         mController.unregisterCallback(mCb);
    104         mService.unregisterReceiver(this);
    105         updateNotification();
    106     }
    107 
    108     @Override
    109     public void onReceive(Context context, Intent intent) {
    110         final String action = intent.getAction();
    111         Log.d(TAG, "Received intent with action " + action);
    112         if (RequestUtils.ACTION_PAUSE.equals(action)) {
    113             mTransportControls.pause();
    114         } else if (RequestUtils.ACTION_PLAY.equals(action)) {
    115             mTransportControls.play();
    116         } else if (RequestUtils.ACTION_NEXT.equals(action)) {
    117             mTransportControls.skipToNext();
    118         } else if (RequestUtils.ACTION_PREV.equals(action)) {
    119             mTransportControls.skipToPrevious();
    120         } else if (RequestUtils.ACTION_REW.equals(action)) {
    121             mTransportControls.rewind();
    122         } else if (RequestUtils.ACTION_FFWD.equals(action)) {
    123             mTransportControls.fastForward();
    124         }
    125 
    126     }
    127 
    128     private final MediaController.Callback mCb = new MediaController.Callback() {
    129         @Override
    130         public void onPlaybackStateChanged(PlaybackState state) {
    131             mPlaybackState = state;
    132             Log.d(TAG, "Received new playback state" + state);
    133             updateNotification();
    134         }
    135 
    136         @Override
    137         public void onMetadataChanged(MediaMetadata metadata) {
    138             mMetadata = metadata;
    139             Log.d(TAG, "Received new metadata " + metadata);
    140             updateNotification();
    141         }
    142     };
    143 
    144     NotificationManager mNoMan = null;
    145 
    146     private void updateNotification() {
    147         if (mNoMan == null) {
    148             mNoMan = (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE);
    149         }
    150         if (mPlaybackState == null) {
    151             mNoMan.cancel(NOTIFICATION_ID);
    152             return;
    153         }
    154         if (!mStarted) {
    155             mNoMan.cancel(NOTIFICATION_ID);
    156             return;
    157         }
    158 
    159         String status;
    160         final int state = mPlaybackState.getState();
    161         switch (state) {
    162             case PlaybackState.STATE_PLAYING:
    163                 status = "PLAYING: ";
    164                 break;
    165             case PlaybackState.STATE_PAUSED:
    166                 status = "PAUSED: ";
    167                 break;
    168             case PlaybackState.STATE_STOPPED:
    169                 status = "STOPPED: ";
    170                 break;
    171             case PlaybackState.STATE_ERROR:
    172                 status = "ERROR: ";
    173                 break;
    174             case PlaybackState.STATE_BUFFERING:
    175                 status = "BUFFERING: ";
    176                 break;
    177             case PlaybackState.STATE_NONE:
    178             default:
    179                 status = "";
    180                 break;
    181         }
    182         CharSequence title, text;
    183         Bitmap art;
    184         if (mMetadata == null) {
    185             title = status;
    186             text = "Empty metadata!";
    187             art = null;
    188         } else {
    189             MediaDescription description = mMetadata.getDescription();
    190             title = description.getTitle();
    191             text = description.getSubtitle();
    192             art = description.getIconBitmap();
    193         }
    194 
    195         String playPauseLabel = "";
    196         int playPauseIcon;
    197         if (state == PlaybackState.STATE_PLAYING) {
    198             playPauseLabel = "Pause";
    199             playPauseIcon = R.drawable.ic_pause;
    200         } else {
    201             playPauseLabel = "Play";
    202             playPauseIcon = R.drawable.ic_play_arrow;
    203         }
    204 
    205         final long pos = mPlaybackState.getPosition();
    206         final long end = mMetadata == null ? 0 : mMetadata
    207                 .getLong(MediaMetadata.METADATA_KEY_DURATION);
    208         Notification notification = new Notification.Builder(mService)
    209                 .setSmallIcon(android.R.drawable.stat_notify_chat)
    210                 .setContentTitle(title)
    211                 .setContentText(text)
    212                 .setShowWhen(false)
    213                 .setContentInfo(DateUtils.formatElapsedTime(pos))
    214                 .setProgress((int) end, (int) pos, false)
    215                 .setLargeIcon(art)
    216                 .addAction(R.drawable.ic_skip_previous, "Previous",
    217                         mIntents.get(R.drawable.ic_skip_previous))
    218                 .addAction(R.drawable.ic_fast_rewind, "Rewind",
    219                         mIntents.get(R.drawable.ic_fast_rewind))
    220                 .addAction(playPauseIcon, playPauseLabel,
    221                         mIntents.get(playPauseIcon))
    222                 .addAction(R.drawable.ic_fast_forward, "Fast Forward",
    223                         mIntents.get(R.drawable.ic_fast_forward))
    224                 .addAction(R.drawable.ic_skip_next, "Next",
    225                         mIntents.get(R.drawable.ic_skip_next))
    226                 .setStyle(new Notification.MediaStyle()
    227                         .setShowActionsInCompactView(2)
    228                         .setMediaSession(mSession.getSessionToken()))
    229                 .setColor(0xFFDB4437)
    230                 .build();
    231 
    232         mService.startForeground(NOTIFICATION_ID, notification);
    233     }
    234 
    235 }
    236