1a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim/* 2a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Copyright (C) 2015 The Android Open Source Project 3a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 4a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Licensed under the Apache License, Version 2.0 (the "License"); 5a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * you may not use this file except in compliance with the License. 6a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * You may obtain a copy of the License at 7a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 8a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * http://www.apache.org/licenses/LICENSE-2.0 9a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 10a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Unless required by applicable law or agreed to in writing, software 11a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * distributed under the License is distributed on an "AS IS" BASIS, 12a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * See the License for the specific language governing permissions and 14a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * limitations under the License. 15a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 16a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 17a907614755847b2630561a1e5949b2b416600d97Sungsoo Limpackage com.example.android.supportv4.media; 18a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 19a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.app.Notification; 20a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.app.PendingIntent; 21a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.content.BroadcastReceiver; 22a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.content.Context; 23a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.content.Intent; 24a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.content.IntentFilter; 25a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.graphics.Bitmap; 26a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.graphics.BitmapFactory; 27a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.graphics.Color; 28a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.os.RemoteException; 29a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.support.v4.app.NotificationCompat; 30a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.support.v4.app.NotificationManagerCompat; 31a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.support.v4.media.MediaDescriptionCompat; 32a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.support.v4.media.MediaMetadataCompat; 33a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.support.v4.media.session.MediaControllerCompat; 34a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.support.v4.media.session.MediaSessionCompat; 35a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.support.v4.media.session.PlaybackStateCompat; 36a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.util.Log; 37a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 38a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport com.example.android.supportv4.R; 39a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport com.example.android.supportv4.media.utils.ResourceHelper; 40a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 41a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim/** 42a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Keeps track of a notification and updates it automatically for a given 43a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * MediaSession. Maintaining a visible notification (usually) guarantees that the music service 44a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * won't be killed during playback. 45a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 46a907614755847b2630561a1e5949b2b416600d97Sungsoo Limpublic class MediaNotificationManager extends BroadcastReceiver { 47a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final String TAG = "MediaNotiManager"; 48a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 49a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final int NOTIFICATION_ID = 412; 50a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final int REQUEST_CODE = 100; 51a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 52a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public static final String ACTION_PAUSE = "com.example.android.supportv4.media.pause"; 53a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public static final String ACTION_PLAY = "com.example.android.supportv4.media.play"; 54a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public static final String ACTION_PREV = "com.example.android.supportv4.media.prev"; 55a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public static final String ACTION_NEXT = "com.example.android.supportv4.media.next"; 56a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 57a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private final MediaBrowserServiceSupport mService; 58a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private MediaSessionCompat.Token mSessionToken; 59a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private MediaControllerCompat mController; 60a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private MediaControllerCompat.TransportControls mTransportControls; 61a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 62a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private PlaybackStateCompat mPlaybackState; 63a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private MediaMetadataCompat mMetadata; 64a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 65a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private NotificationManagerCompat mNotificationManager; 66a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 67a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private PendingIntent mPauseIntent; 68a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private PendingIntent mPlayIntent; 69a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private PendingIntent mPreviousIntent; 70a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private PendingIntent mNextIntent; 71a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 72a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private int mNotificationColor; 73a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 74a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private boolean mStarted = false; 75a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 76a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public MediaNotificationManager(MediaBrowserServiceSupport service) { 77a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mService = service; 78a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim updateSessionToken(); 79a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 80a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mNotificationColor = ResourceHelper.getThemeColor(mService, 81a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim android.R.attr.colorPrimary, Color.DKGRAY); 82a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 83a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mNotificationManager = NotificationManagerCompat.from(mService); 84a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 85a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String pkg = mService.getPackageName(); 86a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mPauseIntent = PendingIntent.getBroadcast(mService, REQUEST_CODE, 87a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim new Intent(ACTION_PAUSE).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); 88a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mPlayIntent = PendingIntent.getBroadcast(mService, REQUEST_CODE, 89a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim new Intent(ACTION_PLAY).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); 90a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mPreviousIntent = PendingIntent.getBroadcast(mService, REQUEST_CODE, 91a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim new Intent(ACTION_PREV).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); 92a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mNextIntent = PendingIntent.getBroadcast(mService, REQUEST_CODE, 93a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim new Intent(ACTION_NEXT).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); 94a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 95a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Cancel all notifications to handle the case where the Service was killed and 96a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // restarted by the system. 97a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mNotificationManager.cancelAll(); 98a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 99a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 100a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 101a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Posts the notification and starts tracking the session to keep it 102a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * updated. The notification will automatically be removed if the session is 103a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * destroyed before {@link #stopNotification} is called. 104a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 105a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void startNotification() { 106a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (!mStarted) { 107a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMetadata = mController.getMetadata(); 108a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mPlaybackState = mController.getPlaybackState(); 109a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 110a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // The notification must be updated after setting started to true 111a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Notification notification = createNotification(); 112a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (notification != null) { 113a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mController.registerCallback(mCb); 114a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim IntentFilter filter = new IntentFilter(); 115a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim filter.addAction(ACTION_NEXT); 116a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim filter.addAction(ACTION_PAUSE); 117a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim filter.addAction(ACTION_PLAY); 118a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim filter.addAction(ACTION_PREV); 119a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mService.registerReceiver(this, filter); 120a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 121a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mService.startForeground(NOTIFICATION_ID, notification); 122a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mStarted = true; 123a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 124a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 125a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 126a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 127a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 128a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Removes the notification and stops tracking the session. If the session 129a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * was destroyed this has no effect. 130a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 131a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void stopNotification() { 132a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mStarted) { 133a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mStarted = false; 134a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mController.unregisterCallback(mCb); 135a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim try { 136a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mNotificationManager.cancel(NOTIFICATION_ID); 137a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mService.unregisterReceiver(this); 138a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } catch (IllegalArgumentException ex) { 139a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // ignore if the receiver is not registered. 140a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 141a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mService.stopForeground(true); 142a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 143a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 144a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 145a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim @Override 146a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void onReceive(Context context, Intent intent) { 147a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim final String action = intent.getAction(); 148a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "Received intent with action " + action); 149a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim switch (action) { 150a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim case ACTION_PAUSE: 151a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mTransportControls.pause(); 152a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim break; 153a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim case ACTION_PLAY: 154a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mTransportControls.play(); 155a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim break; 156a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim case ACTION_NEXT: 157a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mTransportControls.skipToNext(); 158a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim break; 159a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim case ACTION_PREV: 160a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mTransportControls.skipToPrevious(); 161a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim break; 162a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim default: 163a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.w(TAG, "Unknown intent ignored. Action=" + action); 164a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 165a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 166a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 167a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 168a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Update the state based on a change on the session token. Called either when 169a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * we are running for the first time or when the media session owner has destroyed the session 170a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * (see {@link android.media.session.MediaController.Callback#onSessionDestroyed()}) 171a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 172a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private void updateSessionToken() { 173a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim MediaSessionCompat.Token freshToken = mService.getSessionToken(); 174a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mSessionToken == null || !mSessionToken.equals(freshToken)) { 175a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mController != null) { 176a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mController.unregisterCallback(mCb); 177a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 178a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mSessionToken = freshToken; 179a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim try { 180a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mController = new MediaControllerCompat(mService, mSessionToken); 181a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } catch (RemoteException e) { 182a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.e(TAG, "Failed to create MediaControllerCompat.", e); 183a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 184a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mTransportControls = mController.getTransportControls(); 185a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mStarted) { 186a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mController.registerCallback(mCb); 187a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 188a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 189a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 190a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 191a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private PendingIntent createContentIntent() { 192a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Intent openUI = new Intent(mService, MediaBrowserSupport.class); 193a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim openUI.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 194a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return PendingIntent.getActivity(mService, REQUEST_CODE, openUI, 195a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim PendingIntent.FLAG_CANCEL_CURRENT); 196a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 197a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 198a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private final MediaControllerCompat.Callback mCb = new MediaControllerCompat.Callback() { 199a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim @Override 200a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void onPlaybackStateChanged(PlaybackStateCompat state) { 201a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mPlaybackState = state; 202a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "Received new playback state " + state); 203a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (state != null && (state.getState() == PlaybackStateCompat.STATE_STOPPED || 204a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim state.getState() == PlaybackStateCompat.STATE_NONE)) { 205a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim stopNotification(); 206a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } else { 207a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Notification notification = createNotification(); 208a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (notification != null) { 209a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mNotificationManager.notify(NOTIFICATION_ID, notification); 210a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 211a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 212a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 213a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 214a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim @Override 215a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void onMetadataChanged(MediaMetadataCompat metadata) { 216a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMetadata = metadata; 217a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "Received new metadata " + metadata); 218a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Notification notification = createNotification(); 219a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (notification != null) { 220a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mNotificationManager.notify(NOTIFICATION_ID, notification); 221a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 222a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 223a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 224a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim @Override 225a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void onSessionDestroyed() { 226a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim super.onSessionDestroyed(); 227a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "Session was destroyed, resetting to the new session token"); 228a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim updateSessionToken(); 229a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 230a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim }; 231a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 232a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private Notification createNotification() { 233a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "updateNotificationMetadata. mMetadata=" + mMetadata); 234a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mMetadata == null || mPlaybackState == null) { 235a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return null; 236a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 237a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 238a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mService); 239a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 240a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // If skip to previous action is enabled 241a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if ((mPlaybackState.getActions() & PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS) != 0) { 242a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim notificationBuilder.addAction(R.drawable.ic_skip_previous_white_24dp, 243a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mService.getString(R.string.label_previous), mPreviousIntent); 244a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 245a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 246a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim addPlayPauseAction(notificationBuilder); 247a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 248a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // If skip to next action is enabled 249a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if ((mPlaybackState.getActions() & PlaybackStateCompat.ACTION_SKIP_TO_NEXT) != 0) { 250a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim notificationBuilder.addAction(R.drawable.ic_skip_next_white_24dp, 251a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mService.getString(R.string.label_next), mNextIntent); 252a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 253a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 254a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim MediaDescriptionCompat description = mMetadata.getDescription(); 255a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 256a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String fetchArtUrl = null; 257a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Bitmap art = null; 258a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (description.getIconUri() != null) { 259a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // This sample assumes the iconUri will be a valid URL formatted String, but 260a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // it can actually be any valid Android Uri formatted String. 261a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // async fetch the album art icon 262a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String artUrl = description.getIconUri().toString(); 263a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim art = AlbumArtCache.getInstance().getBigImage(artUrl); 264a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (art == null) { 265a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim fetchArtUrl = artUrl; 266a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // use a placeholder art while the remote art is being downloaded 267a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim art = BitmapFactory.decodeResource(mService.getResources(), 268a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim R.drawable.ic_default_art); 269a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 270a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 271a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 272a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim notificationBuilder 273a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .setColor(mNotificationColor) 274a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .setSmallIcon(R.drawable.ic_notification) 275a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) 276a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .setUsesChronometer(true) 277a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .setContentIntent(createContentIntent()) 278a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .setContentTitle(description.getTitle()) 279a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .setContentText(description.getSubtitle()) 280a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .setLargeIcon(art); 281a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 282a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim setNotificationPlaybackState(notificationBuilder); 283a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (fetchArtUrl != null) { 284a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim fetchBitmapFromURLAsync(fetchArtUrl, notificationBuilder); 285a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 286a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 287a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return notificationBuilder.build(); 288a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 289a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 290a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private void addPlayPauseAction(NotificationCompat.Builder builder) { 291a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "updatePlayPauseAction"); 292a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String label; 293a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim int icon; 294a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim PendingIntent intent; 295a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mPlaybackState.getState() == PlaybackStateCompat.STATE_PLAYING) { 296a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim label = mService.getString(R.string.label_pause); 297a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim icon = R.drawable.ic_pause_white_24dp; 298a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim intent = mPauseIntent; 299a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } else { 300a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim label = mService.getString(R.string.label_play); 301a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim icon = R.drawable.ic_play_arrow_white_24dp; 302a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim intent = mPlayIntent; 303a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 304a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim builder.addAction(new NotificationCompat.Action(icon, label, intent)); 305a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 306a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 307a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private void setNotificationPlaybackState(NotificationCompat.Builder builder) { 308a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "updateNotificationPlaybackState. mPlaybackState=" + mPlaybackState); 309a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mPlaybackState == null || !mStarted) { 310a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "updateNotificationPlaybackState. cancelling notification!"); 311a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mService.stopForeground(true); 312a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return; 313a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 314a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mPlaybackState.getState() == PlaybackStateCompat.STATE_PLAYING 315a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim && mPlaybackState.getPosition() >= 0) { 316a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "updateNotificationPlaybackState. updating playback position to " 317a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim + (System.currentTimeMillis() - mPlaybackState.getPosition()) / 1000 318a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim + " seconds"); 319a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim builder 320a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .setWhen(System.currentTimeMillis() - mPlaybackState.getPosition()) 321a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .setShowWhen(true) 322a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .setUsesChronometer(true); 323a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } else { 324a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "updateNotificationPlaybackState. hiding playback position"); 325a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim builder 326a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .setWhen(0) 327a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .setShowWhen(false) 328a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .setUsesChronometer(false); 329a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 330a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 331a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Make sure that the notification can be dismissed by the user when we are not playing: 332a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim builder.setOngoing(mPlaybackState.getState() == PlaybackStateCompat.STATE_PLAYING); 333a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 334a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 335a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private void fetchBitmapFromURLAsync(final String bitmapUrl, 336a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim final NotificationCompat.Builder builder) { 337a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim AlbumArtCache.getInstance().fetch(bitmapUrl, new AlbumArtCache.FetchListener() { 338a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim @Override 339a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void onFetched(String artUrl, Bitmap bitmap, Bitmap icon) { 340a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mMetadata != null && mMetadata.getDescription() != null && 341a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim artUrl.equals(mMetadata.getDescription().getIconUri().toString())) { 342a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // If the media is still the same, update the notification: 343a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "fetchBitmapFromURLAsync: set bitmap to " + artUrl); 344a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim builder.setLargeIcon(bitmap); 345a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mNotificationManager.notify(NOTIFICATION_ID, builder.build()); 346a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 347a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 348a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim }); 349a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 350a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim} 351