From 90f6cd02b7968bd3f10d3a4ddd6f2a32cce3ca46 Mon Sep 17 00:00:00 2001 From: Glenn Guy Date: Thu, 11 Oct 2018 22:10:55 +1100 Subject: Migrate media libraries to support v4 --- .../dsub/service/AutoMediaBrowserService.java | 140 ++++++++++----------- .../dsub/util/compat/RemoteControlClientLP.java | 88 +++++++------ 2 files changed, 110 insertions(+), 118 deletions(-) diff --git a/app/src/main/java/github/daneren2005/dsub/service/AutoMediaBrowserService.java b/app/src/main/java/github/daneren2005/dsub/service/AutoMediaBrowserService.java index e4edabc4..b0f0f399 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/AutoMediaBrowserService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/AutoMediaBrowserService.java @@ -19,15 +19,13 @@ package github.daneren2005.dsub.service; import android.annotation.TargetApi; -import android.content.Intent; -import android.media.MediaDescription; -import android.media.MediaMetadata; -import android.media.browse.MediaBrowser; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.service.media.MediaBrowserService; import android.support.annotation.Nullable; +import android.support.v4.media.MediaBrowserCompat; +import android.support.v4.media.MediaBrowserServiceCompat; +import android.support.v4.media.MediaDescriptionCompat; import android.util.Log; import java.io.IOException; @@ -43,15 +41,13 @@ import github.daneren2005.dsub.domain.MusicFolder; import github.daneren2005.dsub.domain.Playlist; import github.daneren2005.dsub.domain.PodcastChannel; import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.domain.ServerInfo; import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.SilentServiceTask; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.util.compat.RemoteControlClientLP; @TargetApi(Build.VERSION_CODES.LOLLIPOP) -public class AutoMediaBrowserService extends MediaBrowserService { +public class AutoMediaBrowserService extends MediaBrowserServiceCompat { private static final String TAG = AutoMediaBrowserService.class.getSimpleName(); private static final String BROWSER_ROOT = "root"; private static final String BROWSER_ALBUM_LISTS = "albumLists"; @@ -83,7 +79,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { } @Override - public void onLoadChildren(String parentId, Result> result) { + public void onLoadChildren(String parentId, Result> result) { if(BROWSER_ROOT.equals(parentId)) { getRootFolders(result); } else if(BROWSER_ALBUM_LISTS.equals(parentId)) { @@ -116,46 +112,46 @@ public class AutoMediaBrowserService extends MediaBrowserService { getBookmarks(result); } else { // No idea what it is, send empty result - result.sendResult(new ArrayList()); + result.sendResult(new ArrayList()); } } - private void getRootFolders(Result> result) { - List mediaItems = new ArrayList<>(); + private void getRootFolders(Result> result) { + List mediaItems = new ArrayList<>(); - MediaDescription.Builder albumLists = new MediaDescription.Builder(); + MediaDescriptionCompat.Builder albumLists = new MediaDescriptionCompat.Builder(); albumLists.setTitle(downloadService.getString(R.string.main_albums_title)) .setMediaId(BROWSER_ALBUM_LISTS); - mediaItems.add(new MediaBrowser.MediaItem(albumLists.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(albumLists.build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE)); - MediaDescription.Builder library = new MediaDescription.Builder(); + MediaDescriptionCompat.Builder library = new MediaDescriptionCompat.Builder(); library.setTitle(downloadService.getString(R.string.button_bar_browse)) .setMediaId(BROWSER_LIBRARY); - mediaItems.add(new MediaBrowser.MediaItem(library.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(library.build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE)); - MediaDescription.Builder playlists = new MediaDescription.Builder(); + MediaDescriptionCompat.Builder playlists = new MediaDescriptionCompat.Builder(); playlists.setTitle(downloadService.getString(R.string.button_bar_playlists)) .setMediaId(BROWSER_PLAYLISTS); - mediaItems.add(new MediaBrowser.MediaItem(playlists.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(playlists.build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE)); if(Util.getPreferences(downloadService).getBoolean(Constants.PREFERENCES_KEY_PODCASTS_ENABLED, true)) { - MediaDescription.Builder podcasts = new MediaDescription.Builder(); + MediaDescriptionCompat.Builder podcasts = new MediaDescriptionCompat.Builder(); podcasts.setTitle(downloadService.getString(R.string.button_bar_podcasts)) .setMediaId(BROWSER_PODCASTS); - mediaItems.add(new MediaBrowser.MediaItem(podcasts.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(podcasts.build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE)); } if(Util.getPreferences(downloadService).getBoolean(Constants.PREFERENCES_KEY_BOOKMARKS_ENABLED, true)) { - MediaDescription.Builder podcasts = new MediaDescription.Builder(); + MediaDescriptionCompat.Builder podcasts = new MediaDescriptionCompat.Builder(); podcasts.setTitle(downloadService.getString(R.string.button_bar_bookmarks)) .setMediaId(BROWSER_BOOKMARKS); - mediaItems.add(new MediaBrowser.MediaItem(podcasts.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(podcasts.build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE)); } result.sendResult(mediaItems); } - private void getAlbumLists(Result> result) { + private void getAlbumLists(Result> result) { List albums = new ArrayList<>(); albums.add(R.string.main_albums_newest); albums.add(R.string.main_albums_random); @@ -166,20 +162,20 @@ public class AutoMediaBrowserService extends MediaBrowserService { albums.add(R.string.main_albums_recent); albums.add(R.string.main_albums_frequent); - List mediaItems = new ArrayList<>(); + List mediaItems = new ArrayList<>(); for(Integer id: albums) { - MediaDescription description = new MediaDescription.Builder() + MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setTitle(downloadService.getResources().getString(id)) .setMediaId(ALBUM_TYPE_PREFIX + id) .build(); - mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_BROWSABLE)); } result.sendResult(mediaItems); } - private void getAlbumList(final Result> result, final int id) { + private void getAlbumList(final Result> result, final int id) { new SilentServiceTask(downloadService) { @Override protected MusicDirectory doInBackground(MusicService musicService) throws Throwable { @@ -212,16 +208,16 @@ public class AutoMediaBrowserService extends MediaBrowserService { @Override protected void done(MusicDirectory albumSet) { - List mediaItems = new ArrayList<>(); + List mediaItems = new ArrayList<>(); for(Entry album: albumSet.getChildren(true, false)) { - MediaDescription description = new MediaDescription.Builder() + MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setTitle(album.getAlbumDisplay()) .setSubtitle(album.getArtist()) .setMediaId(MUSIC_DIRECTORY_PREFIX + album.getId()) .build(); - mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_BROWSABLE)); } result.sendResult(mediaItems); @@ -231,7 +227,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { result.detach(); } - private void getLibrary(final Result> result) { + private void getLibrary(final Result> result) { new SilentServiceTask>(downloadService) { @Override protected List doInBackground(MusicService musicService) throws Throwable { @@ -240,15 +236,15 @@ public class AutoMediaBrowserService extends MediaBrowserService { @Override protected void done(List folders) { - List mediaItems = new ArrayList<>(); + List mediaItems = new ArrayList<>(); for(MusicFolder folder: folders) { - MediaDescription description = new MediaDescription.Builder() + MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setTitle(folder.getName()) .setMediaId(MUSIC_FOLDER_PREFIX + folder.getId()) .build(); - mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_BROWSABLE)); } result.sendResult(mediaItems); @@ -257,7 +253,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { result.detach(); } - private void getIndexes(final Result> result, final String musicFolderId) { + private void getIndexes(final Result> result, final String musicFolderId) { new SilentServiceTask(downloadService) { @Override protected Indexes doInBackground(MusicService musicService) throws Throwable { @@ -266,16 +262,16 @@ public class AutoMediaBrowserService extends MediaBrowserService { @Override protected void done(Indexes indexes) { - List mediaItems = new ArrayList<>(); + List mediaItems = new ArrayList<>(); // music directories for(Artist artist : indexes.getArtists()) { - MediaDescription description = new MediaDescription.Builder() + MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setTitle(artist.getName()) .setMediaId(MUSIC_DIRECTORY_CONTENTS_PREFIX + artist.getId()) .build(); - mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_BROWSABLE)); } // music files @@ -286,13 +282,13 @@ public class AutoMediaBrowserService extends MediaBrowserService { extras.putByteArray(Constants.INTENT_EXTRA_ENTRY_BYTES, entry.toByteArray()); extras.putString(Constants.INTENT_EXTRA_NAME_CHILD_ID, entry.getId()); - MediaDescription description = new MediaDescription.Builder() + MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setTitle(entry.getTitle()) .setMediaId(entry.getId()) .setExtras(extras) .build(); - mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_PLAYABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_PLAYABLE)); } catch(IOException e) { Log.e(TAG, "Failed to add entry", e); } @@ -305,7 +301,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { result.detach(); } - private void getMusicDirectory(final Result> result, final String musicDirectoryId) { + private void getMusicDirectory(final Result> result, final String musicDirectoryId) { new SilentServiceTask(downloadService) { @Override protected MusicDirectory doInBackground(MusicService musicService) throws Throwable { @@ -314,20 +310,20 @@ public class AutoMediaBrowserService extends MediaBrowserService { @Override protected void done(MusicDirectory directory) { - List mediaItems = new ArrayList<>(); + List mediaItems = new ArrayList<>(); addPlayOptions(mediaItems, musicDirectoryId, Constants.INTENT_EXTRA_NAME_ID); for(Entry entry : directory.getChildren()) { - MediaDescription description; + MediaDescriptionCompat description; if (entry.isDirectory()) { // browse deeper - description = new MediaDescription.Builder() + description = new MediaDescriptionCompat.Builder() .setTitle(entry.getTitle()) .setMediaId(MUSIC_DIRECTORY_CONTENTS_PREFIX + entry.getId()) .build(); - mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_BROWSABLE)); } else { try { // mark individual songs as directly playable @@ -336,13 +332,13 @@ public class AutoMediaBrowserService extends MediaBrowserService { extras.putByteArray(Constants.INTENT_EXTRA_ENTRY_BYTES, entry.toByteArray()); extras.putString(Constants.INTENT_EXTRA_NAME_CHILD_ID, entry.getId()); - description = new MediaDescription.Builder() + description = new MediaDescriptionCompat.Builder() .setTitle(entry.getTitle()) .setMediaId(entry.getId()) .setExtras(extras) .build(); - mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_PLAYABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_PLAYABLE)); } catch (IOException e) { Log.e(TAG, "Failed to add entry", e); } @@ -355,7 +351,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { result.detach(); } - private void getPlaylists(final Result> result) { + private void getPlaylists(final Result> result) { new SilentServiceTask>(downloadService) { @Override protected List doInBackground(MusicService musicService) throws Throwable { @@ -364,15 +360,15 @@ public class AutoMediaBrowserService extends MediaBrowserService { @Override protected void done(List playlists) { - List mediaItems = new ArrayList<>(); + List mediaItems = new ArrayList<>(); for(Playlist playlist: playlists) { - MediaDescription description = new MediaDescription.Builder() + MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setTitle(playlist.getName()) .setMediaId(PLAYLIST_PREFIX + playlist.getId()) .build(); - mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_BROWSABLE)); } result.sendResult(mediaItems); @@ -382,7 +378,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { result.detach(); } - private void getPodcasts(final Result> result) { + private void getPodcasts(final Result> result) { new SilentServiceTask>(downloadService) { @Override protected List doInBackground(MusicService musicService) throws Throwable { @@ -391,15 +387,15 @@ public class AutoMediaBrowserService extends MediaBrowserService { @Override protected void done(List podcasts) { - List mediaItems = new ArrayList<>(); + List mediaItems = new ArrayList<>(); for(PodcastChannel podcast: podcasts) { - MediaDescription description = new MediaDescription.Builder() + MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setTitle(podcast.getName()) .setMediaId(PODCAST_PREFIX + podcast.getId()) .build(); - mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_BROWSABLE)); } result.sendResult(mediaItems); @@ -408,7 +404,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { result.detach(); } - private void getPodcastEpisodes(final Result> result, final String podcastId) { + private void getPodcastEpisodes(final Result> result, final String podcastId) { new SilentServiceTask(downloadService) { @Override protected MusicDirectory doInBackground(MusicService musicService) throws Throwable { @@ -417,7 +413,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { @Override protected void done(MusicDirectory podcasts) { - List mediaItems = new ArrayList<>(); + List mediaItems = new ArrayList<>(); for(Entry entry: podcasts.getChildren(false, true)) { try { @@ -426,14 +422,14 @@ public class AutoMediaBrowserService extends MediaBrowserService { podcastExtras.putByteArray(Constants.INTENT_EXTRA_ENTRY_BYTES, podcast.toByteArray()); podcastExtras.putString(Constants.INTENT_EXTRA_NAME_PODCAST_ID, podcast.getId()); - MediaDescription description = new MediaDescription.Builder() + MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setTitle(podcast.getTitle()) .setSubtitle(Util.formatDate(downloadService, podcast.getDate(), false)) .setMediaId(PODCAST_PREFIX + podcast.getId()) .setExtras(podcastExtras) .build(); - mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_PLAYABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_PLAYABLE)); } catch(IOException e) { Log.e(TAG, "Failed to add podcast", e); } @@ -446,7 +442,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { result.detach(); } - private void getBookmarks(final Result> result) { + private void getBookmarks(final Result> result) { new SilentServiceTask(downloadService) { @Override protected MusicDirectory doInBackground(MusicService musicService) throws Throwable { @@ -455,7 +451,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { @Override protected void done(MusicDirectory bookmarkList) { - List mediaItems = new ArrayList<>(); + List mediaItems = new ArrayList<>(); for(Entry entry: bookmarkList.getChildren(false, true)) { try { @@ -463,14 +459,14 @@ public class AutoMediaBrowserService extends MediaBrowserService { extras.putByteArray(Constants.INTENT_EXTRA_ENTRY_BYTES, entry.toByteArray()); extras.putString(Constants.INTENT_EXTRA_NAME_CHILD_ID, entry.getId()); - MediaDescription description = new MediaDescription.Builder() + MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setTitle(entry.getTitle()) .setSubtitle(Util.formatDuration(entry.getBookmark().getPosition() / 1000)) .setMediaId(entry.getId()) .setExtras(extras) .build(); - mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_PLAYABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_PLAYABLE)); } catch(IOException e) { Log.e(TAG, "Failed to add entry", e); } @@ -483,39 +479,39 @@ public class AutoMediaBrowserService extends MediaBrowserService { result.detach(); } - private void addPlayOptions(List mediaItems, String id, String idConstant) { + private void addPlayOptions(List mediaItems, String id, String idConstant) { Bundle playAllExtras = new Bundle(); playAllExtras.putString(idConstant, id); - MediaDescription.Builder playAll = new MediaDescription.Builder(); + MediaDescriptionCompat.Builder playAll = new MediaDescriptionCompat.Builder(); playAll.setTitle(downloadService.getString(R.string.menu_play)) .setMediaId("play-" + id) .setExtras(playAllExtras); - mediaItems.add(new MediaBrowser.MediaItem(playAll.build(), MediaBrowser.MediaItem.FLAG_PLAYABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(playAll.build(), MediaBrowserCompat.MediaItem.FLAG_PLAYABLE)); Bundle shuffleExtras = new Bundle(); shuffleExtras.putString(idConstant, id); shuffleExtras.putBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); - MediaDescription.Builder shuffle = new MediaDescription.Builder(); + MediaDescriptionCompat.Builder shuffle = new MediaDescriptionCompat.Builder(); shuffle.setTitle(downloadService.getString(R.string.menu_shuffle)) .setMediaId("shuffle-" + id) .setExtras(shuffleExtras); - mediaItems.add(new MediaBrowser.MediaItem(shuffle.build(), MediaBrowser.MediaItem.FLAG_PLAYABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(shuffle.build(), MediaBrowserCompat.MediaItem.FLAG_PLAYABLE)); Bundle playLastExtras = new Bundle(); playLastExtras.putString(idConstant, id); playLastExtras.putBoolean(Constants.INTENT_EXTRA_PLAY_LAST, true); - MediaDescription.Builder playLast = new MediaDescription.Builder(); + MediaDescriptionCompat.Builder playLast = new MediaDescriptionCompat.Builder(); playLast.setTitle(downloadService.getString(R.string.menu_play_last)) .setMediaId("playLast-" + id) .setExtras(playLastExtras); - mediaItems.add(new MediaBrowser.MediaItem(playLast.build(), MediaBrowser.MediaItem.FLAG_PLAYABLE)); + mediaItems.add(new MediaBrowserCompat.MediaItem(playLast.build(), MediaBrowserCompat.MediaItem.FLAG_PLAYABLE)); } - private void getPlayOptions(Result> result, String id, String idConstant) { - List mediaItems = new ArrayList<>(); + private void getPlayOptions(Result> result, String id, String idConstant) { + List mediaItems = new ArrayList<>(); addPlayOptions(mediaItems, id, idConstant); diff --git a/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java b/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java index 1229d024..c5ce0868 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java +++ b/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java @@ -25,21 +25,20 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Bitmap; -import android.media.AudioAttributes; -import android.media.MediaDescription; -import android.media.MediaMetadata; +import android.media.AudioManager; import android.media.RemoteControlClient; -import android.media.session.MediaSession; -import android.media.session.PlaybackState; import android.os.Build; import android.os.Bundle; import android.provider.MediaStore; import android.support.annotation.NonNull; +import android.support.v4.media.MediaDescriptionCompat; +import android.support.v4.media.MediaMetadataCompat; +import android.support.v4.media.session.MediaSessionCompat; +import android.support.v4.media.session.PlaybackStateCompat; import android.support.v7.media.MediaRouter; import android.util.Log; import android.view.KeyEvent; -import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -75,7 +74,7 @@ public class RemoteControlClientLP extends RemoteControlClientBase { private static final String AUTO_RESERVE_SKIP_TO_NEXT = "com.google.android.gms.car.media.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_NEXT"; private static final String AUTO_RESERVE_SKIP_TO_PREVIOUS = "com.google.android.gms.car.media.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_PREVIOUS"; - protected MediaSession mediaSession; + protected MediaSessionCompat mediaSession; protected DownloadService downloadService; protected ImageLoader imageLoader; protected List currentQueue; @@ -84,7 +83,7 @@ public class RemoteControlClientLP extends RemoteControlClientBase { @Override public void register(Context context, ComponentName mediaButtonReceiverComponent) { downloadService = (DownloadService) context; - mediaSession = new MediaSession(downloadService, "DSub MediaSession"); + mediaSession = new MediaSessionCompat(downloadService, "DSub MediaSession"); Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); mediaButtonIntent.setComponent(mediaButtonReceiverComponent); @@ -97,13 +96,10 @@ public class RemoteControlClientLP extends RemoteControlClientBase { PendingIntent activityPendingIntent = PendingIntent.getActivity(context, 0, activityIntent, 0); mediaSession.setSessionActivity(activityPendingIntent); - mediaSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS | MediaSession.FLAG_HANDLES_MEDIA_BUTTONS); + mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS | MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS); mediaSession.setCallback(new EventCallback()); - AudioAttributes.Builder audioAttributesBuilder = new AudioAttributes.Builder(); - audioAttributesBuilder.setUsage(AudioAttributes.USAGE_MEDIA) - .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC); - mediaSession.setPlaybackToLocal(audioAttributesBuilder.build()); + mediaSession.setPlaybackToLocal(AudioManager.STREAM_MUSIC); mediaSession.setActive(true); Bundle sessionExtras = new Bundle(); @@ -128,21 +124,21 @@ public class RemoteControlClientLP extends RemoteControlClientBase { @Override public void setPlaybackState(int state, int index, int queueSize) { - PlaybackState.Builder builder = new PlaybackState.Builder(); + PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder(); - int newState = PlaybackState.STATE_NONE; + int newState = PlaybackStateCompat.STATE_NONE; switch(state) { case RemoteControlClient.PLAYSTATE_PLAYING: - newState = PlaybackState.STATE_PLAYING; + newState = PlaybackStateCompat.STATE_PLAYING; break; case RemoteControlClient.PLAYSTATE_STOPPED: - newState = PlaybackState.STATE_STOPPED; + newState = PlaybackStateCompat.STATE_STOPPED; break; case RemoteControlClient.PLAYSTATE_PAUSED: - newState = PlaybackState.STATE_PAUSED; + newState = PlaybackStateCompat.STATE_PAUSED; break; case RemoteControlClient.PLAYSTATE_BUFFERING: - newState = PlaybackState.STATE_BUFFERING; + newState = PlaybackStateCompat.STATE_BUFFERING; break; } @@ -166,7 +162,7 @@ public class RemoteControlClientLP extends RemoteControlClientBase { builder.setActiveQueueItemId(entry.getId().hashCode()); } - PlaybackState playbackState = builder.build(); + PlaybackStateCompat playbackState = builder.build(); mediaSession.setPlaybackState(playbackState); previousState = state; } @@ -186,19 +182,19 @@ public class RemoteControlClientLP extends RemoteControlClientBase { } public void setMetadata(Entry currentSong, Bitmap bitmap) { - MediaMetadata.Builder builder = new MediaMetadata.Builder(); - builder.putString(MediaMetadata.METADATA_KEY_ARTIST, (currentSong == null) ? null : currentSong.getArtist()) - .putString(MediaMetadata.METADATA_KEY_ALBUM, (currentSong == null) ? null : currentSong.getAlbum()) - .putString(MediaMetadata.METADATA_KEY_ALBUM_ARTIST, (currentSong == null) ? null : currentSong.getArtist()) - .putString(MediaMetadata.METADATA_KEY_TITLE, (currentSong) == null ? null : currentSong.getTitle()) - .putString(MediaMetadata.METADATA_KEY_GENRE, (currentSong) == null ? null : currentSong.getGenre()) - .putLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER, (currentSong == null) ? + MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder(); + builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, (currentSong == null) ? null : currentSong.getArtist()) + .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, (currentSong == null) ? null : currentSong.getAlbum()) + .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, (currentSong == null) ? null : currentSong.getArtist()) + .putString(MediaMetadataCompat.METADATA_KEY_TITLE, (currentSong) == null ? null : currentSong.getTitle()) + .putString(MediaMetadataCompat.METADATA_KEY_GENRE, (currentSong) == null ? null : currentSong.getGenre()) + .putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, (currentSong == null) ? 0 : ((currentSong.getTrack() == null) ? 0 : currentSong.getTrack())) - .putLong(MediaMetadata.METADATA_KEY_DURATION, (currentSong == null) ? + .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, (currentSong == null) ? 0 : ((currentSong.getDuration() == null) ? 0 : (currentSong.getDuration() * 1000))); if(bitmap != null) { - builder.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, bitmap); + builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap); } mediaSession.setMetadata(builder.build()); @@ -221,17 +217,17 @@ public class RemoteControlClientLP extends RemoteControlClientBase { @Override public void updatePlaylist(List playlist) { - List queue = new ArrayList<>(); + List queue = new ArrayList<>(); for(DownloadFile file: playlist) { Entry entry = file.getSong(); - MediaDescription description = new MediaDescription.Builder() + MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setMediaId(entry.getId()) .setTitle(entry.getTitle()) .setSubtitle(entry.getAlbumDisplay()) .build(); - MediaSession.QueueItem item = new MediaSession.QueueItem(description, entry.getId().hashCode()); + MediaSessionCompat.QueueItem item = new MediaSessionCompat.QueueItem(description, entry.getId().hashCode()); queue.add(item); } @@ -239,46 +235,46 @@ public class RemoteControlClientLP extends RemoteControlClientBase { currentQueue = playlist; } - public MediaSession getMediaSession() { + public MediaSessionCompat getMediaSession() { return mediaSession; } protected long getPlaybackActions(boolean isSong, int currentIndex, int size) { - long actions = PlaybackState.ACTION_PLAY | - PlaybackState.ACTION_PAUSE | - PlaybackState.ACTION_SEEK_TO | - PlaybackState.ACTION_SKIP_TO_QUEUE_ITEM; + long actions = PlaybackStateCompat.ACTION_PLAY | + PlaybackStateCompat.ACTION_PAUSE | + PlaybackStateCompat.ACTION_SEEK_TO | + PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM; if(isSong) { if (currentIndex > 0) { - actions |= PlaybackState.ACTION_SKIP_TO_PREVIOUS; + actions |= PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS; } if (currentIndex < size - 1) { - actions |= PlaybackState.ACTION_SKIP_TO_NEXT; + actions |= PlaybackStateCompat.ACTION_SKIP_TO_NEXT; } } else { - actions |= PlaybackState.ACTION_SKIP_TO_PREVIOUS; - actions |= PlaybackState.ACTION_SKIP_TO_NEXT; + actions |= PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS; + actions |= PlaybackStateCompat.ACTION_SKIP_TO_NEXT; } return actions; } - protected void addCustomActions(Entry currentSong, PlaybackState.Builder builder) { + protected void addCustomActions(Entry currentSong, PlaybackStateCompat.Builder builder) { Bundle showOnWearExtras = new Bundle(); showOnWearExtras.putBoolean(SHOW_ON_WEAR, true); int rating = currentSong.getRating(); - PlaybackState.CustomAction thumbsUp = new PlaybackState.CustomAction.Builder(CUSTOM_ACTION_THUMBS_UP, + PlaybackStateCompat.CustomAction thumbsUp = new PlaybackStateCompat.CustomAction.Builder(CUSTOM_ACTION_THUMBS_UP, downloadService.getString(R.string.download_thumbs_up), rating == 5 ? R.drawable.ic_action_rating_good_selected : R.drawable.ic_action_rating_good) .setExtras(showOnWearExtras).build(); - PlaybackState.CustomAction thumbsDown = new PlaybackState.CustomAction.Builder(CUSTOM_ACTION_THUMBS_DOWN, + PlaybackStateCompat.CustomAction thumbsDown = new PlaybackStateCompat.CustomAction.Builder(CUSTOM_ACTION_THUMBS_DOWN, downloadService.getString(R.string.download_thumbs_down), rating == 1 ? R.drawable.ic_action_rating_bad_selected : R.drawable.ic_action_rating_bad) .setExtras(showOnWearExtras).build(); - PlaybackState.CustomAction star = new PlaybackState.CustomAction.Builder(CUSTOM_ACTION_STAR, + PlaybackStateCompat.CustomAction star = new PlaybackStateCompat.CustomAction.Builder(CUSTOM_ACTION_STAR, downloadService.getString(R.string.common_star), currentSong.isStarred() ? R.drawable.ic_toggle_star : R.drawable.ic_toggle_star_outline) .setExtras(showOnWearExtras).build(); @@ -476,7 +472,7 @@ public class RemoteControlClientLP extends RemoteControlClientBase { downloadService.setShufflePlayEnabled(true); } - private class EventCallback extends MediaSession.Callback { + private class EventCallback extends MediaSessionCompat.Callback { @Override public void onPlay() { downloadService.start(); -- cgit v1.2.3 From 73f5e04e0ddd23a8477ee0c9c4b3364817addede Mon Sep 17 00:00:00 2001 From: Glenn Guy Date: Thu, 11 Oct 2018 23:38:40 +1100 Subject: Remove registerMediaButtonEventReceiver for API >= 21 Finally figured out that this was causing an extra controller to be registered with the AVRCP module. With DSub as the only media app running the log would show `V/NewAvrcpMediaPlayerList: onActiveSessionsChanged: number of controllers: 0` on entry into the app and would increase to 2 shortly after. On Android Pie this causes problems as the new AVRCP module's logic is causing the metadata to be sent through to the wrong controller. I'm not sure if you think I've gone about it in the correct way but I've removed the setting for media buttons as well for Lollipop onwards, considering that this setting has no effect anyway on >= 21. --- .../java/github/daneren2005/dsub/fragments/SettingsFragment.java | 9 +++++++++ app/src/main/java/github/daneren2005/dsub/util/Util.java | 4 ++-- app/src/main/res/xml/settings_playback.xml | 3 ++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java index 94c9b7fc..f7031146 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java @@ -24,6 +24,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.EditTextPreference; @@ -109,6 +110,14 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared public void onCreate(Bundle bundle) { super.onCreate(bundle); + if(Build.VERSION.SDK_INT >= 21) { + CheckBoxPreference mediaButtons = (CheckBoxPreference) findPreference("mediaButtons"); + if (mediaButtons != null) { + PreferenceCategory otherCategory = (PreferenceCategory) findPreference("otherSettings"); + otherCategory.removePreference(mediaButtons); + } + } + int instance = this.getArguments().getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, -1); if (instance != -1) { PreferenceScreen preferenceScreen = expandServer(instance); diff --git a/app/src/main/java/github/daneren2005/dsub/util/Util.java b/app/src/main/java/github/daneren2005/dsub/util/Util.java index 5699cdf9..a02e7ded 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Util.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Util.java @@ -1294,11 +1294,11 @@ public final class Util { public static void registerMediaButtonEventReceiver(Context context) { - // Only do it if enabled in the settings. + // Only do it if enabled in the settings and api < 21 SharedPreferences prefs = getPreferences(context); boolean enabled = prefs.getBoolean(Constants.PREFERENCES_KEY_MEDIA_BUTTONS, true); - if (enabled) { + if (enabled && Build.VERSION.SDK_INT < 21) { // AudioManager.registerMediaButtonEventReceiver() was introduced in Android 2.2. // Use reflection to maintain compatibility with 1.5. diff --git a/app/src/main/res/xml/settings_playback.xml b/app/src/main/res/xml/settings_playback.xml index edaf3013..fb3501f0 100644 --- a/app/src/main/res/xml/settings_playback.xml +++ b/app/src/main/res/xml/settings_playback.xml @@ -117,7 +117,8 @@ + android:title="@string/settings.other_title" + android:key="otherSettings"> Date: Thu, 11 Oct 2018 23:50:22 +1100 Subject: Fix metadata lag and missing artist/album/duration on Pie Android Pie takes the metadata from the queue. Missing the Description (album) metadata seems to cause it to wait a few seconds (this error in the log - `2018-10-11 23:39:14.757 31985-31985/? D/NewAvrcpMediaPlayerWrapper: Metadata currently out of sync for github.daneren2005.dsub`) before sending the info over AVRCP. --- .../github/daneren2005/dsub/util/compat/RemoteControlClientLP.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java b/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java index c5ce0868..b27a9850 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java +++ b/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java @@ -221,11 +221,16 @@ public class RemoteControlClientLP extends RemoteControlClientBase { for(DownloadFile file: playlist) { Entry entry = file.getSong(); + Bundle extras = new Bundle(); + extras.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, + ((entry.getDuration() == null) ? 0 : (entry.getDuration() * 1000))); MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setMediaId(entry.getId()) .setTitle(entry.getTitle()) - .setSubtitle(entry.getAlbumDisplay()) + .setSubtitle(entry.getArtist()) + .setDescription(entry.getAlbum()) + .setExtras(extras) .build(); MediaSessionCompat.QueueItem item = new MediaSessionCompat.QueueItem(description, entry.getId().hashCode()); queue.add(item); -- cgit v1.2.3 From 5f04bd8dfea5231fc248855c20edf4baec22f66b Mon Sep 17 00:00:00 2001 From: Glenn Guy Date: Fri, 12 Oct 2018 00:03:56 +1100 Subject: Fix playback pausing when disconnecting bluetooth --- app/src/main/AndroidManifest.xml | 6 ------ .../java/github/daneren2005/dsub/service/DownloadService.java | 8 ++++++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cfc70a55..52756534 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -166,12 +166,6 @@ - - - - - - diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index 6c3cfbd7..f4bc2343 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -42,6 +42,7 @@ import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.domain.RemoteControlState; import github.daneren2005.dsub.domain.RepeatMode; import github.daneren2005.dsub.domain.ServerInfo; +import github.daneren2005.dsub.receiver.AudioNoisyReceiver; import github.daneren2005.dsub.receiver.MediaButtonIntentReceiver; import github.daneren2005.dsub.util.ArtistRadioBuffer; import github.daneren2005.dsub.util.ImageLoader; @@ -77,6 +78,7 @@ import android.content.ComponentCallbacks2; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; import android.media.AudioManager; import android.media.MediaPlayer; @@ -180,6 +182,9 @@ public class DownloadService extends Service { private boolean autoPlayStart = false; private boolean runListenersOnInit = false; + private IntentFilter audioNoisyIntent = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY); + private AudioNoisyReceiver audioNoisyReceiver = new AudioNoisyReceiver(); + private MediaRouteManager mediaRouter; // Variables to manage getCurrentPosition sometimes starting from an arbitrary non-zero number @@ -1328,6 +1333,7 @@ public class DownloadService extends Service { } else if(playerState == PAUSED_TEMP) { setPlayerState(temp ? PAUSED_TEMP : PAUSED); } + unregisterReceiver(audioNoisyReceiver); } catch (Exception x) { handleError(x); } @@ -1352,6 +1358,7 @@ public class DownloadService extends Service { } else if(playerState == PAUSED) { setPlayerState(STOPPED); } + unregisterReceiver(audioNoisyReceiver); } catch(Exception x) { handleError(x); } @@ -1371,6 +1378,7 @@ public class DownloadService extends Service { autoPlayStart = true; } } + registerReceiver(audioNoisyReceiver, audioNoisyIntent); setPlayerState(STARTED); } catch (Exception x) { handleError(x); -- cgit v1.2.3 From 9109204bbc34a42dd1a720cd341eb7a2a775d7cf Mon Sep 17 00:00:00 2001 From: Glenn Guy Date: Sat, 13 Oct 2018 22:41:47 +1100 Subject: Fix again registering/unregistering AudioNoisyReceiver Moved to onCreate()/onDestroy() rather than start() stop() and pause() - receiver would not be registered in some cases causing and exception to occur and audio playback to continue when bluetooth is disconnected. --- .../java/github/daneren2005/dsub/service/DownloadService.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index f4bc2343..9a0f606e 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -183,7 +183,7 @@ public class DownloadService extends Service { private boolean runListenersOnInit = false; private IntentFilter audioNoisyIntent = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY); - private AudioNoisyReceiver audioNoisyReceiver = new AudioNoisyReceiver(); + private AudioNoisyReceiver audioNoisyReceiver = null; private MediaRouteManager mediaRouter; @@ -267,6 +267,8 @@ public class DownloadService extends Service { }, "DownloadService").start(); Util.registerMediaButtonEventReceiver(this); + audioNoisyReceiver = new AudioNoisyReceiver(); + registerReceiver(audioNoisyReceiver, audioNoisyIntent); if (mRemoteControl == null) { // Use the remote control APIs (if available) to set the playback state @@ -380,6 +382,9 @@ public class DownloadService extends Service { proxy.stop(); proxy = null; } + if (audioNoisyReceiver != null) { + unregisterReceiver(audioNoisyReceiver); + } mediaRouter.destroy(); Notifications.hidePlayingNotification(this, this, handler); Notifications.hideDownloadingNotification(this, this, handler); @@ -1333,7 +1338,6 @@ public class DownloadService extends Service { } else if(playerState == PAUSED_TEMP) { setPlayerState(temp ? PAUSED_TEMP : PAUSED); } - unregisterReceiver(audioNoisyReceiver); } catch (Exception x) { handleError(x); } @@ -1358,7 +1362,6 @@ public class DownloadService extends Service { } else if(playerState == PAUSED) { setPlayerState(STOPPED); } - unregisterReceiver(audioNoisyReceiver); } catch(Exception x) { handleError(x); } @@ -1378,7 +1381,6 @@ public class DownloadService extends Service { autoPlayStart = true; } } - registerReceiver(audioNoisyReceiver, audioNoisyIntent); setPlayerState(STARTED); } catch (Exception x) { handleError(x); -- cgit v1.2.3 From 510944ab35b5da1e2fc2c9f2963c32f3a2b12bbf Mon Sep 17 00:00:00 2001 From: Glenn Guy Date: Wed, 17 Oct 2018 20:15:35 +1100 Subject: Ensure startForeground() is called Fixes #890 --- app/src/main/java/github/daneren2005/dsub/service/DownloadService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index 9a0f606e..605ec204 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -309,6 +309,9 @@ public class DownloadService extends Service { public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); lifecycleSupport.onStart(intent); + if(Build.VERSION.SDK_INT >= 26) { + Notifications.shutGoogleUpNotification(this); + } return START_NOT_STICKY; } -- cgit v1.2.3 From 62b69284a67eb15bec96be32a88271bcea624c62 Mon Sep 17 00:00:00 2001 From: Glenn Guy Date: Wed, 17 Oct 2018 22:21:19 +1100 Subject: requestAudioFocus not behaving properly Other apps were only triggering the listener if I had started dsub from Android Auto It seems that the AudioManager instance needs to come from application context rather than the service - I found the hint here: https://stackoverflow.com/a/14129015 --- .../main/java/github/daneren2005/dsub/service/DownloadService.java | 3 ++- app/src/main/java/github/daneren2005/dsub/util/Util.java | 5 +---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index 605ec204..7afdd73f 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -1506,7 +1506,8 @@ public class DownloadService extends Service { this.playerState = playerState; if(playerState == STARTED) { - Util.requestAudioFocus(this); + AudioManager audioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE); + Util.requestAudioFocus(this, audioManager); } if (show) { diff --git a/app/src/main/java/github/daneren2005/dsub/util/Util.java b/app/src/main/java/github/daneren2005/dsub/util/Util.java index a02e7ded..78f3e2d6 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Util.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Util.java @@ -1327,11 +1327,9 @@ public final class Util { } @TargetApi(8) - public static void requestAudioFocus(final Context context) { + public static void requestAudioFocus(final Context context, final AudioManager audioManager) { if(Build.VERSION.SDK_INT >= 26) { if(audioFocusRequest == null) { - final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - AudioAttributes playbackAttributes = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) @@ -1344,7 +1342,6 @@ public final class Util { audioManager.requestAudioFocus(audioFocusRequest); } } else if (Build.VERSION.SDK_INT >= 8 && focusListener == null) { - final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); audioManager.requestAudioFocus(focusListener = getAudioFocusChangeListener(context, audioManager), AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); } } -- cgit v1.2.3 From 361f73ffa001fb6477683eee7f4c23932a234f74 Mon Sep 17 00:00:00 2001 From: Daniel Bowman Date: Sat, 20 Oct 2018 18:38:26 +0100 Subject: Fix a crash on getRecentDownloads if playlist is empty --- .../daneren2005/dsub/service/DownloadServiceTest.java | 14 ++++++++++++++ .../github/daneren2005/dsub/service/DownloadService.java | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/src/androidTest/java/github/daneren2005/dsub/service/DownloadServiceTest.java b/app/src/androidTest/java/github/daneren2005/dsub/service/DownloadServiceTest.java index 44b77b84..37e91642 100644 --- a/app/src/androidTest/java/github/daneren2005/dsub/service/DownloadServiceTest.java +++ b/app/src/androidTest/java/github/daneren2005/dsub/service/DownloadServiceTest.java @@ -49,6 +49,20 @@ public class DownloadServiceTest extends assertEquals(0, position); } + public void testGetRecentDownloadsWithoutPlaylist() { + int output_length = downloadService.getRecentDownloads().size(); + assertEquals(0, output_length); + } + + public void testGetRecentDownloadsWithPlaylist() { + downloadService.getDownloads().clear(); + downloadService.download(this.createMusicSongs(2), false, false, false, + false, 0, 0); + + int output_length = downloadService.getRecentDownloads().size(); + assertEquals(1, output_length); + } + public void testGetCurrentPlayingIndexWithoutPlayList() { int currentPlayingIndex = activity.getDownloadService() .getCurrentPlayingIndex(); diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index 6c3cfbd7..fc2bc7fc 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -1060,7 +1060,7 @@ public class DownloadService extends Service { public synchronized List getRecentDownloads() { int from = Math.max(currentPlayingIndex - 10, 0); int songsToKeep = Math.max(Util.getPreloadCount(this), 20); - int to = Math.min(currentPlayingIndex + songsToKeep, downloadList.size() - 1); + int to = Math.min(currentPlayingIndex + songsToKeep, Math.max(downloadList.size() - 1, 0)); List temp = downloadList.subList(from, to); temp.addAll(backgroundDownloadList); return temp; -- cgit v1.2.3 From 310bc3428700e6438a5e84fcd17326fc4eefef20 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Thu, 25 Oct 2018 16:51:04 -0700 Subject: Update gradle version to be the same as what we have in target-sdk-23 --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index e9bd19e5..c0bcbfde 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ android { applicationId "github.daneren2005.dsub" minSdkVersion 14 targetSdkVersion 26 - versionCode 200 + versionCode 202 versionName '5.4.3' setProperty("archivesBaseName", "DSub $versionName") resConfigs "de", "es", "fr", "hu", "nl", "pt-rPT", "ru", "sv" -- cgit v1.2.3 From 0a4f6215972d970e69859fa690938ef9f0ea2e0a Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Fri, 26 Oct 2018 16:46:00 -0700 Subject: Add changelog for 5.4.4 --- app/build.gradle | 2 +- app/src/main/res/xml/changelog.xml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index c0bcbfde..61c309f3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,7 +9,7 @@ android { minSdkVersion 14 targetSdkVersion 26 versionCode 202 - versionName '5.4.3' + versionName '5.4.4' setProperty("archivesBaseName", "DSub $versionName") resConfigs "de", "es", "fr", "hu", "nl", "pt-rPT", "ru", "sv" } diff --git a/app/src/main/res/xml/changelog.xml b/app/src/main/res/xml/changelog.xml index 42e62e1d..80e26cc8 100644 --- a/app/src/main/res/xml/changelog.xml +++ b/app/src/main/res/xml/changelog.xml @@ -1,5 +1,8 @@ + + Reverted back to target SDK 23 to fix service crashes + Fix more issues from targeting Android O -- cgit v1.2.3 From ac260b65765e55910517d1d468927936d1688d04 Mon Sep 17 00:00:00 2001 From: Daniel Bowman Date: Sat, 27 Oct 2018 14:46:48 +0100 Subject: Fix Genre comparator to pass unit tests --- .../github/daneren2005/dsub/domain/GenreComparatorTest.java | 8 ++++---- app/src/main/java/github/daneren2005/dsub/domain/Genre.java | 11 ++++------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/app/src/androidTest/java/github/daneren2005/dsub/domain/GenreComparatorTest.java b/app/src/androidTest/java/github/daneren2005/dsub/domain/GenreComparatorTest.java index 9ffa518e..16d189fa 100644 --- a/app/src/androidTest/java/github/daneren2005/dsub/domain/GenreComparatorTest.java +++ b/app/src/androidTest/java/github/daneren2005/dsub/domain/GenreComparatorTest.java @@ -16,7 +16,7 @@ public class GenreComparatorTest extends TestCase { Genre g2 = new Genre(); - List genres = new ArrayList(); + List genres = new ArrayList<>(); genres.add(g1); genres.add(g2); @@ -34,7 +34,7 @@ public class GenreComparatorTest extends TestCase { Genre g2 = new Genre(); g2.setName("genre"); - List genres = new ArrayList(); + List genres = new ArrayList<>(); genres.add(g1); genres.add(g2); @@ -53,9 +53,9 @@ public class GenreComparatorTest extends TestCase { g2.setName("Pop"); Genre g3 = new Genre(); - g2.setName("Rap"); + g3.setName("Rap"); - List genres = new ArrayList(); + List genres = new ArrayList<>(); genres.add(g1); genres.add(g2); genres.add(g3); diff --git a/app/src/main/java/github/daneren2005/dsub/domain/Genre.java b/app/src/main/java/github/daneren2005/dsub/domain/Genre.java index 4b6ac344..dcf12a1d 100644 --- a/app/src/main/java/github/daneren2005/dsub/domain/Genre.java +++ b/app/src/main/java/github/daneren2005/dsub/domain/Genre.java @@ -1,16 +1,10 @@ package github.daneren2005.dsub.domain; -import android.content.Context; -import android.content.SharedPreferences; - import java.io.Serializable; import java.util.Collections; import java.util.Comparator; import java.util.List; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; - public class Genre implements Serializable { private String name; private String index; @@ -57,7 +51,10 @@ public class Genre implements Serializable { public static class GenreComparator implements Comparator { @Override public int compare(Genre genre1, Genre genre2) { - return genre1.getName().compareToIgnoreCase(genre2.getName()); + String genre1Name = genre1.getName() != null ? genre1.getName() : ""; + String genre2Name = genre2.getName() != null ? genre2.getName() : ""; + + return genre1Name.compareToIgnoreCase(genre2Name); } public static List sort(List genres) { -- cgit v1.2.3 From 1997f6f5e9cdaa3ab04e65b1dad44b622b0aa77d Mon Sep 17 00:00:00 2001 From: Daniel Bowman Date: Sat, 27 Oct 2018 15:07:39 +0100 Subject: Don't log error if avatar isn't available --- app/src/main/java/github/daneren2005/dsub/util/ImageLoader.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/github/daneren2005/dsub/util/ImageLoader.java b/app/src/main/java/github/daneren2005/dsub/util/ImageLoader.java index 2321e69e..23f48e02 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/ImageLoader.java +++ b/app/src/main/java/github/daneren2005/dsub/util/ImageLoader.java @@ -640,7 +640,7 @@ public class ImageLoader { private final ImageView mView; private Drawable mDrawable; - public AvatarTask(Context context, ImageView view, String username) { + private AvatarTask(Context context, ImageView view, String username) { super(context); mContext = context; mView = view; @@ -659,8 +659,10 @@ public class ImageLoader { mDrawable = Util.createDrawableFromBitmap(mContext, bitmap); } + } catch (java.io.FileNotFoundException x) { + Log.i(TAG, "Avatar not available for download."); } catch (Throwable x) { - Log.e(TAG, "Failed to download album art.", x); + Log.e(TAG, "Failed to download avatar.", x); } return null; -- cgit v1.2.3 From 5076b6753d33328d1e427d5daadbaebd199c795b Mon Sep 17 00:00:00 2001 From: Glenn Guy Date: Mon, 29 Oct 2018 16:10:59 +1100 Subject: Don't call shutGoogleUpNotification when service is already in foreground Since adding the call to shutGoogleUpNotification to onStartCommand, using the controls on the notification would always remove the current notification which is pretty annoying. This fixes that unwanted behaviour and I think is much nicer than blindly calling it every time. --- .../daneren2005/dsub/service/DownloadService.java | 11 ++++++++- .../daneren2005/dsub/util/Notifications.java | 28 +++++++++++++++------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index 88c631f5..0fb5e9e5 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -170,6 +170,7 @@ public class DownloadService extends Service { private boolean downloadOngoing = false; private float volume = 1.0f; private long delayUpdateProgress = DEFAULT_DELAY_UPDATE_PROGRESS; + private boolean foregroundService = false; private AudioEffectsController effectsController; private RemoteControlState remoteState = LOCAL; @@ -309,7 +310,7 @@ public class DownloadService extends Service { public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); lifecycleSupport.onStart(intent); - if(Build.VERSION.SDK_INT >= 26) { + if(Build.VERSION.SDK_INT >= 26 && !this.isForeground()) { Notifications.shutGoogleUpNotification(this); } return START_NOT_STICKY; @@ -1063,6 +1064,14 @@ public class DownloadService extends Service { return size() == 1 || (currentPlaying != null && !currentPlaying.isSong()); } + public synchronized boolean isForeground() { + return this.foregroundService; + } + + public synchronized void setIsForeground(boolean foreground) { + this.foregroundService = foreground; + } + public synchronized List getDownloads() { List temp = new ArrayList(); temp.addAll(downloadList); diff --git a/app/src/main/java/github/daneren2005/dsub/util/Notifications.java b/app/src/main/java/github/daneren2005/dsub/util/Notifications.java index 59341ebf..a8f7add0 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Notifications.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Notifications.java @@ -114,11 +114,11 @@ public final class Notifications { handler.post(new Runnable() { @Override public void run() { - downloadService.stopForeground(true); + stopForeground(downloadService, true); showDownloadingNotification(context, downloadService, handler, downloadService.getCurrentDownloading(), downloadService.getBackgroundDownloads().size()); try { - downloadService.startForeground(NOTIFICATION_ID_PLAYING, notification); + startForeground(downloadService, NOTIFICATION_ID_PLAYING, notification); } catch(Exception e) { Log.e(TAG, "Failed to start notifications after stopping foreground download"); } @@ -130,7 +130,7 @@ public final class Notifications { public void run() { if (playing) { try { - downloadService.startForeground(NOTIFICATION_ID_PLAYING, notification); + startForeground(downloadService, NOTIFICATION_ID_PLAYING, notification); } catch(Exception e) { Log.e(TAG, "Failed to start notifications while playing"); } @@ -138,7 +138,7 @@ public final class Notifications { playShowing = false; persistentPlayingShowing = true; NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - downloadService.stopForeground(false); + stopForeground(downloadService, false); try { notificationManager.notify(NOTIFICATION_ID_PLAYING, notification); @@ -334,7 +334,7 @@ public final class Notifications { handler.post(new Runnable() { @Override public void run() { - downloadService.stopForeground(true); + stopForeground(downloadService, true); if(persistentPlayingShowing) { NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); @@ -413,7 +413,7 @@ public final class Notifications { handler.post(new Runnable() { @Override public void run() { - downloadService.startForeground(NOTIFICATION_ID_DOWNLOADING, notification); + startForeground(downloadService, NOTIFICATION_ID_DOWNLOADING, notification); } }); } @@ -429,7 +429,7 @@ public final class Notifications { handler.post(new Runnable() { @Override public void run() { - downloadService.stopForeground(true); + stopForeground(downloadService, true); } }); } @@ -461,8 +461,8 @@ public final class Notifications { .setChannelId("downloading-channel"); final Notification notification = builder.build(); - downloadService.startForeground(NOTIFICATION_ID_SHUT_GOOGLE_UP, notification); - downloadService.stopForeground(true); + startForeground(downloadService, NOTIFICATION_ID_SHUT_GOOGLE_UP, notification); + stopForeground(downloadService, true); } public static void showSyncNotification(final Context context, int stringId, String extra) { @@ -537,4 +537,14 @@ public final class Notifications { return syncChannel; } + + private static void startForeground(DownloadService downloadService, int notificationId, Notification notification) { + downloadService.startForeground(notificationId, notification); + downloadService.setIsForeground(true); + } + + private static void stopForeground(DownloadService downloadService, boolean removeNotification) { + downloadService.stopForeground(removeNotification); + downloadService.setIsForeground(false); + } } -- cgit v1.2.3 From 7ab937c9748e91dc490f52e7663f1bf6281b494e Mon Sep 17 00:00:00 2001 From: Daniel Bowman Date: Sun, 18 Nov 2018 21:47:58 +0000 Subject: Upgrade to gradle 3.2.1 --- app/build.gradle | 37 ++++++++++++++++---------------- build.gradle | 3 ++- gradle/wrapper/gradle-wrapper.properties | 4 ++-- settings.gradle | 6 ++++-- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 61c309f3..a87ba2b1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,7 +2,6 @@ apply plugin: 'com.android.application' android { compileSdkVersion 27 - buildToolsVersion '25.0.0' defaultConfig { applicationId "github.daneren2005.dsub" @@ -27,14 +26,16 @@ android { zipAlignEnabled true } } - + flavorDimensions "version" productFlavors { floss { // FLOSS build (no proprietary libraries) + dimension "version" } google { // FLOSS build + Google libraries // Adds ChromeCast support + dimension "version" } } @@ -54,20 +55,20 @@ android { } dependencies { - compile project(':Server Proxy') - compile fileTree(include: ['*.jar'], dir: 'libs') - compile 'com.android.support:support-v4:27.1.+' - compile 'com.android.support:appcompat-v7:27.1.+' - compile 'com.android.support:mediarouter-v7:27.1.+' - compile 'com.android.support:recyclerview-v7:27.1.+' - compile 'com.android.support:design:27.1.+' - googleCompile 'com.google.android.gms:play-services-cast:8.1.0' - compile 'com.sothree.slidinguppanel:library:3.0.0' - compile 'de.hdodenhof:circleimageview:1.2.1' - compile 'com.shehabic.droppy:Droppy:0.5.1@aar' - compile group: 'org.fourthline.cling', name: 'cling-core', version:'2.1.1' - compile group: 'org.fourthline.cling', name: 'cling-support', version:'2.1.1' - compile group: 'org.eclipse.jetty', name: 'jetty-server', version:'8.1.16.v20140903' - compile group: 'org.eclipse.jetty', name: 'jetty-servlet', version:'8.1.16.v20140903' - compile group: 'org.eclipse.jetty', name: 'jetty-client', version:'8.1.16.v20140903' + implementation project(path: ':ServerProxy') + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'com.android.support:support-v4:27.1.+' + implementation 'com.android.support:appcompat-v7:27.1.+' + implementation 'com.android.support:mediarouter-v7:27.1.+' + implementation 'com.android.support:recyclerview-v7:27.1.+' + implementation 'com.android.support:design:27.1.+' + googleImplementation 'com.google.android.gms:play-services-cast:8.1.0' + implementation 'com.sothree.slidinguppanel:library:3.0.0' + implementation 'de.hdodenhof:circleimageview:1.2.1' + implementation 'com.shehabic.droppy:Droppy:0.5.1@aar' + implementation group: 'org.fourthline.cling', name: 'cling-core', version:'2.1.1' + implementation group: 'org.fourthline.cling', name: 'cling-support', version:'2.1.1' + implementation group: 'org.eclipse.jetty', name: 'jetty-server', version:'8.1.16.v20140903' + implementation group: 'org.eclipse.jetty', name: 'jetty-servlet', version:'8.1.16.v20140903' + implementation group: 'org.eclipse.jetty', name: 'jetty-client', version:'8.1.16.v20140903' } diff --git a/build.gradle b/build.gradle index d5dfdd4f..3fc890c1 100644 --- a/build.gradle +++ b/build.gradle @@ -7,9 +7,10 @@ buildscript { url 'https://maven.google.com/' name 'Google' } + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.3' + classpath 'com.android.tools.build:gradle:3.2.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 325e6709..90a0ff73 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Nov 09 08:50:56 PST 2017 +#Sun Nov 18 21:50:34 GMT 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip diff --git a/settings.gradle b/settings.gradle index 430c7754..73938efa 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,4 @@ -include ':app', ':Server Proxy' -project(':Server Proxy').projectDir = new File('ServerProxy') +include ':app' + +include ':ServerProxy' +project(':ServerProxy').projectDir = new File('ServerProxy') -- cgit v1.2.3 From 01a5e5e69f7b6bc65ba4529c71f2c332a03db8ed Mon Sep 17 00:00:00 2001 From: Daniel Bowman Date: Thu, 22 Nov 2018 10:26:19 +0000 Subject: Fix failing test #916 Testing previous relies on the player state. The test in it's current form relies on too many side effects for a good unit test. Setting the player state manually for now. --- .../java/github/daneren2005/dsub/service/DownloadServiceTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/androidTest/java/github/daneren2005/dsub/service/DownloadServiceTest.java b/app/src/androidTest/java/github/daneren2005/dsub/service/DownloadServiceTest.java index 37e91642..2e10b977 100644 --- a/app/src/androidTest/java/github/daneren2005/dsub/service/DownloadServiceTest.java +++ b/app/src/androidTest/java/github/daneren2005/dsub/service/DownloadServiceTest.java @@ -132,6 +132,7 @@ public class DownloadServiceTest extends // Do a next before the previous downloadService.next(); + downloadService.setPlayerState(STARTED); // Do the previous downloadService.previous(); -- cgit v1.2.3 From 0021824a74ce86ee951c91045504a99e84df46c4 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Fri, 23 Nov 2018 10:25:25 -0800 Subject: Update ServerProxy gradle version --- ServerProxy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServerProxy b/ServerProxy index 5b318194..08f66ee2 160000 --- a/ServerProxy +++ b/ServerProxy @@ -1 +1 @@ -Subproject commit 5b318194f533e4dc121572ccc71261fe99d060db +Subproject commit 08f66ee2da9aa39ae569c8ed2a2ad02f141e971f -- cgit v1.2.3 From b0e78505555701084b18496e5561f92328b1c66f Mon Sep 17 00:00:00 2001 From: Daniel Bowman Date: Sat, 24 Nov 2018 19:03:50 +0000 Subject: Stop current track if rated bad and empty playlist --- .../main/java/github/daneren2005/dsub/service/DownloadService.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index 0fb5e9e5..e9096900 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -2806,14 +2806,16 @@ public class DownloadService extends Service { } public void setRating(int rating) { final DownloadFile currentPlaying = this.currentPlaying; - if(currentPlaying == null) { + if (currentPlaying == null) { return; } MusicDirectory.Entry entry = currentPlaying.getSong(); // Immediately skip to the next song if down thumbed - if(rating == 1) { + if (rating == 1 && size() > 1) { next(true); + } else if (rating == 1 && size() == 1) { + stop(); } UpdateHelper.setRating(this, entry, rating, new UpdateHelper.OnRatingChange() { -- cgit v1.2.3