diff options
27 files changed, 341 insertions, 43 deletions
@@ -1,4 +1,4 @@ -##Basic Instructions +## Basic Instructions Grab dependent libraries ``` git submodule init @@ -12,19 +12,19 @@ android update project --path ./ Add both projects and all .jar's in the libs folder -##SDK Project Dependencies +## SDK Project Dependencies Under sdk -> extras:<br> android -> support -> v7 -> appcompat<br> android -> support -> v7 -> mediarouter<br> google -> google_play_services -> libproject -> google-play-services_lib -##SDK Library Dependencies +## SDK Library Dependencies android -> support -> v4 -> android-support-v4.jar<br> android -> support -> v7 -> appcompat -> libs android-support-v7-appcompat.jar<br> android -> support -> v7 -> mediarouter -> libs -> android-support-v7-mediarouter.jar<br> google -> google_play_services -> libproject -> google-play-services_lib -> lib -> google-play-services.jar -##Updating Icons +## Updating Icons Media Icons are double standard size. On https://romannurik.github.io/AndroidAssetStudio/icons-actionbar.html you can manually change this via the following js commands: ``` PARAM_RESOURCES.iconSize = {w: 64, h: 64} diff --git a/ServerProxy b/ServerProxy -Subproject a4d957353db2634906e0d5099d7a078a111bfab +Subproject d57fe9ee675350799e462ca6a472f70b39475a2 diff --git a/app/build.gradle b/app/build.gradle index 85692969..ba47f345 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,14 +2,14 @@ apply plugin: 'com.android.application' android { compileSdkVersion 24 - buildToolsVersion "23.0.3" + buildToolsVersion '25.0.0' defaultConfig { applicationId "github.daneren2005.dsub" minSdkVersion 14 targetSdkVersion 23 - versionCode 191 - versionName '5.3.3' + versionCode 194 + versionName '5.3.4' setProperty("archivesBaseName", "DSub $versionName") resConfigs "de", "es", "fr", "hu", "nl", "pt-rPT", "ru", "sv" } diff --git a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java index 0b10d7fb..a1c5ceef 100644 --- a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java +++ b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java @@ -250,12 +250,20 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte return; } - populateTabs(); getImageLoader().onUIVisible(); UpdateView.addActiveActivity(); } @Override + protected void onResume() { + super.onResume(); + + // If this is in onStart is causes crashes when rotating screen in offline mode + // Actual root cause of error is `drawerItemSelected(newFragment);` in the offline mode branch of code + populateTabs(); + } + + @Override protected void onStop() { super.onStop(); diff --git a/app/src/main/java/github/daneren2005/dsub/domain/ServerInfo.java b/app/src/main/java/github/daneren2005/dsub/domain/ServerInfo.java index e41a9503..5852210e 100644 --- a/app/src/main/java/github/daneren2005/dsub/domain/ServerInfo.java +++ b/app/src/main/java/github/daneren2005/dsub/domain/ServerInfo.java @@ -251,4 +251,9 @@ public class ServerInfo implements Serializable { public static boolean hasNewestPodcastEpisodes(Context context) { return ServerInfo.checkServerVersion(context, "1.13"); } + + public static boolean canRescanServer(Context context) { + return ServerInfo.isMadsonic(context) || + (ServerInfo.isStockSubsonic(context) && ServerInfo.checkServerVersion(context, "1.15")); + } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java index 8c2fa4bf..82e50b76 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java @@ -67,8 +67,8 @@ public class MainFragment extends SelectRecyclerFragment<Integer> { onFinishSetupOptionsMenu(menu); try { - if (!ServerInfo.isMadsonic(context) || !UserUtil.isCurrentAdmin()) { - menu.setGroupVisible(R.id.madsonic, false); + if (!ServerInfo.canRescanServer(context) || !UserUtil.isCurrentAdmin()) { + menu.setGroupVisible(R.id.rescan_server, false); } } catch(Exception e) { Log.w(TAG, "Error on setting madsonic invisible", e); diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java index 28cf9911..5cb413fe 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java @@ -1,5 +1,8 @@ package github.daneren2005.dsub.fragments; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.support.v7.app.AlertDialog; import android.content.DialogInterface; import android.content.res.Resources; @@ -342,7 +345,24 @@ public class SelectPlaylistFragment extends SelectRecyclerFragment<Playlist> { private void syncPlaylist(Playlist playlist) { SyncUtil.addSyncedPlaylist(context, playlist.getId()); - downloadPlaylist(playlist.getId(), playlist.getName(), true, true, false, false, true); + + boolean syncImmediately; + if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_SYNC_WIFI, true)) { + ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = manager.getActiveNetworkInfo(); + + if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { + syncImmediately = true; + } else { + syncImmediately = false; + } + } else { + syncImmediately = true; + } + + if(syncImmediately) { + downloadPlaylist(playlist.getId(), playlist.getName(), true, true, false, false, true); + } } private void stopSyncPlaylist(final Playlist playlist) { 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 584a205a..fa2ca340 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java @@ -59,6 +59,7 @@ import github.daneren2005.dsub.service.MusicServiceFactory; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.FileUtil; import github.daneren2005.dsub.util.LoadingTask; +import github.daneren2005.dsub.util.MediaRouteManager; import github.daneren2005.dsub.util.SyncUtil; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.CacheLocationPreference; @@ -200,6 +201,18 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared ActivityCompat.requestPermissions(context, new String[]{ Manifest.permission.ACCESS_COARSE_LOCATION }, SubsonicActivity.PERMISSIONS_REQUEST_LOCATION); } } + } else if(Constants.PREFERENCES_KEY_DLNA_CASTING_ENABLED.equals(key)) { + DownloadService downloadService = DownloadService.getInstance(); + if(downloadService != null) { + MediaRouteManager mediaRouter = downloadService.getMediaRouter(); + + Boolean enabled = sharedPreferences.getBoolean(key, true); + if (enabled) { + mediaRouter.addDLNAProvider(); + } else { + mediaRouter.removeDLNAProvider(); + } + } } scheduleBackup(); diff --git a/app/src/main/java/github/daneren2005/dsub/provider/DLNARouteProvider.java b/app/src/main/java/github/daneren2005/dsub/provider/DLNARouteProvider.java index 0f6975ba..0ee16723 100644 --- a/app/src/main/java/github/daneren2005/dsub/provider/DLNARouteProvider.java +++ b/app/src/main/java/github/daneren2005/dsub/provider/DLNARouteProvider.java @@ -71,6 +71,7 @@ public class DLNARouteProvider extends MediaRouteProvider { private List<String> removing = new ArrayList<String>(); private AndroidUpnpService dlnaService; private ServiceConnection dlnaServiceConnection; + private RegistryListener registryListener; private boolean searchOnConnect = false; public DLNARouteProvider(Context context) { @@ -84,7 +85,7 @@ public class DLNARouteProvider extends MediaRouteProvider { @Override public void onServiceConnected(ComponentName name, IBinder service) { dlnaService = (AndroidUpnpService) service; - dlnaService.getRegistry().addListener(new RegistryListener() { + dlnaService.getRegistry().addListener(registryListener = new RegistryListener() { @Override public void remoteDeviceDiscoveryStarted(Registry registry, RemoteDevice remoteDevice) { @@ -142,6 +143,7 @@ public class DLNARouteProvider extends MediaRouteProvider { @Override public void onServiceDisconnected(ComponentName name) { dlnaService = null; + registryListener = null; } }; @@ -290,6 +292,17 @@ public class DLNARouteProvider extends MediaRouteProvider { } } + public void destroy() { + if(dlnaService != null) { + dlnaService.getRegistry().removeListener(registryListener); + registryListener = null; + } + + if(dlnaServiceConnection != null) { + getContext().getApplicationContext().unbindService(dlnaServiceConnection); + } + } + private class DLNARouteController extends RouteController { private DLNADevice device; 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 ece8ee95..35f6d37a 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/AutoMediaBrowserService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/AutoMediaBrowserService.java @@ -21,6 +21,7 @@ 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; @@ -33,8 +34,11 @@ import java.util.ArrayList; import java.util.List; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.Artist; +import github.daneren2005.dsub.domain.Indexes; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.MusicDirectory.Entry; +import github.daneren2005.dsub.domain.MusicFolder; import github.daneren2005.dsub.domain.Playlist; import github.daneren2005.dsub.domain.PodcastChannel; import github.daneren2005.dsub.domain.PodcastEpisode; @@ -58,6 +62,8 @@ public class AutoMediaBrowserService extends MediaBrowserService { private static final String PODCAST_PREFIX = "po-"; private static final String ALBUM_TYPE_PREFIX = "ty-"; private static final String MUSIC_DIRECTORY_PREFIX = "md-"; + private static final String MUSIC_FOLDER_PREFIX = "mf-"; + private static final String MUSIC_DIRECTORY_CONTENTS_PREFIX = "mdc-"; private DownloadService downloadService; private Handler handler = new Handler(); @@ -89,6 +95,12 @@ public class AutoMediaBrowserService extends MediaBrowserService { getPlayOptions(result, id, Constants.INTENT_EXTRA_NAME_ID); } else if(BROWSER_LIBRARY.equals(parentId)) { getLibrary(result); + } else if(parentId.startsWith(MUSIC_FOLDER_PREFIX)) { + String id = parentId.substring(MUSIC_FOLDER_PREFIX.length()); + getIndexes(result, id); + } else if(parentId.startsWith(MUSIC_DIRECTORY_CONTENTS_PREFIX)) { + String id = parentId.substring(MUSIC_DIRECTORY_CONTENTS_PREFIX.length()); + getMusicDirectory(result, id); } else if(BROWSER_PLAYLISTS.equals(parentId)) { getPlaylists(result); } else if(parentId.startsWith(PLAYLIST_PREFIX)) { @@ -115,10 +127,10 @@ public class AutoMediaBrowserService extends MediaBrowserService { .setMediaId(BROWSER_ALBUM_LISTS); mediaItems.add(new MediaBrowser.MediaItem(albumLists.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE)); - /*MediaDescription.Builder library = new MediaDescription.Builder(); + MediaDescription.Builder library = new MediaDescription.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 MediaBrowser.MediaItem(library.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE)); MediaDescription.Builder playlists = new MediaDescription.Builder(); playlists.setTitle(downloadService.getString(R.string.button_bar_playlists)) @@ -218,8 +230,106 @@ public class AutoMediaBrowserService extends MediaBrowserService { result.detach(); } - private void getLibrary(Result<List<MediaBrowser.MediaItem>> result) { + private void getLibrary(final Result<List<MediaBrowser.MediaItem>> result) { + new SilentServiceTask<List<MusicFolder>>(downloadService) { + @Override + protected List<MusicFolder> doInBackground(MusicService musicService) throws Throwable { + return musicService.getMusicFolders(false, downloadService, null); + } + + @Override + protected void done(List<MusicFolder> folders) { + List<MediaBrowser.MediaItem> mediaItems = new ArrayList<>(); + + for(MusicFolder folder: folders) { + MediaDescription description = new MediaDescription.Builder() + .setTitle(folder.getName()) + .setMediaId(MUSIC_FOLDER_PREFIX + folder.getId()) + .build(); + + mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE)); + } + + result.sendResult(mediaItems); + } + }.execute(); + + result.detach(); + } + private void getIndexes(final Result<List<MediaBrowser.MediaItem>> result, final String musicFolderId) { + new SilentServiceTask<Indexes>(downloadService) { + @Override + protected Indexes doInBackground(MusicService musicService) throws Throwable { + return musicService.getIndexes(musicFolderId, false, downloadService, null); + } + + @Override + protected void done(Indexes indexes) { + List<MediaBrowser.MediaItem> mediaItems = new ArrayList<>(); + + // music directories + for(Artist artist : indexes.getArtists()) { + MediaDescription description = new MediaDescription.Builder() + .setTitle(artist.getName()) + .setMediaId(MUSIC_DIRECTORY_CONTENTS_PREFIX + artist.getId()) + .build(); + + mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE)); + } + + // music files + for(Entry entry: indexes.getEntries()) { + MediaDescription description = new MediaDescription.Builder() + .setTitle(entry.getTitle()) + .setMediaId(MUSIC_DIRECTORY_PREFIX + entry.getId()) + .build(); + mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE)); + } + + result.sendResult(mediaItems); + } + }.execute(); + + result.detach(); + } + + private void getMusicDirectory(final Result<List<MediaBrowser.MediaItem>> result, final String musicDirectoryId) { + new SilentServiceTask<MusicDirectory>(downloadService) { + @Override + protected MusicDirectory doInBackground(MusicService musicService) throws Throwable { + return musicService.getMusicDirectory(musicDirectoryId, "", false, downloadService, null); + } + + @Override + protected void done(MusicDirectory directory) { + List<MediaBrowser.MediaItem> mediaItems = new ArrayList<>(); + + addPlayOptions(mediaItems, musicDirectoryId, Constants.INTENT_EXTRA_NAME_ID); + + for(Entry entry : directory.getChildren()) { + MediaDescription description; + if (entry.isDirectory()) { + // browse deeper + description = new MediaDescription.Builder() + .setTitle(entry.getTitle()) + .setMediaId(MUSIC_DIRECTORY_CONTENTS_PREFIX + entry.getId()) + .build(); + } else { + // playback options for a single item + description = new MediaDescription.Builder() + .setTitle(entry.getTitle()) + .setMediaId(MUSIC_DIRECTORY_PREFIX + entry.getId()) + .build(); + } + + mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE)); + } + result.sendResult(mediaItems); + } + }.execute(); + + result.detach(); } private void getPlaylists(final Result<List<MediaBrowser.MediaItem>> result) { @@ -341,10 +451,8 @@ public class AutoMediaBrowserService extends MediaBrowserService { result.detach(); } - - private void getPlayOptions(Result<List<MediaBrowser.MediaItem>> result, String id, String idConstant) { - List<MediaBrowser.MediaItem> mediaItems = new ArrayList<>(); + private void addPlayOptions(List<MediaBrowser.MediaItem> mediaItems, String id, String idConstant) { Bundle playAllExtras = new Bundle(); playAllExtras.putString(idConstant, id); @@ -373,6 +481,12 @@ public class AutoMediaBrowserService extends MediaBrowserService { .setMediaId("playLast-" + id) .setExtras(playLastExtras); mediaItems.add(new MediaBrowser.MediaItem(playLast.build(), MediaBrowser.MediaItem.FLAG_PLAYABLE)); + } + + private void getPlayOptions(Result<List<MediaBrowser.MediaItem>> result, String id, String idConstant) { + List<MediaBrowser.MediaItem> mediaItems = new ArrayList<>(); + + addPlayOptions(mediaItems, id, idConstant); result.sendResult(mediaItems); } 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 e23995f2..636745d6 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -1665,6 +1665,9 @@ public class DownloadService extends Service { return controller; } + public MediaRouteManager getMediaRouter() { + return mediaRouter; + } public MediaRouteSelector getRemoteSelector() { return mediaRouter.getSelector(); } diff --git a/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java b/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java index 1aa1d212..657ac4a9 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java @@ -177,7 +177,17 @@ public class RESTMusicService implements MusicService { @Override public void startRescan(Context context, ProgressListener listener) throws Exception { - Reader reader = getReader(context, listener, "startRescan"); + String startMethod = ServerInfo.isMadsonic(context, getInstance(context)) ? "startRescan" : "startScan"; + String refreshMethod = null; + if(ServerInfo.isMadsonic(context, getInstance(context))) { + startMethod = "startRescan"; + refreshMethod = "scanstatus"; + } else { + startMethod = "startScan"; + refreshMethod = "getScanStatus"; + } + + Reader reader = getReader(context, listener, startMethod); try { new ErrorParser(context, getInstance(context)).parse(reader); } finally { @@ -187,7 +197,7 @@ public class RESTMusicService implements MusicService { // Now check if still running boolean done = false; while(!done) { - reader = getReader(context, null, "scanstatus"); + reader = getReader(context, null, refreshMethod); try { boolean running = new ScanStatusParser(context, getInstance(context)).parse(reader, listener); if(running) { diff --git a/app/src/main/java/github/daneren2005/dsub/service/parser/ScanStatusParser.java b/app/src/main/java/github/daneren2005/dsub/service/parser/ScanStatusParser.java index ffb3ba05..acd00661 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/parser/ScanStatusParser.java +++ b/app/src/main/java/github/daneren2005/dsub/service/parser/ScanStatusParser.java @@ -21,6 +21,7 @@ import org.xmlpull.v1.XmlPullParser; import java.io.Reader; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.ServerInfo; import github.daneren2005.dsub.util.ProgressListener; public class ScanStatusParser extends AbstractParser { @@ -32,14 +33,23 @@ public class ScanStatusParser extends AbstractParser { public boolean parse(Reader reader, ProgressListener progressListener) throws Exception { init(reader); - Boolean started = null; + String scanName, scanningName; + if(ServerInfo.isMadsonic(context, instance)) { + scanName = "status"; + scanningName = "started"; + } else { + scanName = "scanStatus"; + scanningName = "scanning"; + } + + Boolean scanning = null; int eventType; do { eventType = nextParseEvent(); if (eventType == XmlPullParser.START_TAG) { String name = getElementName(); - if("status".equals(name)) { - started = getBoolean("started"); + if(scanName.equals(name)) { + scanning = getBoolean(scanningName); String msg = context.getResources().getString(R.string.parser_scan_count, getInteger("count")); progressListener.updateProgress(msg); @@ -51,6 +61,6 @@ public class ScanStatusParser extends AbstractParser { validate(); - return started != null && started; + return scanning != null && scanning; } }
\ No newline at end of file diff --git a/app/src/main/java/github/daneren2005/dsub/updates/Updater.java b/app/src/main/java/github/daneren2005/dsub/updates/Updater.java index bc053b1e..2dabb624 100644 --- a/app/src/main/java/github/daneren2005/dsub/updates/Updater.java +++ b/app/src/main/java/github/daneren2005/dsub/updates/Updater.java @@ -48,6 +48,7 @@ public class Updater { this.context = context; List<Updater> updaters = new ArrayList<Updater>(); updaters.add(new UpdaterSongPress()); + updaters.add(new UpdaterNoDLNA()); SharedPreferences prefs = Util.getPreferences(context); int lastVersion = prefs.getInt(Constants.LAST_VERSION, 0); diff --git a/app/src/main/java/github/daneren2005/dsub/updates/UpdaterNoDLNA.java b/app/src/main/java/github/daneren2005/dsub/updates/UpdaterNoDLNA.java new file mode 100644 index 00000000..a060c4fd --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/updates/UpdaterNoDLNA.java @@ -0,0 +1,41 @@ +/* + This file is part of Subsonic. + Subsonic 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. + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2016 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.updates; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Build; + +import github.daneren2005.dsub.util.Constants; +import github.daneren2005.dsub.util.Util; + +public class UpdaterNoDLNA extends Updater { + public UpdaterNoDLNA() { + super(534); + TAG = this.getClass().getSimpleName(); + } + + @Override + public void update(Context context) { + SharedPreferences prefs = Util.getPreferences(context); + + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean(Constants.PREFERENCES_KEY_DLNA_CASTING_ENABLED, false); + editor.commit(); + } + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/util/Constants.java b/app/src/main/java/github/daneren2005/dsub/util/Constants.java index d692f4d2..281c87d7 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Constants.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Constants.java @@ -177,7 +177,8 @@ public final class Constants { public static final String PREFERENCES_KEY_HEADS_UP_NOTIFICATION = "headsUpNotification"; public static final String PREFERENCES_KEY_CAST_CACHE = "castCache"; public static final String PREFERENCES_KEY_PLAYBACK_SPEED = "playbackSpeed"; - public static final String PREFERENCES_KEY_SONG_PLAYBACK_SPEED = "songPlaybackSpeed"; + public static final String PREFERENCES_KEY_CUSTOM_PLAYBACK_SPEED = "customPlaybackSpeed"; + public static final String PREFERENCES_KEY_DLNA_CASTING_ENABLED = "dlnaCastingEnabled"; public static final String OFFLINE_SCROBBLE_COUNT = "scrobbleCount"; public static final String OFFLINE_SCROBBLE_ID = "scrobbleID"; diff --git a/app/src/main/java/github/daneren2005/dsub/util/MediaRouteManager.java b/app/src/main/java/github/daneren2005/dsub/util/MediaRouteManager.java index 9aa54c4b..73ec6aec 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/MediaRouteManager.java +++ b/app/src/main/java/github/daneren2005/dsub/util/MediaRouteManager.java @@ -48,6 +48,7 @@ public class MediaRouteManager extends MediaRouter.Callback { private MediaRouteSelector selector; private List<MediaRouteProvider> providers = new ArrayList<MediaRouteProvider>(); private List<MediaRouteProvider> onlineProviders = new ArrayList<MediaRouteProvider>(); + private DLNARouteProvider dlnaProvider; static { try { @@ -159,10 +160,8 @@ public class MediaRouteManager extends MediaRouter.Callback { addOnlineProviders(); } - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - DLNARouteProvider dlnaProvider = new DLNARouteProvider(downloadService); - router.addProvider(dlnaProvider); - providers.add(dlnaProvider); + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && Util.getPreferences(downloadService).getBoolean(Constants.PREFERENCES_KEY_DLNA_CASTING_ENABLED, true)) { + addDLNAProvider(); } } public void buildSelector() { @@ -178,4 +177,20 @@ public class MediaRouteManager extends MediaRouter.Callback { } selector = builder.build(); } + + public void addDLNAProvider() { + if(dlnaProvider == null) { + dlnaProvider = new DLNARouteProvider(downloadService); + router.addProvider(dlnaProvider); + providers.add(dlnaProvider); + } + } + public void removeDLNAProvider() { + if(dlnaProvider != null) { + router.removeProvider(dlnaProvider); + providers.remove(dlnaProvider); + dlnaProvider.destroy(); + dlnaProvider = null; + } + } } 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 d666afb2..00bca833 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 @@ -433,7 +433,9 @@ public class RemoteControlClientLP extends RemoteControlClientBase { } private void noResults() { - + // Keep getting emails from Google that not playing something with no results is bad + downloadService.clear(); + downloadService.setShufflePlayEnabled(true); } private class EventCallback extends MediaSession.Callback { diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml index 4b542668..b264d4fa 100644 --- a/app/src/main/res/menu/main.xml +++ b/app/src/main/res/menu/main.xml @@ -14,7 +14,7 @@ android:title="@string/menu.shuffle" compat:showAsAction="ifRoom|withText"/> - <group android:id="@+id/madsonic"> + <group android:id="@+id/rescan_server"> <item android:id="@+id/menu_rescan" android:title="@string/menu.rescan"/> diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 094b782d..f384060a 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -31,7 +31,7 @@ <string name="button_bar.playlists">Playlists</string> <string name="button_bar.now_playing">Lecture en cours</string> <string name="button_bar.podcasts">Podcasts</string> - <string name="button_bar.bookmarks">Favoris</string> + <string name="button_bar.bookmarks">Signets</string> <string name="button_bar.shares">Partages</string> <string name="button_bar.chat">Chat</string> <string name="button_bar.admin">Admin</string> @@ -204,11 +204,11 @@ <string name="updated_playlist_error">Échec de la mise à jour \"%s\", réessayer plus tard.</string> <string name="removed_playlist">Titre %1$s retiré de \"%2$s\"</string> - <string name="bookmark.delete">Supprimer le favori</string> - <string name="bookmark.delete_title">Supprimer le favori pour</string> - <string name="bookmark.deleted">Favori pour \"%s\" supprimé</string> - <string name="bookmark.deleted_error">Échec de la suppression du favori pour \"%s\"</string> - <string name="bookmark.details_title">Détails du favori</string> + <string name="bookmark.delete">Supprimer le signet</string> + <string name="bookmark.delete_title">Supprimer le signet pour</string> + <string name="bookmark.deleted">Signet pour \"%s\" supprimé</string> + <string name="bookmark.deleted_error">Échec de la suppression du signet pour \"%s\"</string> + <string name="bookmark.details_title">Détails du signet</string> <string name="bookmark.details">Titre : %1$s \nPosition : %2$s \nCréé le : %3$s @@ -361,8 +361,8 @@ <string name="settings.hide_widget_summary">Cacher le widget après avoir quitté l\'application</string> <string name="settings.podcasts_enabled">Podcasts autorisés</string> <string name="settings.podcasts_enabled_summary">Afficher ou non l\'accès aux podcasts</string> - <string name="settings.bookmarks_enabled">Favoris autorisés</string> - <string name="settings.bookmarks_enabled_summary">Afficher ou non l\'accès aux favoris</string> + <string name="settings.bookmarks_enabled">Signets autorisés</string> + <string name="settings.bookmarks_enabled_summary">Afficher ou non l\'accès aux signets</string> <string name="settings.shares_enabled">Partages autorisés</string> <string name="settings.shares_enabled_summary">Afficher ou non l\'accès aux partages</string> <string name="settings.sync_title">Sync</string> diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index e9aadce7..118ccc80 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -74,6 +74,7 @@ <string-array name="maxBitrateValues"> <item>32</item> + <item>48</item> <item>64</item> <item>80</item> <item>96</item> @@ -88,6 +89,7 @@ <string-array name="maxBitrateNames"> <item>@string/settings.max_bitrate_32</item> + <item>@string/settings.max_bitrate_48</item> <item>@string/settings.max_bitrate_64</item> <item>@string/settings.max_bitrate_80</item> <item>@string/settings.max_bitrate_96</item> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0d9c2aa1..b54e4ff2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -321,6 +321,7 @@ <string name="settings.max_bitrate_wifi">Max Audio bitrate - Wi-Fi</string> <string name="settings.max_bitrate_mobile">Max Audio bitrate - Mobile</string> <string name="settings.max_bitrate_32">32 Kbps</string> + <string name="settings.max_bitrate_48">48 Kbps</string> <string name="settings.max_bitrate_64">64 Kbps</string> <string name="settings.max_bitrate_80">80 Kbps</string> <string name="settings.max_bitrate_96">96 Kbps</string> @@ -384,7 +385,7 @@ <string name="settings.temp_loss_nothing">Do Nothing</string> <string name="settings.keep_played_count_title">Keep played songs</string> <string name="settings.keep_played_count_none">Remove all played songs</string> - <string name="settings.keep_played_count_one">Keep last played songs</string> + <string name="settings.keep_played_count_one">Keep last played song</string> <string name="settings.keep_played_count_two">Keep 2 played songs</string> <string name="settings.keep_played_count_three">Keep 3 played songs</string> <string name="settings.disconnect_pause_title">Pause on Disconnect</string> @@ -488,6 +489,8 @@ <string name="settings.heads_up_notification_summary">Show playing notifications as Heads Up notifications (Android Lollipop+ only)</string> <string name="settings.casting_cache">Cache While Casting</string> <string name="settings.casting_cache_summary">Cache currently playing songs while casting</string> + <string name="settings.casting.dlna_casting_enabled">DLNA Enabled</string> + <string name="settings.casting.dlna_casting_enabled.summary">If you are having battery drain problems on Android 7.0 try turning this off</string> <string name="shuffle.title">Shuffle By</string> <string name="shuffle.startYear">Start Year:</string> diff --git a/app/src/main/res/xml/changelog.xml b/app/src/main/res/xml/changelog.xml index 34697168..11257b04 100644 --- a/app/src/main/res/xml/changelog.xml +++ b/app/src/main/res/xml/changelog.xml @@ -1,5 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> <changelog> + <release version="5.3.4" versioncode="193" releasedate="11/28/2016"> + <change>Added toggle for DLNA casting to fix battery issues some users are having on Android 7.0+</change> + <change>Fix rotating screen in offline mode</change> + </release> <release version="5.3.3" versioncode="191" releasedate="11/9/2016"> <change>Add support for Android 7's split screen UI</change> <change>Fix for Android 7 not playing</change> diff --git a/app/src/main/res/xml/settings_cast.xml b/app/src/main/res/xml/settings_cast.xml index c23ae04d..78bafdd4 100644 --- a/app/src/main/res/xml/settings_cast.xml +++ b/app/src/main/res/xml/settings_cast.xml @@ -28,4 +28,14 @@ android:key="castCache" android:defaultValue="false"/> </PreferenceCategory> + + <PreferenceCategory + android:title="@string/settings.other_title"> + + <CheckBoxPreference + android:title="@string/settings.casting.dlna_casting_enabled" + android:summary="@string/settings.casting.dlna_casting_enabled.summary" + android:key="dlnaCastingEnabled" + android:defaultValue="true"/> + </PreferenceCategory> </PreferenceScreen>
\ No newline at end of file diff --git a/build.gradle b/build.gradle index 5b7e9efd..b3146795 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.2' + classpath 'com.android.tools.build:gradle:2.3.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 f9d370e8..a58c8fc3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Aug 16 16:00:21 PDT 2016 +#Tue Mar 07 08:58:29 PST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip diff --git a/privacy.txt b/privacy.txt new file mode 100644 index 00000000..336f0bc0 --- /dev/null +++ b/privacy.txt @@ -0,0 +1,23 @@ +Privacy Policy +General + +DSub For Subsonic ("DSub") is developed & maintained by one developer. As the developer of DSub, I do care about and respect your privacy. + +This Privacy Policy ("Policy") aims to describe how information obtained from users is collected, used and disclosed. + +By using DSub, you agree that your personal information will be handled as described in this Policy. +Information being collected + +DSub does not collect any personally identifiable information. + +DSub requests the permission 'READ_PHONE_STATE'. This permission is used by DSub solely to determine whether you're in a phone call/the phone is ringing, so that music playback can be paused. This permission also grants access to some personally identifiable information (your phone's IMEI number, your phone number and your network/carrier). This personally identifiable information is never accessed, used, stored or disclosed by DSub. +DSub requests the permission 'RECORD_AUDIO'. This permission is used by DSub to provide Equalizer functionality and no audio is ever stored or transmitted by DSub. + +Changes to the Policy + +If the Policy changes, the modification date below will be updated. The Policy may change from time to time, so please be sure to check back periodically. + +Last modified: 08 March, 2017. +Contact + +If you have any questions about the Policy, please contact me via dsub.android@gmail.com.com |