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