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: