diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a47d8f79..072ab231 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -158,14 +158,6 @@ THE SOFTWARE. - - - - - - - * - * 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 . - */ - -package ch.blinkenlights.android.vanilla; - -import android.annotation.TargetApi; -import android.app.PendingIntent; -import android.content.Context; -import android.content.BroadcastReceiver; -import android.content.Intent; -import android.content.IntentFilter; -import android.graphics.Bitmap; -import android.provider.MediaStore; -import android.database.Cursor; -import android.database.DatabaseUtils; -import android.media.MediaDescription; -import android.media.MediaMetadata; -import android.media.browse.MediaBrowser; -import android.media.browse.MediaBrowser.MediaItem; -import android.media.session.MediaSession; -import android.media.session.PlaybackState; -import android.service.media.MediaBrowserService; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Bundle; -import android.os.Message; -import android.os.Looper; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Process; -import android.os.SystemClock; -import android.util.Log; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Handles Music Playback through MirrorLink(tm) by implementing a MediaBrowserService. - */ - -@TargetApi(21) -public class MirrorLinkMediaBrowserService extends MediaBrowserService - implements Handler.Callback, - TimelineCallback { - - private static final String TAG = "MirrorLinkMediaBrowserService"; - // Action to change the repeat mode - private static final String CUSTOM_ACTION_REPEAT = "ch.blinkenlights.android.vanilla.REPEAT"; - // Action to change the repeat mode - private static final String CUSTOM_ACTION_SHUFFLE = "ch.blinkenlights.android.vanilla.SHUFFLE"; - - // Media managers - private MediaAdapter mArtistAdapter; - private MediaAdapter mAlbumAdapter; - private MediaAdapter mSongAdapter; - private MediaAdapter mPlaylistAdapter; - private MediaAdapter mGenreAdapter; - private MediaAdapter[] mMediaAdapters = new MediaAdapter[MediaUtils.TYPE_GENRE + 1]; - private List mQueryResult = new ArrayList(); - - private final List mMediaRoot = new ArrayList(); - - // Media Session - private MediaSession mSession; - private Bundle mSessionExtras; - - // Indicates whether the service was started. - private boolean mServiceStarted; - - private Looper mLooper; - private Handler mHandler; - - @Override - public void onCreate() { - Log.d("VanillaMusic", "MediaBrowserService#onCreate"); - super.onCreate(); - - HandlerThread thread = new HandlerThread("MediaBrowserService", Process.THREAD_PRIORITY_DEFAULT); - thread.start(); - - // Prep the Media Adapters (caches the top categories) - mArtistAdapter = new MediaAdapter(this, MediaUtils.TYPE_ARTIST, null ,null); - mAlbumAdapter = new MediaAdapter(this, MediaUtils.TYPE_ALBUM, null, null); - mSongAdapter = new MediaAdapter(this, MediaUtils.TYPE_SONG, null, null); - mPlaylistAdapter = new MediaAdapter(this, MediaUtils.TYPE_PLAYLIST, null, null); - mGenreAdapter = new MediaAdapter(this, MediaUtils.TYPE_GENRE, null, null); - mMediaAdapters[MediaUtils.TYPE_ARTIST] = mArtistAdapter; - mMediaAdapters[MediaUtils.TYPE_ALBUM] = mAlbumAdapter; - mMediaAdapters[MediaUtils.TYPE_SONG] = mSongAdapter; - mMediaAdapters[MediaUtils.TYPE_PLAYLIST] = mPlaylistAdapter; - mMediaAdapters[MediaUtils.TYPE_GENRE] = mGenreAdapter; - - // Fill and cache the top queries - - mMediaRoot.add(new MediaBrowser.MediaItem( - new MediaDescription.Builder() - .setMediaId(Integer.toString(MediaUtils.TYPE_ARTIST)) - .setTitle(getString(R.string.artists)) - .setIconUri(Uri.parse("android.resource://" + - "ch.blinkenlights.android.vanilla/drawable/ic_menu_music_library")) - .setSubtitle(getString(R.string.artists)) - .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE - )); - - mMediaRoot.add(new MediaBrowser.MediaItem( - new MediaDescription.Builder() - .setMediaId(Integer.toString(MediaUtils.TYPE_ALBUM)) - .setTitle(getString(R.string.albums)) - .setIconUri(Uri.parse("android.resource://" + - "ch.blinkenlights.android.vanilla/drawable/ic_menu_music_library")) - .setSubtitle(getString(R.string.albums)) - .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE - )); - - mMediaRoot.add(new MediaBrowser.MediaItem( - new MediaDescription.Builder() - .setMediaId(Integer.toString(MediaUtils.TYPE_SONG)) - .setTitle(getString(R.string.songs)) - .setIconUri(Uri.parse("android.resource://" + - "ch.blinkenlights.android.vanilla/drawable/ic_menu_music_library")) - .setSubtitle(getString(R.string.songs)) - .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE - )); - - mMediaRoot.add(new MediaBrowser.MediaItem( - new MediaDescription.Builder() - .setMediaId(Integer.toString(MediaUtils.TYPE_GENRE)) - .setTitle(getString(R.string.genres)) - .setIconUri(Uri.parse("android.resource://" + - "ch.blinkenlights.android.vanilla/drawable/ic_menu_music_library")) - .setSubtitle(getString(R.string.genres)) - .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE - )); - - mMediaRoot.add(new MediaBrowser.MediaItem( - new MediaDescription.Builder() - .setMediaId(Integer.toString(MediaUtils.TYPE_PLAYLIST)) - .setTitle(getString(R.string.playlists)) - .setIconUri(Uri.parse("android.resource://" + - "ch.blinkenlights.android.vanilla/drawable/ic_menu_music_library")) - .setSubtitle(getString(R.string.playlists)) - .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE - )); - - - // Start a new MediaSession - mSession = new MediaSession(this, "VanillaMediaBrowserService"); - setSessionToken(mSession.getSessionToken()); - mSession.setCallback(new MediaSessionCallback()); - mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS); - mSessionExtras = new Bundle(); - mSession.setExtras(mSessionExtras); - - // Register with the PlaybackService - PlaybackService.addTimelineCallback(this); - - // Make sure the PlaybackService is running - if(!PlaybackService.hasInstance()) { - Thread t = new Thread(new Runnable() { - @Override - public void run() { - PlaybackService.get(MirrorLinkMediaBrowserService.this); - } - }); - t.start(); - } - - mLooper = thread.getLooper(); - mHandler = new Handler(mLooper, this); - - updatePlaybackState(null); - setSong(0, null); - } - - @Override - public int onStartCommand(Intent startIntent, int flags, int startId) { - Log.d("VanillaMusic", "MediaBrowserService#onStartCommand"); - return START_STICKY; - } - - @Override - public void onDestroy() { - Log.d("VanillaMusic", "MediaBrowserService#onDestroy"); - mServiceStarted = false; - PlaybackService.removeTimelineCallback(this); - mSession.release(); - } - - /** - * Helper class to encode/decode item references - * derived from queries in a string - */ - private static class MediaID { - // Separators used to build MediaIDs for the MediaBrowserService - public static final String ID_TYPE_ROOT = Integer.toString(MediaUtils.TYPE_INVALID); - public static final String MEDIATYPE_SEPARATOR = "/"; - public static final String FILTER_SEPARATOR = "#"; - - final int mType; - final long mId; - final String mLabel; - - public MediaID(int type, long id, String label) { - mType = type; - mId = id; - mLabel = label; - } - - public MediaID(String mediaId) { - int type = MediaUtils.TYPE_INVALID; - long id = -1; - String label = null; - if(mediaId != null) { - String[] items = mediaId.split(MEDIATYPE_SEPARATOR); - type = items.length > 0 ? Integer.parseInt(items[0]) : MediaUtils.TYPE_INVALID; - if(items.length > 1) { - items = items[1].split(FILTER_SEPARATOR); - if(items.length >= 2) { - label = items[1]; - id = Long.parseLong(items[0]); - } - } - } - mType = type; - mId = id; - mLabel = label; - } - - public boolean isTopAdapter() { - return mId == -1; - } - - public boolean isInvalid() { - return mType == MediaUtils.TYPE_INVALID; - } - - @Override - public String toString() { - return toString(mType, mId, mLabel); - } - - public static boolean isTopAdapter(String mediaId) { - return mediaId.indexOf(MEDIATYPE_SEPARATOR) == -1; - } - - public static String toString(int type, long id, String label) { - return Integer.toString(type) - + (id == -1 ? "" : ( - MEDIATYPE_SEPARATOR - + id - + (label == null ? "" : - FILTER_SEPARATOR - + label - ) - ) - ); - } - } - - private static Limiter buildLimiterFromMediaID(MediaID parent) { - Limiter limiter = null; - String[] fields; - Object data; - if(!parent.isInvalid() && !parent.isTopAdapter()) { - switch(parent.mType) { - case MediaUtils.TYPE_ARTIST: - // expand using a album query limited by artist - fields = new String[] { parent.mLabel }; - data = String.format("%s=%d", MediaStore.Audio.Media.ARTIST_ID, parent.mId); - limiter = new Limiter(MediaUtils.TYPE_ARTIST, fields, data); - break; - case MediaUtils.TYPE_ALBUM: - // expand using a song query limited by album - fields = new String[] { parent.mLabel }; - data = String.format("%s=%d", MediaStore.Audio.Media.ALBUM_ID, parent.mId); - limiter = new Limiter(MediaUtils.TYPE_SONG, fields, data); - break; - case MediaUtils.TYPE_GENRE: - // expand using an artist limiter by genere - fields = new String[] { parent.mLabel }; - data = parent.mId; - limiter = new Limiter(MediaUtils.TYPE_GENRE, fields, data); - break; - case MediaUtils.TYPE_PLAYLIST: - // don't build much, a a playlist is playable but not expandable - case MediaUtils.TYPE_SONG: - // don't build much, a song is playable but not expandable - case MediaUtils.TYPE_INVALID: - break; - } - } - return limiter; - } - - private QueryTask buildQueryFromMediaID(MediaID parent, boolean empty, boolean all) - { - String[] projection; - - if (parent.mType == MediaUtils.TYPE_PLAYLIST) { - projection = empty ? Song.EMPTY_PLAYLIST_PROJECTION : Song.FILLED_PLAYLIST_PROJECTION; - } else { - projection = empty ? Song.EMPTY_PROJECTION : Song.FILLED_PROJECTION; - } - - QueryTask query; - if (all && (parent.mType != MediaUtils.TYPE_PLAYLIST)) { - query = (mMediaAdapters[parent.mType]).buildSongQuery(projection); - query.data = parent.mId; - query.mode = SongTimeline.MODE_PLAY_ID_FIRST; - } else { - query = MediaUtils.buildQuery(parent.mType, parent.mId, projection, null); - query.mode = SongTimeline.MODE_PLAY; - } - - return query; - } - - private void loadChildrenAsync( final MediaID parent, - final Result> result) { - - // Asynchronously load the music catalog in a separate thread - final Limiter limiter = buildLimiterFromMediaID(parent); - new AsyncTask() { - private static final int ASYNCTASK_SUCCEEDED = 1; - private static final int ASYNCTASK_FAILED = 0; - - @Override - protected Integer doInBackground(Void... params) { - int result = ASYNCTASK_FAILED; - try { - mQueryResult.clear(); - clearLimiters(); - if(parent.isTopAdapter()) { - runQuery(mQueryResult, parent.mType, mMediaAdapters[parent.mType]); - } else if (limiter != null) { - switch(limiter.type) { - case MediaUtils.TYPE_ALBUM: - mSongAdapter.setLimiter(limiter); - runQuery(mQueryResult, MediaUtils.TYPE_SONG, mSongAdapter); - break; - case MediaUtils.TYPE_ARTIST: - mAlbumAdapter.setLimiter(limiter); - runQuery(mQueryResult, MediaUtils.TYPE_ALBUM, mAlbumAdapter); - break; - case MediaUtils.TYPE_SONG: - mSongAdapter.setLimiter(limiter); - runQuery(mQueryResult, MediaUtils.TYPE_SONG, mSongAdapter); - break; - case MediaUtils.TYPE_PLAYLIST: - mPlaylistAdapter.setLimiter(limiter); - runQuery(mQueryResult, MediaUtils.TYPE_PLAYLIST, mPlaylistAdapter); - break; - case MediaUtils.TYPE_GENRE: - mSongAdapter.setLimiter(limiter); - runQuery(mQueryResult, MediaUtils.TYPE_SONG, mSongAdapter); - break; - } - } - result = ASYNCTASK_SUCCEEDED; - } catch (Exception e) { - Log.d("VanillaMusic","Failed retrieving Media"); - } - return Integer.valueOf(result); - } - - @Override - protected void onPostExecute(Integer current) { - List items = null; - if (result != null) { - items = mQueryResult; - try { - if (current == ASYNCTASK_SUCCEEDED) { - result.sendResult(items); - } else { - result.sendResult(Collections.emptyList()); - } - } catch (IndexOutOfBoundsException e) { - Log.v("VanillaMusic", "result.send failed: " + e); - } - } - } - }.execute(); - } - - private void clearLimiters() { - for(MediaAdapter adapter : mMediaAdapters) { - adapter.setLimiter(null); - } - } - - - private String subtitleForMediaType(int mediaType) { - switch(mediaType) { - case MediaUtils.TYPE_ARTIST: - return getString(R.string.artists); - case MediaUtils.TYPE_SONG: - return getString(R.string.songs); - case MediaUtils.TYPE_PLAYLIST: - return getString(R.string.playlists); - case MediaUtils.TYPE_GENRE: - return getString(R.string.genres); - case MediaUtils.TYPE_ALBUM: - return getString(R.string.albums); - } - return ""; - } - - private void runQuery(List populateMe, int mediaType, MediaAdapter adapter) { - populateMe.clear(); - try { - Cursor cursor = adapter.query(); - Context context = getApplicationContext(); - - if (cursor == null) { - return; - } - - final int flags = (mediaType == MediaUtils.TYPE_SONG || mediaType == MediaUtils.TYPE_PLAYLIST) ? MediaBrowser.MediaItem.FLAG_PLAYABLE : MediaBrowser.MediaItem.FLAG_BROWSABLE; - final int count = cursor.getCount(); - for (int j = 0; j != count; ++j) { - cursor.moveToPosition(j); - final String id = cursor.getString(0); - final String label = cursor.getString(2); - long mediaId = Long.parseLong(id); - - Song song = MediaUtils.getSongByTypeId(context, mediaType, mediaId); - MediaBrowser.MediaItem item = new MediaBrowser.MediaItem( - new MediaDescription.Builder() - .setMediaId(MediaID.toString(mediaType, mediaId, label)) - .setTitle(label) - .setSubtitle(subtitleForMediaType(mediaType)) - .setIconBitmap(song.getSmallCover(context)) - .build(), - flags); - populateMe.add(item); - } - - cursor.close(); - } catch (Exception e) { - Log.d("VanillaMusic","Failed retrieving Media"); - } - } - - /* - ** MediaBrowserService APIs - */ - - @Override - public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) { - return new BrowserRoot(MediaID.ID_TYPE_ROOT, null); - } - - @Override - public void onLoadChildren(final String parentMediaId, final Result> result) { - // Use result.detach to allow calling result.sendResult from another thread: - result.detach(); - if (!MediaID.ID_TYPE_ROOT.equals(parentMediaId)) { - loadChildrenAsync(new MediaID(parentMediaId), result); - } else { - result.sendResult(mMediaRoot); - } - } - - private void setSessionActive() { - if (!mServiceStarted) { - // The MirrorLinkMediaBrowserService needs to keep running even after the calling MediaBrowser - // is disconnected. Call startService(Intent) and then stopSelf(..) when we no longer - // need to play media. - startService(new Intent(getApplicationContext(), MirrorLinkMediaBrowserService.class)); - mServiceStarted = true; - } - - if (!mSession.isActive()) { - mSession.setActive(true); - } - } - - private void setSessionInactive() { - if(mServiceStarted) { - // service is no longer necessary. Will be started again if needed. - MirrorLinkMediaBrowserService.this.stopSelf(); - mServiceStarted = false; - } - - if(mSession.isActive()) { - mSession.setActive(false); - } - } - - private static final int MSG_PLAY = 1; - private static final int MSG_PLAY_QUERY = 2; - private static final int MSG_PAUSE = 3; - private static final int MSG_STOP = 4; - private static final int MSG_SEEKTO = 5; - private static final int MSG_NEXTSONG = 6; - private static final int MSG_PREVSONG = 7; - private static final int MSG_SEEKFW = 8; - private static final int MSG_SEEKBW = 9; - private static final int MSG_REPEAT = 10; - private static final int MSG_SHUFFLE = 11; - private static final int MSG_UPDATE_STATE = 12; - - @Override - public boolean handleMessage(Message message) - { - switch (message.what) { - case MSG_PLAY: - setSessionActive(); - - if(PlaybackService.hasInstance()) { - PlaybackService.get(MirrorLinkMediaBrowserService.this).play(); - } - break; - case MSG_PLAY_QUERY: - setSessionActive(); - if(PlaybackService.hasInstance()) { - QueryTask query = buildQueryFromMediaID(new MediaID((String)message.obj), false, true); - PlaybackService.get(MirrorLinkMediaBrowserService.this).addSongs(query); - } - break; - case MSG_PAUSE: - if(PlaybackService.hasInstance()) { - PlaybackService.get(MirrorLinkMediaBrowserService.this).pause(); - } - break; - case MSG_STOP: - if(PlaybackService.hasInstance()) { - PlaybackService.get(MirrorLinkMediaBrowserService.this).pause(); - } - setSessionInactive(); - break; - case MSG_SEEKTO: - if(PlaybackService.hasInstance()) { - PlaybackService.get(MirrorLinkMediaBrowserService.this).seekToProgress(message.arg1); - } - break; - case MSG_NEXTSONG: - if(PlaybackService.hasInstance()) { - PlaybackService.get(MirrorLinkMediaBrowserService.this).performAction(Action.NextSong, null); - } - break; - case MSG_PREVSONG: - if(PlaybackService.hasInstance()) { - PlaybackService.get(MirrorLinkMediaBrowserService.this).performAction(Action.PreviousSong, null); - } - break; - case MSG_SEEKFW: - if(PlaybackService.hasInstance()) { - PlaybackService.get(MirrorLinkMediaBrowserService.this).performAction(Action.SeekForward, null); - } - break; - case MSG_SEEKBW: - if(PlaybackService.hasInstance()) { - PlaybackService.get(MirrorLinkMediaBrowserService.this).performAction(Action.SeekBackward, null); - } - break; - case MSG_REPEAT: - if(PlaybackService.hasInstance()) { - PlaybackService.get(MirrorLinkMediaBrowserService.this).performAction(Action.Repeat, null); - } - break; - case MSG_SHUFFLE: - if(PlaybackService.hasInstance()) { - PlaybackService.get(MirrorLinkMediaBrowserService.this).performAction(Action.Shuffle, null); - } - break; - case MSG_UPDATE_STATE: - updatePlaybackState((String)message.obj); - break; - default: - return false; - } - - return true; - } - /* - ** MediaSession.Callback - */ - private final class MediaSessionCallback extends MediaSession.Callback { - - @Override - public void onPlay() { - mHandler.sendEmptyMessage(MSG_PLAY); - } - - @Override - public void onSeekTo(long position) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_SEEKTO, (int) position ,0)); - } - - @Override - public void onPlayFromMediaId(final String mediaId, Bundle extras) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_PLAY_QUERY, mediaId)); - } - - @Override - public void onPause() { - mHandler.sendEmptyMessage(MSG_PAUSE); - } - - @Override - public void onStop() { - mHandler.sendEmptyMessage(MSG_STOP); - } - - @Override - public void onSkipToNext() { - mHandler.sendEmptyMessage(MSG_NEXTSONG); - } - - @Override - public void onSkipToPrevious() { - mHandler.sendEmptyMessage(MSG_PREVSONG); - } - - @Override - public void onFastForward() { - mHandler.sendEmptyMessage(MSG_SEEKFW); - } - - @Override - public void onRewind() { - mHandler.sendEmptyMessage(MSG_SEEKBW); - } - - @Override - public void onCustomAction(String action, Bundle extras) { - if (CUSTOM_ACTION_REPEAT.equals(action)) { - mHandler.sendEmptyMessage(MSG_REPEAT); - } else if (CUSTOM_ACTION_SHUFFLE.equals(action)) { - mHandler.sendEmptyMessage(MSG_SHUFFLE); - } - } - - @Override - public void onPlayFromSearch(final String query, final Bundle extras) { - mHandler.sendEmptyMessage(MSG_PLAY); - } - } - - /** - * Update the current media player state, optionally showing an error message. - * - * @param error if not null, error message to present to the user. - */ - private void updatePlaybackState(String error) { - long position = PlaybackState.PLAYBACK_POSITION_UNKNOWN; - int state = PlaybackState.STATE_PAUSED; - - if(PlaybackService.hasInstance()) { - if (PlaybackService.get(this).isPlaying()) { - state = PlaybackState.STATE_PLAYING; - } - position = PlaybackService.get(this).getPosition(); - } - - PlaybackState.Builder stateBuilder = new PlaybackState.Builder() - .setActions(getAvailableActions()); - - setCustomAction(stateBuilder); - - // If there is an error message, send it to the playback state: - if (error != null) { - // Error states are really only supposed to be used for errors that cause playback to - // stop unexpectedly and persist until the user takes action to fix it. - stateBuilder.setErrorMessage(error); - state = PlaybackState.STATE_ERROR; - } - stateBuilder.setState(state, position, 1.0f, SystemClock.elapsedRealtime()); - mSession.setPlaybackState(stateBuilder.build()); - - } - // 'DriveSafe' icons need to meet contrast requirement, and as such are usually - // monochrome in nature, hence the new repeat_inactive_service and shuffle_inactive_service - // artwork - - private static final int[] FINISH_ICONS = - { R.drawable.repeat_inactive_service - , R.drawable.repeat_active - , R.drawable.repeat_current_active - , R.drawable.stop_current_active - , R.drawable.random_active }; - - private static final int[] SHUFFLE_ICONS = - { R.drawable.shuffle_inactive_service - , R.drawable.shuffle_active - , R.drawable.shuffle_album_active }; - - private void setCustomAction(PlaybackState.Builder stateBuilder) { - if(PlaybackService.hasInstance()) { - Bundle customActionExtras = new Bundle(); - final int finishMode = PlaybackService.finishAction(PlaybackService.get(this).getState()); - final int shuffleMode = PlaybackService.shuffleMode(PlaybackService.get(this).getState()); - - stateBuilder.addCustomAction(new PlaybackState.CustomAction.Builder( - CUSTOM_ACTION_REPEAT, getString(R.string.cycle_repeat_mode), FINISH_ICONS[finishMode]) - .setExtras(customActionExtras) - .build()); - - stateBuilder.addCustomAction(new PlaybackState.CustomAction.Builder( - CUSTOM_ACTION_SHUFFLE, getString(R.string.cycle_shuffle_mode), SHUFFLE_ICONS[shuffleMode]) - .setExtras(customActionExtras) - .build()); - } - } - - private long getAvailableActions() { - long actions = PlaybackState.ACTION_PLAY | - PlaybackState.ACTION_PLAY_FROM_MEDIA_ID | - PlaybackState.ACTION_PLAY_FROM_SEARCH | - PlaybackState.ACTION_SKIP_TO_PREVIOUS | - PlaybackState.ACTION_SKIP_TO_NEXT; - - if(PlaybackService.hasInstance()) { - if (PlaybackService.get(this).isPlaying()) { - actions |= PlaybackState.ACTION_PAUSE; - actions |= PlaybackState.ACTION_FAST_FORWARD; - actions |= PlaybackState.ACTION_REWIND; - } - } - return actions; - } - - /** - * Implementation of the PlaybackService callbacks - */ - public void onTimelineChanged() { - mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_STATE, null)); - } - - public void setState(long uptime, int state) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_STATE, null)); - } - - public void replaceSong(int delta, Song song) { - } - - public void onMediaChange() { - setSong(0, null); - } - - public void recreate() { - } - - public void setSong(long uptime, Song song) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_STATE, null)); - if(song == null) { - if(PlaybackService.hasInstance()) { - song = PlaybackService.get(this).getSong(0); - } - } - - if(song != null) { - long[] androidIds = MediaUtils.getAndroidMediaIds(getApplicationContext(), song); - long songId = androidIds[0]; - if (songId != -1) { - MediaMetadata metadata = new MediaMetadata.Builder() - .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, Long.toString(songId)) - .putString(MediaMetadata.METADATA_KEY_ALBUM, song.album) - .putString(MediaMetadata.METADATA_KEY_ARTIST, song.artist) - .putLong(MediaMetadata.METADATA_KEY_DURATION, song.duration) - .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, "content://media/external/audio/media/" + Long.toString(songId) + "/albumart") - .putString(MediaMetadata.METADATA_KEY_TITLE, song.title) - .putLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER, song.trackNumber) - .build(); - mSession.setMetadata(metadata); - } - } - } - - public void onPositionInfoChanged() { - mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_STATE, null)); - // updatePlaybackState(null); - } - - public void onError(String error) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_STATE, error)); - // updatePlaybackState(error); - } - -} diff --git a/app/src/main/java/ch/blinkenlights/android/vanilla/PlaybackService.java b/app/src/main/java/ch/blinkenlights/android/vanilla/PlaybackService.java index f6a582c2..92d31d52 100644 --- a/app/src/main/java/ch/blinkenlights/android/vanilla/PlaybackService.java +++ b/app/src/main/java/ch/blinkenlights/android/vanilla/PlaybackService.java @@ -1197,35 +1197,14 @@ public final class PlaybackService extends Service } /** - * When playing through MirrorLink(tm) don't interact - * with the User directly as this is considered distracting - * while driving + * Enqueues a Toast message to be shown. */ - private void showMirrorLinkSafeToast(int resId, int duration) { - if(getMirrorLinkCallback() == null) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_SHOW_TOAST, duration, resId)); - } + private void showToast(int resId, int duration) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_SHOW_TOAST, duration, resId)); } - private void showMirrorLinkSafeToast(CharSequence text, int duration) { - if(getMirrorLinkCallback() == null) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_SHOW_TOAST, duration, 0, text)); - } - } - - /** - * Returns TRUE if the mirror link service has been registered - */ - private MirrorLinkMediaBrowserService getMirrorLinkCallback() { - if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) - return null; // does not support mirrorlink - - for (Object o : sCallbacks) { - if (o instanceof MirrorLinkMediaBrowserService) { - return (MirrorLinkMediaBrowserService)o; - } - } - return null; + private void showToast(CharSequence text, int duration) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_SHOW_TOAST, duration, 0, text)); } /** @@ -1238,7 +1217,7 @@ public final class PlaybackService extends Service synchronized (mStateLock) { if ((mState & FLAG_EMPTY_QUEUE) != 0) { setFinishAction(SongTimeline.FINISH_RANDOM); - showMirrorLinkSafeToast(R.string.random_enabling, Toast.LENGTH_SHORT); + showToast(R.string.random_enabling, Toast.LENGTH_SHORT); } int state = updateState(mState | FLAG_PLAYING); @@ -1428,7 +1407,7 @@ public final class PlaybackService extends Service } catch (IOException e) { mErrorMessage = getResources().getString(R.string.song_load_failed, song.path); updateState(mState | FLAG_ERROR); - showMirrorLinkSafeToast(mErrorMessage, Toast.LENGTH_LONG); + showToast(mErrorMessage, Toast.LENGTH_LONG); Log.e("VanillaMusic", "IOException", e); /* Automatically advance to next song IF we are currently playing or already did skip something @@ -1469,10 +1448,6 @@ public final class PlaybackService extends Service { Log.e("VanillaMusic", "MediaPlayer error: " + what + ' ' + extra); - MirrorLinkMediaBrowserService service = getMirrorLinkCallback(); - if(service != null) { - service.onError("MediaPlayer Error"); - } return true; } @@ -1864,7 +1839,7 @@ public final class PlaybackService extends Service default: throw new IllegalArgumentException("Invalid add mode: " + query.mode); } - showMirrorLinkSafeToast(getResources().getQuantityString(text, count, count), Toast.LENGTH_SHORT); + showToast(getResources().getQuantityString(text, count, count), Toast.LENGTH_SHORT); } /** @@ -2320,7 +2295,7 @@ public final class PlaybackService extends Service break; case ClearQueue: clearQueue(); - showMirrorLinkSafeToast(R.string.queue_cleared, Toast.LENGTH_SHORT); + showToast(R.string.queue_cleared, Toast.LENGTH_SHORT); break; case ToggleControls: case ShowQueue: