1214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer/* 2214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * Copyright (c) 2016, The Android Open Source Project 3214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * 4214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * Licensed under the Apache License, Version 2.0 (the "License"); 5214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * you may not use this file except in compliance with the License. 6214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * You may obtain a copy of the License at 7214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * 8214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * http://www.apache.org/licenses/LICENSE-2.0 9214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * 10214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * Unless required by applicable law or agreed to in writing, software 11214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * distributed under the License is distributed on an "AS IS" BASIS, 12214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * See the License for the specific language governing permissions and 14214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * limitations under the License. 15214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer */ 16214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerpackage com.android.car.stream.media; 17214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 18214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.content.Context; 19214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.graphics.Bitmap; 20214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.media.MediaDescription; 21214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.media.MediaMetadata; 22214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.media.session.PlaybackState; 23214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.net.Uri; 24214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.os.Handler; 25214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.os.Message; 26214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.support.annotation.NonNull; 27214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.support.annotation.Nullable; 28214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.text.TextUtils; 29214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.util.Log; 30214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport com.android.car.apps.common.BitmapDownloader; 31214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport com.android.car.apps.common.BitmapWorkerOptions; 32214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport com.android.car.stream.R; 33214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 34214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer/** 35214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * An service which connects to {@link MediaStateManager} for media updates (playback state and 36214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * metadata) and notifies listeners for these changes. 37214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * <p/> 38214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer */ 39214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerpublic class MediaPlaybackMonitor implements MediaStateManager.Listener { 40214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer protected static final String TAG = "MediaPlaybackMonitor"; 41214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 42214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // MSG for metadata update handler 43214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static final int MSG_UPDATE_METADATA = 1; 44214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static final int MSG_IMAGE_DOWNLOADED = 2; 45214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static final int MSG_NEW_ALBUM_ART_RECEIVED = 3; 46214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 47214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public interface MediaPlaybackMonitorListener { 48214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer void onPlaybackStateChanged(PlaybackState state); 49214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 50214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer void onMetadataChanged(String title, String text, Bitmap art, int color, String appName); 51214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 52214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer void onAlbumArtUpdated(Bitmap albumArt); 53214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 54214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer void onNewAppConnected(); 55214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 56214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer void removeMediaStreamCard(); 57214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 58214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 59214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static final String[] PREFERRED_BITMAP_ORDER = { 60214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer MediaMetadata.METADATA_KEY_ALBUM_ART, 61214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer MediaMetadata.METADATA_KEY_ART, 62214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer MediaMetadata.METADATA_KEY_DISPLAY_ICON 63214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer }; 64214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 65214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static final String[] PREFERRED_URI_ORDER = { 66214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer MediaMetadata.METADATA_KEY_ALBUM_ART_URI, 67214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer MediaMetadata.METADATA_KEY_ART_URI, 68214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI 69214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer }; 70214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 71214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private MediaMetadata mCurrentMetadata; 72214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private MediaStatusUpdateHandler mMediaStatusUpdateHandler; 73214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private MediaAppInfo mCurrentMediaAppInfo; 74214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private MediaPlaybackMonitorListener mMonitorListener; 75214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 76214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private Context mContext; 77214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 78214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private final int mIconSize; 79214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 80214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public MediaPlaybackMonitor(Context context, @NonNull MediaPlaybackMonitorListener callback) { 81214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mContext = context; 82214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMonitorListener = callback; 83214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mIconSize = mContext.getResources().getDimensionPixelSize(R.dimen.stream_media_icon_size); 84214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 85214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 86214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public final void start() { 87214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMediaStatusUpdateHandler = new MediaStatusUpdateHandler(); 88214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 89214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 90214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public final void stop() { 91214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (mMediaStatusUpdateHandler != null) { 92214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMediaStatusUpdateHandler.removeCallbacksAndMessages(null); 93214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMediaStatusUpdateHandler = null; 94214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 95214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 96214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 97214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer @Override 98214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public void onMediaSessionConnected(PlaybackState state, MediaMetadata metaData, 99214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer MediaAppInfo appInfo) { 100214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 101214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Log.d(TAG, "MediaSession onConnected called"); 102214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 103214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 104214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // If the current media app is not the same as the new media app, reset 105214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // the media app in MediaStreamManager 106214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (mCurrentMediaAppInfo == null 107214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer || !mCurrentMediaAppInfo.getPackageName().equals(appInfo.getPackageName())) { 108214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMonitorListener.onNewAppConnected(); 109214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (mMediaStatusUpdateHandler != null) { 110214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMediaStatusUpdateHandler.removeCallbacksAndMessages(null); 111214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 112214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mCurrentMediaAppInfo = appInfo; 113214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 114214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 115214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (metaData != null) { 116214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer onMetadataChanged(metaData); 117214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 118214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 119214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (state != null) { 120214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer onPlaybackStateChanged(state); 121214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 122214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 123214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 124214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer @Override 125214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public void onPlaybackStateChanged(@Nullable PlaybackState state) { 126214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 127214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Log.d(TAG, "onPlaybackStateChanged called " + state.getState()); 128214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 129214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 130214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (state == null) { 131214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Log.w(TAG, "playback state is null in onPlaybackStateChanged"); 132214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMonitorListener.removeMediaStreamCard(); 133214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return; 134214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 135214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 136214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (mMonitorListener != null) { 137214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMonitorListener.onPlaybackStateChanged(state); 138214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 139214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 140214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 141214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer @Override 142214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public void onMetadataChanged(@Nullable MediaMetadata metadata) { 143214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 144214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Log.d(TAG, "onMetadataChanged called"); 145214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 146214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (metadata == null) { 147214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMonitorListener.removeMediaStreamCard(); 148214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return; 149214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 150214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 151214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Log.d(TAG, "received " + metadata.getDescription()); 152214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 153214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // Compare the new metadata and the last we have posted notification for. If both 154214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // metadata and album art are the same, just ignore and return. If the album art is new, 155214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // update the stream item with the new album art. 156214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer MediaDescription currentDescription = mCurrentMetadata == null ? 157214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer null : mCurrentMetadata.getDescription(); 158214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 159214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (!MediaUtils.isSameMediaDescription(metadata.getDescription(), currentDescription)) { 160214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Message msg = 161214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMediaStatusUpdateHandler.obtainMessage(MSG_UPDATE_METADATA, metadata); 162214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // Remove obsolete notifications in the queue. 163214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMediaStatusUpdateHandler.removeMessages(MSG_UPDATE_METADATA); 164214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMediaStatusUpdateHandler.sendMessage(msg); 165214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } else { 166214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Bitmap newBitmap = metadata.getDescription().getIconBitmap(); 167214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (newBitmap == null) { 168214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return; 169214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 170214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (newBitmap.sameAs(mMediaStatusUpdateHandler.getCurrentIcon())) { 171214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 172214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Log.d(TAG, "Received duplicate metadata, ignoring..."); 173214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 174214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } else { 175214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // same metadata, but new album art 176214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 177214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Log.d(TAG, "Received metadata with new album art"); 178214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 179214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Message msg = mMediaStatusUpdateHandler 180214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer .obtainMessage(MSG_NEW_ALBUM_ART_RECEIVED, newBitmap); 181214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMediaStatusUpdateHandler.removeMessages(MSG_NEW_ALBUM_ART_RECEIVED); 182214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMediaStatusUpdateHandler.sendMessage(msg); 183214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 184214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 185214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 186214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 187214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer @Override 188214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public void onSessionDestroyed() { 189214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 190214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Log.d(TAG, "Media session destroyed"); 191214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 192214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMonitorListener.removeMediaStreamCard(); 193214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 194214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 195214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private class BitmapCallback extends BitmapDownloader.BitmapCallback { 196214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer final private int mSeq; 197214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 198214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public BitmapCallback(int seq) { 199214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mSeq = seq; 200214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 201214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 202214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer @Override 203214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public void onBitmapRetrieved(Bitmap bitmap) { 204214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (mMediaStatusUpdateHandler == null) { 205214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 206214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Log.d(TAG, "The callback comes after we finish"); 207214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 208214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return; 209214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 210214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Message msg = mMediaStatusUpdateHandler.obtainMessage(MSG_IMAGE_DOWNLOADED, 211214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mSeq, 0, bitmap); 212214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMediaStatusUpdateHandler.sendMessage(msg); 213214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 214214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 215214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 216214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private class MediaStatusUpdateHandler extends Handler { 217214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private int mSeq = 0; 218214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private BitmapCallback mCallback; 219214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private MediaMetadata mMetadata; 220214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private String mTitle; 221214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private String mSubtitle; 222214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private Bitmap mIcon; 223214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private Uri mIconUri; 224214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private final BitmapDownloader mDownloader = BitmapDownloader.getInstance(mContext); 225214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 226214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private void extractMetadata(MediaMetadata metadata) { 227214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (metadata == mMetadata) { 228214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // We are up to date and must return here, because we've already recycled the bitmap 229214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // inside it. 230214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return; 231214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 232214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // keep a reference so we know which metadata we have stored. 233214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMetadata = metadata; 234214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer MediaDescription description = metadata.getDescription(); 235214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mTitle = description.getTitle() == null ? null : description.getTitle().toString(); 236214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mSubtitle = description.getSubtitle() == null ? 237214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer null : description.getSubtitle().toString(); 238214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer final Bitmap originalBitmap = getMetadataBitmap(metadata); 239214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (originalBitmap != null) { 240214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mIcon = originalBitmap; 241214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } else { 242214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mIcon = null; 243214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 244214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mIconUri = getMetadataIconUri(metadata); 245214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 246214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Log.d(TAG, "Album Art Uri: " + mIconUri); 247214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 248214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 249214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 250214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private Uri getMetadataIconUri(MediaMetadata metadata) { 251214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // Get the best Uri we can find 252214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer for (int i = 0; i < PREFERRED_URI_ORDER.length; i++) { 253214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer String iconUri = metadata.getString(PREFERRED_URI_ORDER[i]); 254214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (!TextUtils.isEmpty(iconUri)) { 255214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return Uri.parse(iconUri); 256214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 257214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 258214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return null; 259214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 260214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 261214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private Bitmap getMetadataBitmap(MediaMetadata metadata) { 262214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // Get the best art bitmap we can find 263214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer for (int i = 0; i < PREFERRED_BITMAP_ORDER.length; i++) { 264214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Bitmap bitmap = metadata.getBitmap(PREFERRED_BITMAP_ORDER[i]); 265214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (bitmap != null) { 266214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 267214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Log.d(TAG, "Retrieved bitmap type: " + PREFERRED_BITMAP_ORDER[i] 268214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer + " w: " + bitmap.getWidth() 269214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer + " h: " + bitmap.getHeight()); 270214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 271214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return bitmap; 272214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 273214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 274214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return null; 275214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 276214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 277214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public Bitmap getCurrentIcon() { 278214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return mIcon; 279214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 280214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 281214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer @Override 282214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public void handleMessage(Message msg) { 283214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer MediaAppInfo mediaAppInfo = mCurrentMediaAppInfo; 284214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer int color = mediaAppInfo.getMediaClientAccentColor(); 285214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer String appName = mediaAppInfo.getAppName(); 286214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer switch (msg.what) { 287214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer case MSG_UPDATE_METADATA: 288214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mSeq++; 289214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer MediaMetadata metadata = (MediaMetadata) msg.obj; 290214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (metadata == null) { 291214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Log.w(TAG, "media metadata is null!"); 292214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return; 293214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 294214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer extractMetadata(metadata); 295214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (mCallback != null) { 296214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // it's ok to cancel a callback that has already been called, the downloader 297214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // will just ignore the operation. 298214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mDownloader.cancelDownload(mCallback); 299214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mCallback = null; 300214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 301214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (mIcon != null) { 302214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMonitorListener.onMetadataChanged(mTitle, mSubtitle, mIcon, 303214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer color, appName); 304214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } else if (mIconUri != null) { 305214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mCallback = new BitmapCallback(mSeq); 306214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mDownloader.getBitmap( 307214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer new BitmapWorkerOptions.Builder(mContext) 308214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer .resource(mIconUri).width(mIconSize) 309214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer .height(mIconSize).build(), mCallback); 310214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } else { 311214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMonitorListener.onMetadataChanged(mTitle, mSubtitle, mIcon, 312214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer color, appName); 313214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 314214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // Only set mCurrentMetadata after we have updated the listener (if the 315214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // bitmap is downloaded asynchronously, that is fine too. The stream card will 316214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // be posted, when image is downloaded.) 317214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mCurrentMetadata = metadata; 318214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer break; 319214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 320214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer case MSG_IMAGE_DOWNLOADED: 321214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 322214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Log.d(TAG, "Image downloaded..."); 323214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 324214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer int seq = msg.arg1; 325214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Bitmap bitmap = (Bitmap) msg.obj; 326214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (seq == mSeq) { 327214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMonitorListener.onMetadataChanged(mTitle, mSubtitle, bitmap, color, appName); 328214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 329214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer break; 330214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 331214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer case MSG_NEW_ALBUM_ART_RECEIVED: 332214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 333214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Log.d(TAG, "Received a new album art..."); 334214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 335214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Bitmap newAlbumArt = (Bitmap) msg.obj; 336214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer mMonitorListener.onAlbumArtUpdated(newAlbumArt); 337214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer break; 338214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer default: 339214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 340214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 341214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 342214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer} 343