/* * Copyright (C) 2014 Fastboot Mobile, LLC. * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 3 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program; * if not, see <http://www.gnu.org/licenses>. */ package com.fastbootmobile.encore.service; import android.annotation.TargetApi; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.media.AudioManager; import android.media.MediaMetadataEditor; import android.media.MediaMetadataRetriever; import android.media.RemoteControlClient; import android.os.Build; import android.util.Log; import com.fastbootmobile.encore.model.Album; import com.fastbootmobile.encore.model.Artist; import com.fastbootmobile.encore.model.Song; import com.fastbootmobile.encore.providers.ProviderAggregator; import com.fastbootmobile.encore.receivers.RemoteControlReceiver; import com.fastbootmobile.encore.utils.AvrcpUtils; import com.fastbootmobile.encore.utils.Utils; /** * Remote Metadata manager for pre-Lollipop devices */ @TargetApi(Build.VERSION_CODES.KITKAT) public class RemoteMetadataManager implements IRemoteMetadataManager { private static final String TAG = "RemoteMetadataManager"; private RemoteControlClient mClient; private final ComponentName mEventReceiver; private final AudioManager mAudioManager; private BitmapDrawable mPreviousAlbumArt; private PlaybackService mContext; public RemoteMetadataManager(PlaybackService service) { mEventReceiver = new ComponentName(service, RemoteControlReceiver.class); mContext = service; Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); mediaButtonIntent.setComponent(mEventReceiver); PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(service.getApplicationContext(), 0, mediaButtonIntent, 0); mClient = new RemoteControlClient(mediaPendingIntent); mAudioManager = (AudioManager) service.getSystemService(Context.AUDIO_SERVICE); } private int getActionsFlags(final boolean hasNext) { int actions = 0; actions |= RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE; actions |= RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS; actions |= RemoteControlClient.FLAG_KEY_MEDIA_RATING; if (hasNext) { actions |= RemoteControlClient.FLAG_KEY_MEDIA_NEXT; } return actions; } @Override public void setup() { } @Override public void release() { } @Override public void setActive(boolean active) { if (active) { mAudioManager.registerMediaButtonEventReceiver(mEventReceiver); mAudioManager.registerRemoteControlClient(mClient); } else { mAudioManager.unregisterMediaButtonEventReceiver(mEventReceiver); mAudioManager.unregisterRemoteControlClient(mClient); } } @Override public void setAlbumArt(BitmapDrawable bmp) { if (mPreviousAlbumArt != bmp) { RemoteControlClient.MetadataEditor metadata = mClient.editMetadata(false); if (bmp != null) { Bitmap bmpSource = bmp.getBitmap(); Bitmap bmpCopy = bmpSource.copy(bmpSource.getConfig(), false); mPreviousAlbumArt = bmp; metadata.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, bmpCopy); } else { metadata.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, null); } metadata.apply(); } } @Override public void setCurrentSong(Song song, boolean hasNext) { final RemoteControlClient.MetadataEditor metadata = mClient.editMetadata(false); final ProviderAggregator aggregator = ProviderAggregator.getDefault(); final Artist artist = aggregator.retrieveArtist(song.getArtist(), song.getProvider()); final Album album = aggregator.retrieveAlbum(song.getAlbum(), song.getProvider()); if (artist != null) { metadata.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, artist.getName()); } if (album != null) { metadata.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, album.getName()); } metadata.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, song.getTitle()); metadata.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, song.getDuration()); // Ensure the defined bitmap is still valid if (Utils.hasKitKat()) { Bitmap check = metadata.getBitmap(MediaMetadataEditor.BITMAP_KEY_ARTWORK, null); if (check != null && check.isRecycled()) { metadata.putBitmap(MediaMetadataEditor.BITMAP_KEY_ARTWORK, null); } } try { metadata.apply(); } catch (IllegalStateException e) { // Can happen in a race condition where the bitmap gets released during the // memory allocation of the notification. Remove the bitmap. metadata.putBitmap(MediaMetadataEditor.BITMAP_KEY_ARTWORK, null); try { metadata.apply(); } catch (IllegalStateException e1) { Log.e(TAG, "Cannot apply Remote Metadata values", e); } } mClient.setTransportControlFlags(getActionsFlags(hasNext)); AvrcpUtils.notifyMetaChanged(mContext, song.getRef().hashCode(), artist != null ? artist.getName() : null, album != null ? album.getName() : null, song.getTitle(), mContext.getQueue().size(), song.getDuration(), mContext.getCurrentTrackPositionImpl()); } @Override public void notifyPlaying(long timeElapsed) { mClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING); AvrcpUtils.notifyPlayStateChanged(mContext, true, timeElapsed); } @Override public void notifyBuffering() { mClient.setPlaybackState(RemoteControlClient.PLAYSTATE_BUFFERING); AvrcpUtils.notifyPlayStateChanged(mContext, true, 0); } @Override public void notifyPaused(long timeElapsed) { mClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED); AvrcpUtils.notifyPlayStateChanged(mContext, true, 0); } @Override public void notifyStopped() { mClient.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED); AvrcpUtils.notifyPlayStateChanged(mContext, false, 0); } }