diff options
30 files changed, 345 insertions, 213 deletions
@@ -13,7 +13,7 @@ <content url="file://$MODULE_DIR$"> <excludeFolder url="file://$MODULE_DIR$/.gradle" /> </content> - <orderEntry type="inheritedJdk" /> + <orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" /> <orderEntry type="sourceFolder" forTests="false" /> </component> </module>
\ No newline at end of file diff --git a/ServerProxy b/ServerProxy -Subproject d57fe9ee675350799e462ca6a472f70b39475a2 +Subproject 5b318194f533e4dc121572ccc71261fe99d060d diff --git a/app/build.gradle b/app/build.gradle index 26afb5ea..47604723 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -28,6 +28,16 @@ android { } } + productFlavors { + floss { + // FLOSS build (no proprietary libraries) + } + google { + // FLOSS build + Google libraries + // Adds ChromeCast support + } + } + packagingOptions { exclude 'META-INF/beans.xml' } @@ -51,7 +61,7 @@ dependencies { compile 'com.android.support:mediarouter-v7:24.2.+' compile 'com.android.support:recyclerview-v7:24.2.+' compile 'com.android.support:design:24.2.+' - compile 'com.google.android.gms:play-services-cast:8.1.0' + 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' diff --git a/app/src/floss/java/github/daneren2005/dsub/util/compat/GoogleCompat.java b/app/src/floss/java/github/daneren2005/dsub/util/compat/GoogleCompat.java new file mode 100644 index 00000000..08db4f1c --- /dev/null +++ b/app/src/floss/java/github/daneren2005/dsub/util/compat/GoogleCompat.java @@ -0,0 +1,31 @@ +package github.daneren2005.dsub.util.compat; + +import android.content.Context; +import android.support.v7.media.MediaRouter; + +import github.daneren2005.dsub.service.DownloadService; +import github.daneren2005.dsub.service.RemoteController; + + +// Provides stubs for Google-related functionality +public final class GoogleCompat { + + public static boolean playServicesAvailable(Context context) { + return false; + } + + public static void installProvider(Context context) throws Exception { + } + + public static boolean castAvailable() { + return false; + } + + public static RemoteController getController(DownloadService downloadService, MediaRouter.RouteInfo info) { + return null; + } + + public static String getCastControlCategory() { + return null; + } +} diff --git a/app/src/google/AndroidManifest.xml b/app/src/google/AndroidManifest.xml new file mode 100644 index 00000000..14827d43 --- /dev/null +++ b/app/src/google/AndroidManifest.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="github.daneren2005.dsub"> + + <meta-data + android:name="com.google.android.backup.api_key" + android:value="AEdPqrEAAAAIUhOMtwa_eG-f0oYUHnetl_Cz7cO9zae8ZXOK5w" /> + <meta-data + android:name="com.google.android.gms.version" + android:value="@integer/google_play_services_version" /> + <meta-data + android:name="com.google.android.gms.car.application" + android:resource="@xml/auto_app_description" /> + <meta-data + android:name="com.google.android.gms.car.notification.SmallIcon" + android:resource="@drawable/stat_notify_playing" /> + +</manifest> diff --git a/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java b/app/src/google/java/github/daneren2005/dsub/service/ChromeCastController.java index f9e2bfb1..b2405705 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java +++ b/app/src/google/java/github/daneren2005/dsub/service/ChromeCastController.java @@ -45,7 +45,6 @@ import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.EnvironmentVariables; import github.daneren2005.dsub.util.FileUtil; import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.util.compat.CastCompat; import github.daneren2005.serverproxy.FileProxy; import github.daneren2005.serverproxy.ServerProxy; import github.daneren2005.serverproxy.WebProxy; diff --git a/app/src/google/java/github/daneren2005/dsub/util/compat/GoogleCompat.java b/app/src/google/java/github/daneren2005/dsub/util/compat/GoogleCompat.java new file mode 100644 index 00000000..63992b0f --- /dev/null +++ b/app/src/google/java/github/daneren2005/dsub/util/compat/GoogleCompat.java @@ -0,0 +1,61 @@ +package github.daneren2005.dsub.util.compat; + +import android.content.Context; +import android.support.v7.media.MediaRouter; +import android.util.Log; + +import com.google.android.gms.cast.CastDevice; +import com.google.android.gms.cast.CastMediaControlIntent; +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GoogleApiAvailability; +import com.google.android.gms.security.ProviderInstaller; + +import github.daneren2005.dsub.service.ChromeCastController; +import github.daneren2005.dsub.service.DownloadService; +import github.daneren2005.dsub.service.RemoteController; +import github.daneren2005.dsub.util.EnvironmentVariables; + +public final class GoogleCompat { + + private static final String TAG = GoogleCompat.class.getSimpleName(); + + public static boolean playServicesAvailable(Context context){ + int result = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context); + if(result != ConnectionResult.SUCCESS){ + Log.w(TAG, "No play services, failed with result: " + result); + return false; + } + return true; + } + + public static void installProvider(Context context) throws Exception{ + ProviderInstaller.installIfNeeded(context); + } + + public static boolean castAvailable() { + if (EnvironmentVariables.CAST_APPLICATION_ID == null) { + Log.w(TAG, "CAST_APPLICATION_ID not provided"); + return false; + } + try { + Class.forName("com.google.android.gms.cast.CastDevice"); + } catch (Exception ex) { + Log.w(TAG, "Chromecast library not available"); + return false; + } + return true; + } + + public static RemoteController getController(DownloadService downloadService, MediaRouter.RouteInfo info) { + CastDevice device = CastDevice.getFromBundle(info.getExtras()); + if(device != null) { + return new ChromeCastController(downloadService, device); + } else { + return null; + } + } + + public static String getCastControlCategory() { + return CastMediaControlIntent.categoryForCast(EnvironmentVariables.CAST_APPLICATION_ID); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 37643a21..06f79977 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -243,18 +243,7 @@ <meta-data android:name="android.app.default_searchable" android:value="github.daneren2005.dsub.activity.QueryReceiverActivity"/> - - <meta-data android:name="com.google.android.backup.api_key" - android:value="AEdPqrEAAAAIUhOMtwa_eG-f0oYUHnetl_Cz7cO9zae8ZXOK5w"/> - <meta-data - android:name="com.google.android.gms.version" - android:value="@integer/google_play_services_version" /> - - <meta-data android:name="com.google.android.gms.car.application" - android:resource="@xml/auto_app_description"/> - <meta-data android:name="com.google.android.gms.car.notification.SmallIcon" - android:resource="@drawable/stat_notify_playing" /> </application> </manifest> 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 82e50b76..e7c7f1fb 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java @@ -270,6 +270,10 @@ public class MainFragment extends SelectRecyclerFragment<Integer> { } private void getLogs() { + if (EnvironmentVariables.PASTEBIN_DEV_KEY == null) { + Util.toast(context, "No PASTEBIN_DEV_KEY configured - can't upload logs"); + return; + } try { final PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); new LoadingTask<String>(context) { diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java index 10623b4e..f1b2b9c8 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java @@ -1175,10 +1175,10 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis downloadService.previous(); break; case ACTION_FORWARD: - downloadService.seekTo(downloadService.getPlayerPosition() + DownloadService.FAST_FORWARD); + downloadService.fastForward(); break; case ACTION_REWIND: - downloadService.seekTo(downloadService.getPlayerPosition() - DownloadService.REWIND); + downloadService.rewind(); break; } return null; @@ -1364,7 +1364,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis switch (playerState) { case DOWNLOADING: if(currentPlaying != null) { - if(Util.isWifiRequiredForDownload(context)) { + if(Util.isWifiRequiredForDownload(context) || Util.isLocalNetworkRequiredForDownload(context)) { statusTextView.setText(context.getResources().getString(R.string.download_playerstate_mobile_disabled)); } else { long bytes = currentPlaying.getPartialFile().length(); 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 fa2ca340..94c9b7fc 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java @@ -795,7 +795,7 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared try { String url = (String) value; new URL(url); - if (url.contains(" ") || url.contains("@") || url.contains("_")) { + if (url.contains(" ") || url.contains("@")) { throw new Exception(); } } catch (Exception x) { @@ -816,7 +816,7 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared } new URL(url); - if (url.contains(" ") || url.contains("@") || url.contains("_")) { + if (url.contains(" ") || url.contains("@")) { throw new Exception(); } } catch (Exception x) { diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java index de230309..a8b21be9 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java @@ -1601,7 +1601,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR Share share = shares.get(0); shareExternal(share); } else { - Util.toast(context, context.getResources().getString(R.string.playlist_error), false); + Util.toast(context, context.getResources().getString(R.string.share_create_error), false); } } @@ -1611,9 +1611,10 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR if (error instanceof OfflineException || error instanceof ServerTooOldException) { msg = getErrorMessage(error); } else { - msg = context.getResources().getString(R.string.playlist_error) + " " + getErrorMessage(error); + msg = context.getResources().getString(R.string.share_create_error) + " " + getErrorMessage(error); } + Log.e(TAG, "Failed to create share", error); Util.toast(context, msg, false); } }.execute(); 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 35f6d37a..88cfe559 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/AutoMediaBrowserService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/AutoMediaBrowserService.java @@ -279,12 +279,18 @@ public class AutoMediaBrowserService extends MediaBrowserService { // music files for(Entry entry: indexes.getEntries()) { + entry.setBookmark(null); // don't resume from a bookmark in a browse listing + Bundle extras = new Bundle(); + extras.putSerializable(Constants.INTENT_EXTRA_ENTRY, entry); + extras.putString(Constants.INTENT_EXTRA_NAME_CHILD_ID, entry.getId()); + MediaDescription description = new MediaDescription.Builder() .setTitle(entry.getTitle()) - .setMediaId(MUSIC_DIRECTORY_PREFIX + entry.getId()) + .setMediaId(entry.getId()) + .setExtras(extras) .build(); - mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE)); + mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_PLAYABLE)); } result.sendResult(mediaItems); @@ -315,15 +321,24 @@ public class AutoMediaBrowserService extends MediaBrowserService { .setTitle(entry.getTitle()) .setMediaId(MUSIC_DIRECTORY_CONTENTS_PREFIX + entry.getId()) .build(); + + mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE)); } else { - // playback options for a single item + // mark individual songs as directly playable + entry.setBookmark(null); // don't resume from a bookmark in a browse listing + Bundle extras = new Bundle(); + extras.putSerializable(Constants.INTENT_EXTRA_ENTRY, entry); + extras.putString(Constants.INTENT_EXTRA_NAME_CHILD_ID, entry.getId()); + description = new MediaDescription.Builder() .setTitle(entry.getTitle()) - .setMediaId(MUSIC_DIRECTORY_PREFIX + entry.getId()) + .setMediaId(entry.getId()) + .setExtras(extras) .build(); + + mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_PLAYABLE)); } - mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE)); } 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 8213a7d4..a4ca705c 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -68,6 +68,7 @@ import java.util.Iterator; import java.util.List; import java.util.Timer; import java.util.TimerTask; +import java.util.concurrent.CopyOnWriteArrayList; import android.annotation.TargetApi; import android.app.Service; @@ -107,12 +108,11 @@ public class DownloadService extends Service { public static final String CMD_NEXT = "github.daneren2005.dsub.CMD_NEXT"; public static final String CANCEL_DOWNLOADS = "github.daneren2005.dsub.CANCEL_DOWNLOADS"; public static final String START_PLAY = "github.daneren2005.dsub.START_PLAYING"; - public static final int FAST_FORWARD = 30000; - public static final int REWIND = 10000; private static final long DEFAULT_DELAY_UPDATE_PROGRESS = 1000L; private static final double DELETE_CUTOFF = 0.84; private static final int REQUIRED_ALBUM_MATCHES = 4; - private static final int REMOTE_PLAYLIST_TOTAL = 3; + private static final int REMOTE_PLAYLIST_PREV = 10; + private static final int REMOTE_PLAYLIST_NEXT = 40; private static final int SHUFFLE_MODE_NONE = 0; private static final int SHUFFLE_MODE_ALL = 1; private static final int SHUFFLE_MODE_ARTIST = 2; @@ -155,7 +155,7 @@ public class DownloadService extends Service { private boolean removePlayed; private boolean shufflePlay; private boolean artistRadio; - private final List<OnSongChangedListener> onSongChangedListeners = new ArrayList<>(); + private final CopyOnWriteArrayList<OnSongChangedListener> onSongChangedListeners = new CopyOnWriteArrayList<>(); private long revision; private static DownloadService instance; private String suggestedPlaylistName; @@ -509,14 +509,17 @@ public class DownloadService extends Service { private synchronized void updateRemotePlaylist() { List<DownloadFile> playlist = new ArrayList<>(); if(currentPlaying != null) { - int index = downloadList.indexOf(currentPlaying); - if(index == -1) { - index = 0; + int startIndex = downloadList.indexOf(currentPlaying) - REMOTE_PLAYLIST_PREV; + if(startIndex < 0) { + startIndex = 0; } int size = size(); - int end = index + REMOTE_PLAYLIST_TOTAL; - for(int i = index; i < size && i < end; i++) { + int endIndex = downloadList.indexOf(currentPlaying) + REMOTE_PLAYLIST_NEXT; + if(endIndex > size) { + endIndex = size; + } + for(int i = startIndex; i < endIndex; i++) { playlist.add(downloadList.get(i)); } } @@ -1038,6 +1041,15 @@ public class DownloadService extends Service { return temp; } + public synchronized List<DownloadFile> 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); + List<DownloadFile> temp = downloadList.subList(from, to); + temp.addAll(backgroundDownloadList); + return temp; + } + public List<DownloadFile> getBackgroundDownloads() { return backgroundDownloadList; } @@ -1178,10 +1190,10 @@ public class DownloadService extends Service { } } public synchronized int rewind() { - return seekToWrapper(-REWIND); + return seekToWrapper(Integer.parseInt(Util.getPreferences(this).getString(Constants.PREFERENCES_KEY_REWIND_INTERVAL, "10"))*-1000); } public synchronized int fastForward() { - return seekToWrapper(FAST_FORWARD); + return seekToWrapper(Integer.parseInt(Util.getPreferences(this).getString(Constants.PREFERENCES_KEY_FASTFORWARD_INTERVAL, "30"))*1000); } protected int seekToWrapper(int difference) { int msPlayed = Math.max(0, getPlayerPosition()); @@ -2605,7 +2617,7 @@ public class DownloadService extends Service { // Check forwards for(int i = index + 1; i < downloadList.size() && matched < REQUIRED_ALBUM_MATCHES; i++) { - if(albumName.equals(downloadList.get(i).getSong().getAlbum())) { + if(Util.equals(albumName, downloadList.get(i).getSong().getAlbum())) { matched++; } else { break; @@ -2614,7 +2626,7 @@ public class DownloadService extends Service { // Check backwards for(int i = index - 1; i >= 0 && matched < REQUIRED_ALBUM_MATCHES; i--) { - if(albumName.equals(downloadList.get(i).getSong().getAlbum())) { + if(Util.equals(albumName, downloadList.get(i).getSong().getAlbum())) { matched++; } else { break; @@ -2789,12 +2801,7 @@ public class DownloadService extends Service { addOnSongChangedListener(listener, false); } public void addOnSongChangedListener(OnSongChangedListener listener, boolean run) { - synchronized(onSongChangedListeners) { - int index = onSongChangedListeners.indexOf(listener); - if (index == -1) { - onSongChangedListeners.add(listener); - } - } + onSongChangedListeners.addIfAbsent(listener); if(run) { if(mediaPlayerHandler != null) { @@ -2813,56 +2820,47 @@ public class DownloadService extends Service { } } public void removeOnSongChangeListener(OnSongChangedListener listener) { - synchronized(onSongChangedListeners) { - int index = onSongChangedListeners.indexOf(listener); - if (index != -1) { - onSongChangedListeners.remove(index); - } - } + onSongChangedListeners.remove(listener); } private void onSongChanged() { final long atRevision = revision; - synchronized(onSongChangedListeners) { - final boolean shouldFastForward = shouldFastForward(); - for (final OnSongChangedListener listener : onSongChangedListeners) { - handler.post(new Runnable() { - @Override - public void run() { - if (revision == atRevision && instance != null) { - listener.onSongChanged(currentPlaying, currentPlayingIndex, shouldFastForward); + final boolean shouldFastForward = shouldFastForward(); + for (final OnSongChangedListener listener : onSongChangedListeners) { + handler.post(new Runnable() { + @Override + public void run() { + if (revision == atRevision && instance != null) { + listener.onSongChanged(currentPlaying, currentPlayingIndex, shouldFastForward); - MusicDirectory.Entry entry = currentPlaying != null ? currentPlaying.getSong() : null; - listener.onMetadataUpdate(entry, METADATA_UPDATED_ALL); - } + MusicDirectory.Entry entry = currentPlaying != null ? currentPlaying.getSong() : null; + listener.onMetadataUpdate(entry, METADATA_UPDATED_ALL); } - }); - } + } + }); + } - if (mediaPlayerHandler != null && !onSongChangedListeners.isEmpty()) { - mediaPlayerHandler.post(new Runnable() { - @Override - public void run() { - onSongProgress(); - } - }); - } + if (mediaPlayerHandler != null && !onSongChangedListeners.isEmpty()) { + mediaPlayerHandler.post(new Runnable() { + @Override + public void run() { + onSongProgress(); + } + }); } } private void onSongsChanged() { final long atRevision = revision; - synchronized(onSongChangedListeners) { - final boolean shouldFastForward = shouldFastForward(); - for (final OnSongChangedListener listener : onSongChangedListeners) { - handler.post(new Runnable() { - @Override - public void run() { - if (revision == atRevision && instance != null) { - listener.onSongsChanged(downloadList, currentPlaying, currentPlayingIndex, shouldFastForward); - } + final boolean shouldFastForward = shouldFastForward(); + for (final OnSongChangedListener listener : onSongChangedListeners) { + handler.post(new Runnable() { + @Override + public void run() { + if (revision == atRevision && instance != null) { + listener.onSongsChanged(downloadList, currentPlaying, currentPlayingIndex, shouldFastForward); } - }); - } + } + }); } } @@ -2877,17 +2875,15 @@ public class DownloadService extends Service { final int index = getCurrentPlayingIndex(); final int queueSize = size(); - synchronized(onSongChangedListeners) { - for (final OnSongChangedListener listener : onSongChangedListeners) { - handler.post(new Runnable() { - @Override - public void run() { - if (revision == atRevision && instance != null) { - listener.onSongProgress(currentPlaying, position, duration, isSeekable); - } + for (final OnSongChangedListener listener : onSongChangedListeners) { + handler.post(new Runnable() { + @Override + public void run() { + if (revision == atRevision && instance != null) { + listener.onSongProgress(currentPlaying, position, duration, isSeekable); } - }); - } + } + }); } if(manual) { @@ -2910,35 +2906,31 @@ public class DownloadService extends Service { } private void onStateUpdate() { final long atRevision = revision; - synchronized(onSongChangedListeners) { - for (final OnSongChangedListener listener : onSongChangedListeners) { - handler.post(new Runnable() { - @Override - public void run() { - if (revision == atRevision && instance != null) { - listener.onStateUpdate(currentPlaying, playerState); - } + for (final OnSongChangedListener listener : onSongChangedListeners) { + handler.post(new Runnable() { + @Override + public void run() { + if (revision == atRevision && instance != null) { + listener.onStateUpdate(currentPlaying, playerState); } - }); - } + } + }); } } public void onMetadataUpdate() { onMetadataUpdate(METADATA_UPDATED_ALL); } public void onMetadataUpdate(final int updateType) { - synchronized(onSongChangedListeners) { - for (final OnSongChangedListener listener : onSongChangedListeners) { - handler.post(new Runnable() { - @Override - public void run() { - if (instance != null) { - MusicDirectory.Entry entry = currentPlaying != null ? currentPlaying.getSong() : null; - listener.onMetadataUpdate(entry, updateType); - } + for (final OnSongChangedListener listener : onSongChangedListeners) { + handler.post(new Runnable() { + @Override + public void run() { + if (instance != null) { + MusicDirectory.Entry entry = currentPlaying != null ? currentPlaying.getSong() : null; + listener.onMetadataUpdate(entry, updateType); } - }); - } + } + }); } handler.post(new Runnable() { 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 657ac4a9..a4987b09 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java @@ -42,8 +42,6 @@ import android.net.NetworkInfo; import android.util.Base64; import android.util.Log; -import com.google.android.gms.security.ProviderInstaller; - import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.*; import github.daneren2005.dsub.fragments.MainFragment; @@ -81,6 +79,8 @@ import github.daneren2005.dsub.util.FileUtil; import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.SongDBHandler; import github.daneren2005.dsub.util.Util; +import github.daneren2005.dsub.util.compat.GoogleCompat; + import java.io.*; import java.util.Map; import java.util.zip.GZIPInputStream; @@ -1875,7 +1875,7 @@ public class RESTMusicService implements MusicService { private HttpURLConnection getConnectionDirect(Context context, String url, Map<String, String> headers, int minNetworkTimeout) throws Exception { if(!hasInstalledGoogleSSL) { try { - ProviderInstaller.installIfNeeded(context); + GoogleCompat.installProvider(context); } catch(Exception e) { // Just continue on anyways, doesn't really harm anything if this fails Log.w(TAG, "Failed to update to use Google Play SSL", e); diff --git a/app/src/main/java/github/daneren2005/dsub/util/CacheCleaner.java b/app/src/main/java/github/daneren2005/dsub/util/CacheCleaner.java index ac8fa72a..f160e176 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/CacheCleaner.java +++ b/app/src/main/java/github/daneren2005/dsub/util/CacheCleaner.java @@ -151,7 +151,7 @@ public class CacheCleaner { private Set<File> findUndeletableFiles() { Set<File> undeletable = new HashSet<File>(5); - for (DownloadFile downloadFile : downloadService.getDownloads()) { + for (DownloadFile downloadFile : downloadService.getRecentDownloads()) { undeletable.add(downloadFile.getPartialFile()); undeletable.add(downloadFile.getCompleteFile()); } 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 21adce8c..e0a1e164 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Constants.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Constants.java @@ -103,6 +103,7 @@ public final class Constants { public static final String PREFERENCES_KEY_SCROBBLE = "scrobble"; public static final String PREFERENCES_KEY_REPEAT_MODE = "repeatMode"; public static final String PREFERENCES_KEY_WIFI_REQUIRED_FOR_DOWNLOAD = "wifiRequiredForDownload"; + public static final String PREFERENCES_KEY_LOCAL_NETWORK_REQUIRED_FOR_DOWNLOAD = "localNetworkRequiredForDownload"; public static final String PREFERENCES_KEY_RANDOM_SIZE = "randomSize"; public static final String PREFERENCES_KEY_SLEEP_TIMER_DURATION = "sleepTimerDuration"; public static final String PREFERENCES_KEY_OFFLINE = "offline"; @@ -179,7 +180,9 @@ public final class Constants { 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_DLNA_CASTING_ENABLED = "dlnaCastingEnabled"; - + public static final String PREFERENCES_KEY_REWIND_INTERVAL = "rewindInterval"; + public static final String PREFERENCES_KEY_FASTFORWARD_INTERVAL = "fastforwardInterval"; + public static final String OFFLINE_SCROBBLE_COUNT = "scrobbleCount"; public static final String OFFLINE_SCROBBLE_ID = "scrobbleID"; public static final String OFFLINE_SCROBBLE_SEARCH = "scrobbleTitle"; diff --git a/app/src/main/java/github/daneren2005/dsub/util/EnvironmentVariables.java b/app/src/main/java/github/daneren2005/dsub/util/EnvironmentVariables.java index 710d5232..8af74f07 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/EnvironmentVariables.java +++ b/app/src/main/java/github/daneren2005/dsub/util/EnvironmentVariables.java @@ -16,6 +16,6 @@ package github.daneren2005.dsub.util; public final class EnvironmentVariables { - public static final String PASTEBIN_DEV_KEY = ""; - public static final String CAST_APPLICATION_ID = ""; + public static final String PASTEBIN_DEV_KEY = null; + public static final String CAST_APPLICATION_ID = null; } diff --git a/app/src/main/java/github/daneren2005/dsub/util/FileUtil.java b/app/src/main/java/github/daneren2005/dsub/util/FileUtil.java index 04dc73b7..fb395c77 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/FileUtil.java +++ b/app/src/main/java/github/daneren2005/dsub/util/FileUtil.java @@ -67,8 +67,8 @@ public class FileUtil { private static final String TAG = FileUtil.class.getSimpleName(); private static final String[] FILE_SYSTEM_UNSAFE = {"/", "\\", "..", ":", "\"", "?", "*", "<", ">", "|"}; private static final String[] FILE_SYSTEM_UNSAFE_DIR = {"\\", "..", ":", "\"", "?", "*", "<", ">", "|"}; - private static final List<String> MUSIC_FILE_EXTENSIONS = Arrays.asList("mp3", "ogg", "aac", "flac", "m4a", "wav", "wma"); - private static final List<String> VIDEO_FILE_EXTENSIONS = Arrays.asList("flv", "mp4", "m4v", "wmv", "avi", "mov", "mpg", "mkv"); + private static final List<String> MUSIC_FILE_EXTENSIONS = Arrays.asList("mp3", "ogg", "aac", "flac", "m4a", "wav", "wma", "opus", "oga"); + private static final List<String> VIDEO_FILE_EXTENSIONS = Arrays.asList("flv", "mp4", "m4v", "wmv", "avi", "mov", "mpg", "mkv", "3gp", "webm"); private static final List<String> PLAYLIST_FILE_EXTENSIONS = Arrays.asList("m3u"); private static final int MAX_FILENAME_LENGTH = 254 - ".complete.mp3".length(); private static File DEFAULT_MUSIC_DIR; 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 73ec6aec..e19cc156 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/MediaRouteManager.java +++ b/app/src/main/java/github/daneren2005/dsub/util/MediaRouteManager.java @@ -19,10 +19,6 @@ import android.os.Build; import android.support.v7.media.MediaRouteProvider; import android.support.v7.media.MediaRouteSelector; import android.support.v7.media.MediaRouter; -import android.util.Log; - -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GooglePlayServicesUtil; import java.util.ArrayList; import java.util.List; @@ -32,7 +28,7 @@ import github.daneren2005.dsub.provider.DLNARouteProvider; import github.daneren2005.dsub.provider.JukeboxRouteProvider; import github.daneren2005.dsub.service.DownloadService; import github.daneren2005.dsub.service.RemoteController; -import github.daneren2005.dsub.util.compat.CastCompat; +import github.daneren2005.dsub.util.compat.GoogleCompat; import static android.support.v7.media.MediaRouter.RouteInfo; @@ -50,25 +46,10 @@ public class MediaRouteManager extends MediaRouter.Callback { private List<MediaRouteProvider> onlineProviders = new ArrayList<MediaRouteProvider>(); private DLNARouteProvider dlnaProvider; - static { - try { - CastCompat.checkAvailable(); - castAvailable = true; - } catch(Throwable t) { - castAvailable = false; - } - } - public MediaRouteManager(DownloadService downloadService) { this.downloadService = downloadService; router = MediaRouter.getInstance(downloadService); - - // Check if play services is available - int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(downloadService); - if(result != ConnectionResult.SUCCESS){ - Log.w(TAG, "No play services, failed with result: " + result); - castAvailable = false; - } + castAvailable = GoogleCompat.playServicesAvailable(downloadService) && GoogleCompat.castAvailable(); addProviders(); buildSelector(); @@ -83,7 +64,7 @@ public class MediaRouteManager extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, RouteInfo info) { if(castAvailable) { - RemoteController controller = CastCompat.getController(downloadService, info); + RemoteController controller = GoogleCompat.getController(downloadService, info); if(controller != null) { downloadService.setRemoteEnabled(RemoteControlState.CHROMECAST, controller); } @@ -137,7 +118,7 @@ public class MediaRouteManager extends MediaRouter.Callback { } public RemoteController getRemoteController(RouteInfo info) { if(castAvailable) { - return CastCompat.getController(downloadService, info); + return GoogleCompat.getController(downloadService, info); } else { return null; } @@ -170,7 +151,7 @@ public class MediaRouteManager extends MediaRouter.Callback { builder.addControlCategory(JukeboxRouteProvider.CATEGORY_JUKEBOX_ROUTE); } if(castAvailable) { - builder.addControlCategory(CastCompat.getCastControlCategory()); + builder.addControlCategory(GoogleCompat.getCastControlCategory()); } if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { builder.addControlCategory(DLNARouteProvider.CATEGORY_DLNA); 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 7f8a168d..93004a48 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Util.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Util.java @@ -36,6 +36,7 @@ import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.media.AudioManager.OnAudioFocusChangeListener; import android.net.ConnectivityManager; +import android.net.Network; import android.net.NetworkInfo; import android.net.wifi.WifiManager; import android.os.Build; @@ -1082,7 +1083,10 @@ public final class Util { boolean wifiConnected = connected && networkInfo.getType() == ConnectivityManager.TYPE_WIFI; boolean wifiRequired = isWifiRequiredForDownload(context); - return connected && (!wifiRequired || wifiConnected); + boolean isLocalNetwork = connected && !networkInfo.isRoaming(); + boolean localNetworkRequired = isLocalNetworkRequiredForDownload(context); + + return connected && (!wifiRequired || wifiConnected) && (!localNetworkRequired || isLocalNetwork); } else { return connected; } @@ -1116,6 +1120,11 @@ public final class Util { return prefs.getBoolean(Constants.PREFERENCES_KEY_WIFI_REQUIRED_FOR_DOWNLOAD, false); } + public static boolean isLocalNetworkRequiredForDownload(Context context) { + SharedPreferences prefs = getPreferences(context); + return prefs.getBoolean(Constants.PREFERENCES_KEY_LOCAL_NETWORK_REQUIRED_FOR_DOWNLOAD, false); + } + public static void info(Context context, int titleId, int messageId) { info(context, titleId, messageId, true); } diff --git a/app/src/main/java/github/daneren2005/dsub/util/compat/CastCompat.java b/app/src/main/java/github/daneren2005/dsub/util/compat/CastCompat.java deleted file mode 100644 index 415106db..00000000 --- a/app/src/main/java/github/daneren2005/dsub/util/compat/CastCompat.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - 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 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.util.compat; - -import android.support.v7.media.MediaRouter; - -import com.google.android.gms.cast.CastDevice; -import com.google.android.gms.cast.CastMediaControlIntent; - -import github.daneren2005.dsub.service.ChromeCastController; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.RemoteController; -import github.daneren2005.dsub.util.EnvironmentVariables; - -public final class CastCompat { - static { - try { - Class.forName("com.google.android.gms.cast.CastDevice"); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - public static void checkAvailable() throws Throwable { - // Calling here forces class initialization. - } - - public static RemoteController getController(DownloadService downloadService, MediaRouter.RouteInfo info) { - CastDevice device = CastDevice.getFromBundle(info.getExtras()); - if(device != null) { - return new ChromeCastController(downloadService, device); - } else { - return null; - } - } - - public static String getCastControlCategory() { - return CastMediaControlIntent.categoryForCast(EnvironmentVariables.CAST_APPLICATION_ID); - } -} 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 00bca833..816a071d 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 @@ -370,6 +370,30 @@ public class RemoteControlClientLP extends RemoteControlClientBase { private void playMusicDirectory(Entry dir, boolean shuffle, boolean append, boolean playFromBookmark) { playMusicDirectory(dir.getId(), shuffle, append, playFromBookmark); } + private void playMusicDirectory(final String dirId, final boolean shuffle, final boolean append, final Entry startEntry) { + new SilentServiceTask<Void>(downloadService) { + @Override + protected Void doInBackground(MusicService musicService) throws Throwable { + MusicDirectory musicDirectory; + if(Util.isTagBrowsing(downloadService) && !Util.isOffline(downloadService)) { + musicDirectory = musicService.getAlbum(dirId, "dir", false, downloadService, null); + } else { + musicDirectory = musicService.getMusicDirectory(dirId, "dir", false, downloadService, null); + } + + List<Entry> playEntries = new ArrayList<>(); + List<Entry> allEntries = musicDirectory.getChildren(false, true); + for(Entry song: allEntries) { + if (!song.isVideo() && song.getRating() != 1) { + playEntries.add(song); + } + } + playSongs(playEntries, shuffle, append, startEntry); + + return null; + } + }.execute(); + } private void playMusicDirectory(final String dirId, final boolean shuffle, final boolean append, final boolean playFromBookmark) { new SilentServiceTask<Void>(downloadService) { @Override @@ -409,6 +433,19 @@ public class RemoteControlClientLP extends RemoteControlClientBase { private void playSongs(List<Entry> entries, boolean shuffle, boolean append) { playSongs(entries, shuffle, append, false); } + private void playSongs(List<Entry> entries, boolean shuffle, boolean append, Entry startEntry) { + if(!append) { + downloadService.clear(); + } + + int startIndex = entries.indexOf(startEntry); + int startPosition = 0; + if(startEntry.getBookmark() != null) { + Bookmark bookmark = startEntry.getBookmark(); + startPosition = bookmark.getPosition(); + } + downloadService.download(entries, false, true, !append, shuffle, startIndex, startPosition); + } private void playSongs(List<Entry> entries, boolean shuffle, boolean append, boolean resumeFromBookmark) { if(!append) { downloadService.clear(); @@ -429,7 +466,7 @@ public class RemoteControlClientLP extends RemoteControlClientBase { } } - downloadService.download(entries, false, !append, false, shuffle, startIndex, startPosition); + downloadService.download(entries, false, true, !append, shuffle, startIndex, startPosition); } private void noResults() { @@ -564,13 +601,13 @@ public class RemoteControlClientLP extends RemoteControlClientBase { playSong(entry, true); } - // Currently only happens when playing bookmarks so we should be looking up parent + // Enqueue an entire directory when selecting a bookmark or a song String childId = extras.getString(Constants.INTENT_EXTRA_NAME_CHILD_ID, null); if(childId != null) { if(Util.isTagBrowsing(downloadService) && !Util.isOffline(downloadService)) { - playMusicDirectory(entry.getAlbumId(), shuffle, playLast, true); + playMusicDirectory(entry.getAlbumId(), shuffle, playLast, entry); } else { - playMusicDirectory(entry.getParent(), shuffle, playLast, true); + playMusicDirectory(entry.getParent(), shuffle, playLast, entry); } } } diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index c43f3aea..5772e580 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -168,7 +168,7 @@ <string name="download.empty">Wiedergabeliste ist leer</string> <string name="download.shuffle_loading">Wiedergabeliste wird gemischt...</string> <string name="download.playerstate_downloading">Downloade - %s</string> - <string name="download.playerstate_mobile_disabled">Warte auf Wi-Fi für den Download</string> + <string name="download.playerstate_mobile_disabled">Warte auf Wi-Fi oder lokales Netzwerk für den Download</string> <string name="download.playerstate_buffering">Buffere</string> <string name="download.playerstate_playing_shuffle">Playing shuffle</string> <string name="download.menu_show_album">Zeige Album</string> @@ -301,6 +301,8 @@ <string name="settings.max_bitrate_unlimited">Unbegrenzt</string> <string name="settings.wifi_required_title">Nur Wi-Fi streaming</string> <string name="settings.wifi_required_summary">Medien nur streamen, wenn mit Wi-Fi verbunden</string> + <string name="settings.local_network_required_title">Kein streaming mit Roaming-Netzwerken</string> + <string name="settings.local_network_required_summary">Medien nur streamen, wenn mit lokalem Anbieter verbunden</string> <string name="settings.network_timeout_title">Netzwerk Timeout</string> <string name="settings.network_timeout_10000">10 Sekunden</string> <string name="settings.network_timeout_15000">15 Sekunden</string> diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 12102043..3416a471 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -307,8 +307,8 @@ <string name="settings.theme_dark">Sötét</string> <string name="settings.theme_black">Fekete</string> <string name="settings.theme_holo">Holo</string> - <string name="settings.theme_day_night">Nappal/Éjszaka</string> - <string name="settings.theme_day_black_night">Nappal/Fekete éjszaka</string> + <string name="settings.theme_day_night">Nappali/Éjszakai</string> + <string name="settings.theme_day_black_night">Nappali/Éjszakai (fekete)</string> <string name="settings.theme_fullscreen">Teljes képernyős</string> <string name="settings.theme_fullscreen_summary">Teljes képernyős üzemmód (értesítési sáv elrejtése).</string> <string name="settings.track_title">Dalsorszám megjelenítése</string> @@ -321,6 +321,7 @@ <string name="settings.max_bitrate_wifi">Max. audió bitráta - Wi-Fi</string> <string name="settings.max_bitrate_mobile">Max. audió bitráta - Mobilhálózat</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> @@ -488,6 +489,8 @@ <string name="settings.heads_up_notification_summary">Lejátszási értesítések megjelenítése felugró értesítésekként (Android Lollipop+).</string> <string name="settings.casting_cache">Casting közbeni gyorsítótárazás</string> <string name="settings.casting_cache_summary">Az éppen lejátszott dal gyorsítótárazása a tartalomátküldés (Casting) alatt.</string> + <string name="settings.casting.dlna_casting_enabled">DLNA engedélyezve</string> + <string name="settings.casting.dlna_casting_enabled.summary">Ha akkumulátor-merülési probléma lépne fel Android 7.0 alatt, kapcsolja ki a funkciót!</string> <string name="shuffle.title">Dalsorrend keverése</string> <string name="shuffle.startYear">Kezdő év:</string> @@ -613,6 +616,7 @@ <string name="details.title.podcast">Podcast információi</string> <string name="details.title.playlist">Lejátszási lista információi</string> <string name="details.title.artist">Előadó információi</string> + <string name="details.title.internet_radio_station">Internet Radio részletezés</string> <string name="details.podcast">Podcast</string> <string name="details.status">Státusz</string> <string name="details.artist">Előadó</string> @@ -652,6 +656,10 @@ <string name="details.last_played">Utoljára lejátszott</string> <string name="details.expiration">Lejárati idő</string> <string name="details.played_count">Lejátszások száma</string> + <string name="details.stream_url">Stream URL</string> + <string name="details.home_page">Honlap</string> + + <string name="permission.external_storage.failed">A DSub nem tud működni tárhely-írási engedély nélkül!</string> <plurals name="select_album_n_songs"> <item quantity="zero">Nincsenek dalok</item> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b54e4ff2..be1a7bff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -180,7 +180,7 @@ <string name="download.empty">Playlist is empty</string> <string name="download.shuffle_loading">Shuffle list is loading...</string> <string name="download.playerstate_downloading">Downloading - %s</string> - <string name="download.playerstate_mobile_disabled">Waiting for WiFi network to download</string> + <string name="download.playerstate_mobile_disabled">Waiting for WiFi or local (non-roaming) network to download</string> <string name="download.playerstate_buffering">Buffering</string> <string name="download.playerstate_playing_shuffle">Shuffle mode</string> <string name="download.playerstate_playing_artist_radio">Artist radio</string> @@ -346,6 +346,8 @@ <string name="settings.max_bitrate_unlimited">Unlimited</string> <string name="settings.wifi_required_title">Wi-Fi streaming only</string> <string name="settings.wifi_required_summary">Only stream media if connected to Wi-Fi</string> + <string name="settings.local_network_required_title">Don\'t stream when roaming</string> + <string name="settings.local_network_required_summary">Don\'t stream media while roaming</string> <string name="settings.network_timeout_title">Network Timeout</string> <string name="settings.network_timeout_10000">10 seconds</string> <string name="settings.network_timeout_15000">15 seconds</string> @@ -491,6 +493,8 @@ <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="settings.rewind_interval">Rewind Interval</string> + <string name="settings.fastforward_interval">Fast Forward Interval</string> <string name="shuffle.title">Shuffle By</string> <string name="shuffle.startYear">Start Year:</string> @@ -498,6 +502,7 @@ <string name="shuffle.genre">Genre:</string> <string name="shuffle.pick_genre">Pick a genre</string> + <string name="share.create_error">Failed to create share %s</string> <string name="share.expires">Expires: %s</string> <string name="share.expires_never">Never Expires</string> <string name="share.deleted">Deleted share %s</string> diff --git a/app/src/main/res/xml/settings_cache.xml b/app/src/main/res/xml/settings_cache.xml index 248572ca..76926379 100644 --- a/app/src/main/res/xml/settings_cache.xml +++ b/app/src/main/res/xml/settings_cache.xml @@ -40,6 +40,12 @@ android:key="wifiRequiredForDownload" android:defaultValue="false"/> + <CheckBoxPreference + android:title="@string/settings.local_network_required_title" + android:summary="@string/settings.local_network_required_summary" + android:key="localNetworkRequiredForDownload" + android:defaultValue="false"/> + <ListPreference android:title="@string/settings.network_timeout_title" android:key="networkTimeout" @@ -96,4 +102,4 @@ android:key="screenLitOnDownload" android:defaultValue="true"/> </PreferenceCategory> -</PreferenceScreen>
\ No newline at end of file +</PreferenceScreen> diff --git a/app/src/main/res/xml/settings_playback.xml b/app/src/main/res/xml/settings_playback.xml index da31d071..edaf3013 100644 --- a/app/src/main/res/xml/settings_playback.xml +++ b/app/src/main/res/xml/settings_playback.xml @@ -52,6 +52,20 @@ android:defaultValue="all" android:entryValues="@array/songPressActionValues" android:entries="@array/songPressActionNames"/> + + <github.daneren2005.dsub.view.SeekBarPreference + android:title="@string/settings.rewind_interval" + android:key="rewindInterval" + android:defaultValue="10" + android:dialogLayout="@layout/seekbar_preference" + myns:max="60"/> + + <github.daneren2005.dsub.view.SeekBarPreference + android:title="@string/settings.fastforward_interval" + android:key="fastforwardInterval" + android:defaultValue="30" + android:dialogLayout="@layout/seekbar_preference" + myns:max="60"/> </PreferenceCategory> <PreferenceCategory diff --git a/build.gradle b/build.gradle index b3146795..b304f7fc 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.1' + classpath 'com.android.tools.build:gradle:2.3.3' // 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 a58c8fc3..325e6709 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Mar 07 08:58:29 PST 2017 +#Thu Nov 09 08:50:56 PST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip |