diff --git a/.gitignore b/.gitignore
index 4838c7c33..8dc679d0d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,5 @@ proguard_logs/
.gradle/*
/build/
local.properties
-*Thumbs.db
\ No newline at end of file
+*Thumbs.db
+app/google/release
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 78351890a..dafc4fbc6 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -6,11 +6,18 @@ android {
defaultConfig {
applicationId "github.daneren2005.dsub"
minSdkVersion 15
- targetSdkVersion 26
- versionCode 203
- versionName '5.5.0'
+ targetSdkVersion 29
+ versionCode 206
+ versionName '5.5.2'
setProperty("archivesBaseName", "DSub $versionName")
resConfigs "de", "es", "fr", "hu", "nl", "pt-rPT", "ru", "sv"
+ vectorDrawables.useSupportLibrary = true
+ resValue 'string', 'account_type.subsonic', applicationId + ".subsonic"
+ resValue 'string', 'provider.search', applicationId + ".provider.DSubSearchProvider"
+ resValue 'string', 'provider.playlist', applicationId + ".playlists.provider"
+ resValue 'string', 'provider.podcast', applicationId + ".podcasts.provider"
+ resValue 'string', 'provider.starred', applicationId + ".starred.provider"
+ resValue 'string', 'provider.recently_added', applicationId + ".mostrecent.provider"
}
buildTypes {
release {
diff --git a/app/src/google/java/github/daneren2005/dsub/service/ChromeCastController.java b/app/src/google/java/github/daneren2005/dsub/service/ChromeCastController.java
index b2405705d..2bd4cb593 100644
--- a/app/src/google/java/github/daneren2005/dsub/service/ChromeCastController.java
+++ b/app/src/google/java/github/daneren2005/dsub/service/ChromeCastController.java
@@ -49,6 +49,8 @@
import github.daneren2005.serverproxy.ServerProxy;
import github.daneren2005.serverproxy.WebProxy;
+import static github.daneren2005.dsub.util.compat.GoogleCompat.castApplicationId;
+
/**
* Created by owner on 2/9/14.
*/
@@ -421,14 +423,14 @@ public void onConnectionSuspended(int cause) {
void launchApplication() {
try {
- Cast.CastApi.launchApplication(apiClient, EnvironmentVariables.CAST_APPLICATION_ID, false).setResultCallback(resultCallback);
+ Cast.CastApi.launchApplication(apiClient, castApplicationId(), false).setResultCallback(resultCallback);
} catch (Exception e) {
Log.e(TAG, "Failed to launch application", e);
}
}
void reconnectApplication() {
try {
- Cast.CastApi.joinApplication(apiClient, EnvironmentVariables.CAST_APPLICATION_ID, sessionId).setResultCallback(resultCallback);
+ Cast.CastApi.joinApplication(apiClient, castApplicationId(), sessionId).setResultCallback(resultCallback);
} catch (Exception e) {
Log.e(TAG, "Failed to reconnect application", e);
}
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
index 63992b0f9..f8bd4ee77 100644
--- a/app/src/google/java/github/daneren2005/dsub/util/compat/GoogleCompat.java
+++ b/app/src/google/java/github/daneren2005/dsub/util/compat/GoogleCompat.java
@@ -9,6 +9,7 @@
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.security.ProviderInstaller;
+import static com.google.android.gms.cast.CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID;
import github.daneren2005.dsub.service.ChromeCastController;
import github.daneren2005.dsub.service.DownloadService;
@@ -32,10 +33,17 @@ public static void installProvider(Context context) throws Exception{
ProviderInstaller.installIfNeeded(context);
}
+ public static String castApplicationId() {
+ if (EnvironmentVariables.CAST_APPLICATION_ID != null) {
+ return EnvironmentVariables.CAST_APPLICATION_ID;
+ } else {
+ return DEFAULT_MEDIA_RECEIVER_APPLICATION_ID;
+ }
+ }
+
public static boolean castAvailable() {
- if (EnvironmentVariables.CAST_APPLICATION_ID == null) {
- Log.w(TAG, "CAST_APPLICATION_ID not provided");
- return false;
+ if (castApplicationId() == DEFAULT_MEDIA_RECEIVER_APPLICATION_ID) {
+ Log.i(TAG, "Using DEFAULT_MEDIA_RECEIVER_APPLICATION_ID for casting");
}
try {
Class.forName("com.google.android.gms.cast.CastDevice");
@@ -56,6 +64,6 @@ public static RemoteController getController(DownloadService downloadService, Me
}
public static String getCastControlCategory() {
- return CastMediaControlIntent.categoryForCast(EnvironmentVariables.CAST_APPLICATION_ID);
+ return CastMediaControlIntent.categoryForCast(castApplicationId());
}
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 527565343..2572bbb53 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -16,14 +16,14 @@
-
-
+
+
@@ -39,7 +39,8 @@
android:backupAgent="github.daneren2005.dsub.util.SettingsBackupAgent"
android:icon="@drawable/launch"
android:theme="@style/Theme.DSub.Light"
- android:largeHeap="true">
+ android:largeHeap="true"
+ android:usesCleartextTraffic="true">
@@ -89,10 +90,11 @@
-
+
-
@@ -214,24 +216,24 @@
+ android:authorities="@string/provider.search"/>
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 5948064d1..d475be7b5 100644
--- a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java
+++ b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java
@@ -18,6 +18,7 @@
*/
package github.daneren2005.dsub.activity;
+import android.Manifest;
import android.app.UiModeManager;
import android.content.Context;
import android.content.DialogInterface;
@@ -184,6 +185,17 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin
if (ContextCompat.checkSelfPermission(this, permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{ permission.WRITE_EXTERNAL_STORAGE }, PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
}
+
+ SharedPreferences prefs = Util.getPreferences(this);
+ int instance = prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
+ String expectedSSID = prefs.getString(Constants.PREFERENCES_KEY_SERVER_LOCAL_NETWORK_SSID + instance, "");
+ if(!expectedSSID.isEmpty()) {
+ String currentSSID = Util.getSSID(this);
+
+ if(currentSSID == "" && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+ ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, SubsonicActivity.PERMISSIONS_REQUEST_LOCATION);
+ }
+ }
}
@Override
@@ -198,6 +210,14 @@ public void onRequestPermissionsResult(int requestCode, String permissions[], in
finish();
}
}
+ case PERMISSIONS_REQUEST_LOCATION: {
+ // If request is cancelled, the result arrays are empty.
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+
+ } else {
+ Util.toast(this, R.string.permission_location_failed);
+ }
+ }
}
}
@@ -1248,7 +1268,7 @@ public void uncaughtException(Thread thread, Throwable throwable) {
PrintWriter printWriter = null;
try {
- PackageInfo packageInfo = context.getPackageManager().getPackageInfo("github.daneren2005.dsub", 0);
+ PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
file = new File(Environment.getExternalStorageDirectory(), "dsub-stacktrace.txt");
printWriter = new PrintWriter(file);
printWriter.println("Android API level: " + Build.VERSION.SDK);
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 674ce98a4..c5463f383 100644
--- a/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java
+++ b/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java
@@ -214,7 +214,7 @@ else if(Constants.PREFERENCES_KEY_SYNC_MOST_RECENT.equals(key)) {
if(downloadService != null) {
MediaRouteManager mediaRouter = downloadService.getMediaRouter();
- Boolean enabled = sharedPreferences.getBoolean(key, true);
+ Boolean enabled = sharedPreferences.getBoolean(key, false);
if (enabled) {
mediaRouter.addDLNAProvider();
} else {
@@ -528,6 +528,10 @@ protected void onAddEditTextToDialogView(View dialogView, final EditText editTex
super.onAddEditTextToDialogView(dialogView, editText);
ViewGroup root = (ViewGroup) ((ViewGroup) dialogView).getChildAt(0);
+ if(internalSSID == "" && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+ ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, SubsonicActivity.PERMISSIONS_REQUEST_LOCATION);
+ }
+
Button defaultButton = new Button(getContext());
defaultButton.setText(internalSSIDDisplay);
defaultButton.setOnClickListener(new View.OnClickListener() {
@@ -575,6 +579,12 @@ public void onClick(View v) {
serverSyncPreference.setSummary(R.string.settings_server_sync_summary);
serverSyncPreference.setTitle(R.string.settings_server_sync);
+ final CheckBoxPreference serverAuthHeaderPreference = new CheckBoxPreference(context);
+ serverAuthHeaderPreference.setKey(Constants.PREFERENCES_KEY_SERVER_AUTHHEADER + instance);
+ serverAuthHeaderPreference.setChecked(Util.isAuthHeaderEnabled(context, instance));
+ serverAuthHeaderPreference.setSummary(R.string.settings_server_authheaders_summary);
+ serverAuthHeaderPreference.setTitle(R.string.settings_server_authheaders);
+
final Preference serverOpenBrowser = new Preference(context);
serverOpenBrowser.setKey(Constants.PREFERENCES_KEY_OPEN_BROWSER);
serverOpenBrowser.setPersistent(false);
@@ -649,6 +659,7 @@ public boolean onPreferenceClick(Preference preference) {
screen.addPreference(serverPasswordPreference);
screen.addPreference(serverTagPreference);
screen.addPreference(serverSyncPreference);
+ screen.addPreference(serverAuthHeaderPreference);
screen.addPreference(serverTestConnectionPreference);
screen.addPreference(serverOpenBrowser);
screen.addPreference(serverRemoveServerPreference);
@@ -803,7 +814,7 @@ public boolean onPreferenceChange(Preference preference, Object value) {
try {
String url = (String) value;
new URL(url);
- if (url.contains(" ") || url.contains("@")) {
+ if (url.contains(" ")) {
throw new Exception();
}
} catch (Exception x) {
@@ -824,7 +835,7 @@ public boolean onPreferenceChange(Preference preference, Object value) {
}
new URL(url);
- if (url.contains(" ") || url.contains("@")) {
+ if (url.contains(" ")) {
throw new Exception();
}
} catch (Exception x) {
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 e90969007..67a0f36fe 100644
--- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java
+++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java
@@ -310,7 +310,9 @@ public boolean onError(MediaPlayer mediaPlayer, int what, int more) {
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
lifecycleSupport.onStart(intent);
- if(Build.VERSION.SDK_INT >= 26 && !this.isForeground()) {
+
+ String action = intent.getAction();
+ if(Build.VERSION.SDK_INT >= 26 && !this.isForeground() && !"KEYCODE_MEDIA_START".equals(action)) {
Notifications.shutGoogleUpNotification(this);
}
return START_NOT_STICKY;
@@ -1081,7 +1083,7 @@ public synchronized List getDownloads() {
public synchronized List getRecentDownloads() {
int from = Math.max(currentPlayingIndex - 10, 0);
- int songsToKeep = Math.max(Util.getPreloadCount(this), 20);
+ int songsToKeep = Math.min(Math.max(Util.getPreloadCount(this), 20), downloadList.size());
int to = Math.min(currentPlayingIndex + songsToKeep, Math.max(downloadList.size() - 1, 0));
List temp = downloadList.subList(from, to);
temp.addAll(backgroundDownloadList);
@@ -1519,12 +1521,14 @@ public synchronized void setPlayerState(final PlayerState playerState) {
Util.requestAudioFocus(this, audioManager);
}
+ SharedPreferences prefs = Util.getPreferences(this);
+ boolean usingMediaStyleNotification = prefs.getBoolean(Constants.PREFERENCES_KEY_MEDIA_STYLE_NOTIFICATION, true) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
+
if (show) {
- Notifications.showPlayingNotification(this, this, handler, currentPlaying.getSong());
+ Notifications.showPlayingNotification(this, this, handler, currentPlaying.getSong(), usingMediaStyleNotification);
} else if (pause) {
- SharedPreferences prefs = Util.getPreferences(this);
- if(prefs.getBoolean(Constants.PREFERENCES_KEY_PERSISTENT_NOTIFICATION, false)) {
- Notifications.showPlayingNotification(this, this, handler, currentPlaying.getSong());
+ if (prefs.getBoolean(Constants.PREFERENCES_KEY_PERSISTENT_NOTIFICATION, false)) {
+ Notifications.showPlayingNotification(this, this, handler, currentPlaying.getSong(), usingMediaStyleNotification);
} else {
Notifications.hidePlayingNotification(this, this, handler);
}
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 100224e8c..8fdafc111 100644
--- a/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java
+++ b/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java
@@ -1911,11 +1911,16 @@ private HttpURLConnection getConnectionDirect(Context context, String url, Map= 500) {
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 017ba2f37..0ce58d738 100644
--- a/app/src/main/java/github/daneren2005/dsub/util/Constants.java
+++ b/app/src/main/java/github/daneren2005/dsub/util/Constants.java
@@ -18,6 +18,8 @@
*/
package github.daneren2005.dsub.util;
+import github.daneren2005.dsub.BuildConfig;
+
/**
* @author Sindre Mehus
* @version $Id$
@@ -85,6 +87,7 @@ public final class Constants {
public static final String PREFERENCES_KEY_MUSIC_FOLDER_ID = "musicFolderId";
public static final String PREFERENCES_KEY_USERNAME = "username";
public static final String PREFERENCES_KEY_PASSWORD = "password";
+ public static final String PREFERENCES_KEY_SERVER_AUTHHEADER = "authHeader";
public static final String PREFERENCES_KEY_ENCRYPTED_PASSWORD = "encryptedPassword";
public static final String PREFERENCES_KEY_INSTALL_TIME = "installTime";
public static final String PREFERENCES_KEY_THEME = "theme";
@@ -117,6 +120,7 @@ public final class Constants {
public static final String PREFERENCES_EQUALIZER_ON = "equalizerOn";
public static final String PREFERENCES_EQUALIZER_SETTINGS = "equalizerSettings";
public static final String PREFERENCES_KEY_PERSISTENT_NOTIFICATION = "persistentNotification";
+ public static final String PREFERENCES_KEY_MEDIA_STYLE_NOTIFICATION = "mediaStyleNotification";
public static final String PREFERENCES_KEY_GAPLESS_PLAYBACK = "gaplessPlayback";
public static final String PREFERENCES_KEY_REMOVE_PLAYED = "removePlayed";
public static final String PREFERENCES_KEY_KEEP_PLAYED_CNT = "keepPlayedCount";
@@ -212,17 +216,17 @@ public final class Constants {
public static final String FRAGMENT_POSITION = "fragmentPosition";
// Name of the preferences file.
- public static final String PREFERENCES_FILE_NAME = "github.daneren2005.dsub_preferences";
- public static final String OFFLINE_SYNC_NAME = "github.daneren2005.dsub.offline";
+ public static final String PREFERENCES_FILE_NAME = BuildConfig.APPLICATION_ID + "_preferences";
+ public static final String OFFLINE_SYNC_NAME = BuildConfig.APPLICATION_ID + ".offline";
public static final String OFFLINE_SYNC_DEFAULT = "syncDefaults";
// Account prefs
public static final String SYNC_ACCOUNT_NAME = "Subsonic Account";
- public static final String SYNC_ACCOUNT_TYPE = "subsonic.org";
- public static final String SYNC_ACCOUNT_PLAYLIST_AUTHORITY = "github.daneren2005.dsub.playlists.provider";
- public static final String SYNC_ACCOUNT_PODCAST_AUTHORITY = "github.daneren2005.dsub.podcasts.provider";
- public static final String SYNC_ACCOUNT_STARRED_AUTHORITY = "github.daneren2005.dsub.starred.provider";
- public static final String SYNC_ACCOUNT_MOST_RECENT_AUTHORITY = "github.daneren2005.dsub.mostrecent.provider";
+ public static final String SYNC_ACCOUNT_TYPE = BuildConfig.APPLICATION_ID + ".subsonic";
+ public static final String SYNC_ACCOUNT_PLAYLIST_AUTHORITY = BuildConfig.APPLICATION_ID + ".playlists.provider";
+ public static final String SYNC_ACCOUNT_PODCAST_AUTHORITY = BuildConfig.APPLICATION_ID + ".podcasts.provider";
+ public static final String SYNC_ACCOUNT_STARRED_AUTHORITY = BuildConfig.APPLICATION_ID + ".starred.provider";
+ public static final String SYNC_ACCOUNT_MOST_RECENT_AUTHORITY = BuildConfig.APPLICATION_ID + ".mostrecent.provider";
public static final String TASKER_EXTRA_BUNDLE = "com.twofortyfouram.locale.intent.extra.BUNDLE";
diff --git a/app/src/main/java/github/daneren2005/dsub/util/DownloadFileItemHelperCallback.java b/app/src/main/java/github/daneren2005/dsub/util/DownloadFileItemHelperCallback.java
index e1e2dc63c..0e80295a2 100644
--- a/app/src/main/java/github/daneren2005/dsub/util/DownloadFileItemHelperCallback.java
+++ b/app/src/main/java/github/daneren2005/dsub/util/DownloadFileItemHelperCallback.java
@@ -4,9 +4,9 @@
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
-import org.eclipse.jetty.util.ArrayQueue;
import java.util.Queue;
+import java.util.ArrayDeque;
import github.daneren2005.dsub.adapter.SectionAdapter;
import github.daneren2005.dsub.fragments.SubsonicFragment;
@@ -22,7 +22,7 @@ public class DownloadFileItemHelperCallback extends ItemTouchHelper.SimpleCallba
private boolean mainList;
private BackgroundTask pendingTask = null;
- private Queue pendingOperations = new ArrayQueue();
+ private Queue pendingOperations = new ArrayDeque();
public DownloadFileItemHelperCallback(SubsonicFragment fragment, boolean mainList) {
super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
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 e19cc1567..00e02dab1 100644
--- a/app/src/main/java/github/daneren2005/dsub/util/MediaRouteManager.java
+++ b/app/src/main/java/github/daneren2005/dsub/util/MediaRouteManager.java
@@ -141,7 +141,7 @@ private void addProviders() {
addOnlineProviders();
}
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && Util.getPreferences(downloadService).getBoolean(Constants.PREFERENCES_KEY_DLNA_CASTING_ENABLED, true)) {
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && Util.getPreferences(downloadService).getBoolean(Constants.PREFERENCES_KEY_DLNA_CASTING_ENABLED, false)) {
addDLNAProvider();
}
}
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 a8f7add0a..88bc8138f 100644
--- a/app/src/main/java/github/daneren2005/dsub/util/Notifications.java
+++ b/app/src/main/java/github/daneren2005/dsub/util/Notifications.java
@@ -43,6 +43,7 @@
import github.daneren2005.dsub.provider.DSubWidgetProvider;
import github.daneren2005.dsub.service.DownloadFile;
import github.daneren2005.dsub.service.DownloadService;
+import github.daneren2005.dsub.util.compat.RemoteControlClientLP;
import github.daneren2005.dsub.view.UpdateView;
public final class Notifications {
@@ -65,43 +66,110 @@ public final class Notifications {
private final static Pair NOTIFICATION_TEXT_COLORS = new Pair();
- public static void showPlayingNotification(final Context context, final DownloadService downloadService, final Handler handler, MusicDirectory.Entry song) {
+ public static void showPlayingNotification(final Context context, final DownloadService downloadService, final Handler handler, MusicDirectory.Entry song, boolean usingMediaStyleNotification) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
getPlayingNotificationChannel(context);
}
- // Set the icon, scrolling text and timestamp
- final Notification notification = new NotificationCompat.Builder(context)
- .setSmallIcon(R.drawable.stat_notify_playing)
- .setTicker(song.getTitle())
- .setWhen(System.currentTimeMillis())
- .setChannelId("now-playing-channel")
- .build();
+ final Notification notification;
final boolean playing = downloadService.getPlayerState() == PlayerState.STARTED;
- if(playing) {
- notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
- }
+
boolean remote = downloadService.isRemoteEnabled();
boolean isSingle = downloadService.isCurrentPlayingSingle();
boolean shouldFastForward = downloadService.shouldFastForward();
- if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.JELLY_BEAN){
- RemoteViews expandedContentView = new RemoteViews(context.getPackageName(), R.layout.notification_expanded);
- setupViews(expandedContentView ,context, song, true, playing, remote, isSingle, shouldFastForward);
- notification.bigContentView = expandedContentView;
- notification.priority = Notification.PRIORITY_HIGH;
- }
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- notification.visibility = Notification.VISIBILITY_PUBLIC;
- if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_HEADS_UP_NOTIFICATION, false) && !UpdateView.hasActiveActivity()) {
- notification.vibrate = new long[0];
+ if (usingMediaStyleNotification) {
+ RemoteControlClientLP remoteControlClient = (RemoteControlClientLP) downloadService.getRemoteControlClient();
+
+ android.support.v4.media.app.NotificationCompat.MediaStyle mediaStyle = new android.support.v4.media.app.NotificationCompat.MediaStyle()
+ .setMediaSession(remoteControlClient.getMediaSession().getSessionToken());
+
+ if (isSingle) {
+ mediaStyle.setShowActionsInCompactView(1);
+ } else {
+ mediaStyle.setShowActionsInCompactView(0, 2, 4);
}
- }
- RemoteViews smallContentView = new RemoteViews(context.getPackageName(), R.layout.notification);
- setupViews(smallContentView, context, song, false, playing, remote, isSingle, shouldFastForward);
- notification.contentView = smallContentView;
+ String title = song.getTitle();
+ String artist = song.getArtist();
+ String album = song.getAlbum();
+
+ NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, "now-playing-channel")
+ .setSmallIcon(R.drawable.stat_notify_playing)
+ .setContentTitle(title)
+ .setContentText(artist + " - " + album)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setStyle(mediaStyle);
+
+ // Set the album art.
+ try {
+ ImageLoader imageLoader = SubsonicActivity.getStaticImageLoader(context);
+ if(imageLoader != null) {
+ Bitmap bitmap = imageLoader.getCachedImage(context, song, false);
+
+ if(bitmap != null) {
+ notificationBuilder.setLargeIcon(bitmap);
+ }
+ }
+ } catch (Exception x) {
+ Log.w(TAG, "Failed to get notification cover art", x);
+ }
+
+ PendingIntent prevIntent = null;
+ PendingIntent nextIntent = null;
+ if (!isSingle) {
+ prevIntent = getMediaPendingIntent("KEYCODE_MEDIA_PREVIOUS", context);
+ nextIntent = getMediaPendingIntent("KEYCODE_MEDIA_NEXT", context);
+ }
+
+ PendingIntent rewindIntent = getMediaPendingIntent("KEYCODE_MEDIA_REWIND", context);
+ PendingIntent playIntent = getMediaPendingIntent(playing ? "KEYCODE_MEDIA_PLAY_PAUSE" : "KEYCODE_MEDIA_START", context);
+ PendingIntent forwardIntent = getMediaPendingIntent("KEYCODE_MEDIA_FAST_FORWARD", context);
+
+ if (!isSingle) {
+ notificationBuilder.addAction(R.drawable.ic_baseline_skip_previous_32, "Previous", prevIntent);
+ }
+
+ notificationBuilder.addAction(R.drawable.ic_baseline_fast_rewind_32, "Rewind", rewindIntent);
+ notificationBuilder.addAction(playing ? R.drawable.ic_baseline_pause_48 : R.drawable.ic_baseline_play_arrow_48, playing ? "Pause" : "Play", playIntent);
+ notificationBuilder.addAction(R.drawable.ic_baseline_fast_forward_32, "Forward", forwardIntent);
+
+ if (!isSingle) {
+ notificationBuilder.addAction(R.drawable.ic_baseline_skip_next_32, "Next", nextIntent);
+ }
+
+ notification = notificationBuilder.build();
+ } else {
+ // Set the icon, scrolling text and timestamp
+ notification = new NotificationCompat.Builder(context, "now-playing-channel")
+ .setSmallIcon(R.drawable.stat_notify_playing)
+ .setTicker(song.getTitle())
+ .setWhen(System.currentTimeMillis())
+ .build();
+
+ if(playing) {
+ notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
+ }
+
+ if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.JELLY_BEAN){
+ RemoteViews expandedContentView = new RemoteViews(context.getPackageName(), R.layout.notification_expanded);
+ setupViews(expandedContentView, context, song, true, playing, remote, isSingle, shouldFastForward);
+ notification.bigContentView = expandedContentView;
+ notification.priority = Notification.PRIORITY_HIGH;
+ }
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ notification.visibility = Notification.VISIBILITY_PUBLIC;
+
+ if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_HEADS_UP_NOTIFICATION, false) && !UpdateView.hasActiveActivity()) {
+ notification.vibrate = new long[0];
+ }
+ }
+
+ RemoteViews smallContentView = new RemoteViews(context.getPackageName(), R.layout.notification);
+ setupViews(smallContentView, context, song, false, playing, remote, isSingle, shouldFastForward);
+ notification.contentView = smallContentView;
+ }
Intent notificationIntent = new Intent(context, SubsonicFragmentActivity.class);
notificationIntent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true);
@@ -154,10 +222,52 @@ public void run() {
DSubWidgetProvider.notifyInstances(context, downloadService, playing);
}
+ private static PendingIntent getMediaPendingIntent(String action, Context context) {
+ Intent intent = new Intent(action);
+ intent.setComponent(new ComponentName(context, DownloadService.class));
+
+ int keyCode = 0;
+ switch (action) {
+ case "KEYCODE_MEDIA_PREVIOUS":
+ keyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS;
+ break;
+
+ case "KEYCODE_MEDIA_REWIND":
+ keyCode = KeyEvent.KEYCODE_MEDIA_REWIND;
+ break;
+
+ case "KEYCODE_MEDIA_PLAY_PAUSE":
+ keyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
+ break;
+
+ case "KEYCODE_MEDIA_START":
+ keyCode = KeyEvent.KEYCODE_MEDIA_PLAY;
+ break;
+
+ case "KEYCODE_MEDIA_NEXT":
+ keyCode = KeyEvent.KEYCODE_MEDIA_NEXT;
+ break;
+
+ case "KEYCODE_MEDIA_FAST_FORWARD":
+ keyCode = KeyEvent.KEYCODE_MEDIA_FAST_FORWARD;
+ break;
+
+ case "KEYCODE_MEDIA_STOP":
+ keyCode = KeyEvent.KEYCODE_MEDIA_STOP;
+ break;
+ }
+
+ if (keyCode != 0) {
+ intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, keyCode));
+ }
+
+ return PendingIntent.getService(context, 0, intent, 0);
+ }
+
private static void setupViews(RemoteViews rv, Context context, MusicDirectory.Entry song, boolean expanded, boolean playing, boolean remote, boolean isSingleFile, boolean shouldFastForward) {
// Use the same text for the ticker and the expanded notification
String title = song.getTitle();
- String arist = song.getArtist();
+ String artist = song.getArtist();
String album = song.getAlbum();
// Set the album art.
@@ -181,7 +291,7 @@ private static void setupViews(RemoteViews rv, Context context, MusicDirectory.E
// set the text for the notifications
rv.setTextViewText(R.id.notification_title, title);
- rv.setTextViewText(R.id.notification_artist, arist);
+ rv.setTextViewText(R.id.notification_artist, artist);
rv.setTextViewText(R.id.notification_album, album);
boolean persistent = Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_PERSISTENT_NOTIFICATION, false);
@@ -276,53 +386,32 @@ private static void setupViews(RemoteViews rv, Context context, MusicDirectory.E
PendingIntent pendingIntent;
if(previous > 0) {
- Intent prevIntent = new Intent("KEYCODE_MEDIA_PREVIOUS");
- prevIntent.setComponent(new ComponentName(context, DownloadService.class));
- prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS));
- pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0);
+ pendingIntent = getMediaPendingIntent("KEYCODE_MEDIA_PREVIOUS", context);
rv.setOnClickPendingIntent(previous, pendingIntent);
}
if(rewind > 0) {
- Intent rewindIntent = new Intent("KEYCODE_MEDIA_REWIND");
- rewindIntent.setComponent(new ComponentName(context, DownloadService.class));
- rewindIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_REWIND));
- pendingIntent = PendingIntent.getService(context, 0, rewindIntent, 0);
+ pendingIntent = getMediaPendingIntent("KEYCODE_MEDIA_REWIND", context);
rv.setOnClickPendingIntent(rewind, pendingIntent);
}
if(pause > 0) {
if(playing) {
- Intent pauseIntent = new Intent("KEYCODE_MEDIA_PLAY_PAUSE");
- pauseIntent.setComponent(new ComponentName(context, DownloadService.class));
- pauseIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
- pendingIntent = PendingIntent.getService(context, 0, pauseIntent, 0);
+ pendingIntent = getMediaPendingIntent("KEYCODE_MEDIA_PLAY_PAUSE", context);
rv.setOnClickPendingIntent(pause, pendingIntent);
} else {
- Intent prevIntent = new Intent("KEYCODE_MEDIA_START");
- prevIntent.setComponent(new ComponentName(context, DownloadService.class));
- prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY));
- pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0);
+ pendingIntent = getMediaPendingIntent("KEYCODE_MEDIA_START", context);
rv.setOnClickPendingIntent(pause, pendingIntent);
}
}
if(next > 0) {
- Intent nextIntent = new Intent("KEYCODE_MEDIA_NEXT");
- nextIntent.setComponent(new ComponentName(context, DownloadService.class));
- nextIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT));
- pendingIntent = PendingIntent.getService(context, 0, nextIntent, 0);
+ pendingIntent = getMediaPendingIntent("KEYCODE_MEDIA_NEXT", context);
rv.setOnClickPendingIntent(next, pendingIntent);
}
if(fastForward > 0) {
- Intent fastForwardIntent = new Intent("KEYCODE_MEDIA_FAST_FORWARD");
- fastForwardIntent.setComponent(new ComponentName(context, DownloadService.class));
- fastForwardIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD));
- pendingIntent = PendingIntent.getService(context, 0, fastForwardIntent, 0);
+ pendingIntent = getMediaPendingIntent("KEYCODE_MEDIA_FAST_FORWARD", context);
rv.setOnClickPendingIntent(fastForward, pendingIntent);
}
if(close > 0) {
- Intent prevIntent = new Intent("KEYCODE_MEDIA_STOP");
- prevIntent.setComponent(new ComponentName(context, DownloadService.class));
- prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_STOP));
- pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0);
+ pendingIntent = getMediaPendingIntent("KEYCODE_MEDIA_STOP", context);
rv.setOnClickPendingIntent(close, pendingIntent);
}
}
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 b58a81e4d..872e95612 100644
--- a/app/src/main/java/github/daneren2005/dsub/util/Util.java
+++ b/app/src/main/java/github/daneren2005/dsub/util/Util.java
@@ -460,6 +460,11 @@ public static boolean isSyncEnabled(Context context, int instance) {
return prefs.getBoolean(Constants.PREFERENCES_KEY_SERVER_SYNC + instance, true);
}
+ public static boolean isAuthHeaderEnabled(Context context, int instance) {
+ SharedPreferences prefs = getPreferences(context);
+ return prefs.getBoolean(Constants.PREFERENCES_KEY_SERVER_AUTHHEADER + instance, true);
+ }
+
public static String getParentFromEntry(Context context, MusicDirectory.Entry entry) {
if(Util.isTagBrowsing(context)) {
if(!entry.isDirectory()) {
diff --git a/app/src/main/res/drawable/ic_baseline_fast_forward_32.xml b/app/src/main/res/drawable/ic_baseline_fast_forward_32.xml
new file mode 100644
index 000000000..2ed771186
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_fast_forward_32.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_fast_rewind_32.xml b/app/src/main/res/drawable/ic_baseline_fast_rewind_32.xml
new file mode 100644
index 000000000..d25463685
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_fast_rewind_32.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_pause_48.xml b/app/src/main/res/drawable/ic_baseline_pause_48.xml
new file mode 100644
index 000000000..8d5e417e9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_pause_48.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_pause_64.xml b/app/src/main/res/drawable/ic_baseline_pause_64.xml
new file mode 100644
index 000000000..8de9e59e9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_pause_64.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_play_arrow_48.xml b/app/src/main/res/drawable/ic_baseline_play_arrow_48.xml
new file mode 100644
index 000000000..c775d2c09
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_play_arrow_48.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_play_arrow_64.xml b/app/src/main/res/drawable/ic_baseline_play_arrow_64.xml
new file mode 100644
index 000000000..f42648b89
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_play_arrow_64.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_skip_next_32.xml b/app/src/main/res/drawable/ic_baseline_skip_next_32.xml
new file mode 100644
index 000000000..23a02ee02
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_skip_next_32.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_skip_previous_32.xml b/app/src/main/res/drawable/ic_baseline_skip_previous_32.xml
new file mode 100644
index 000000000..e01d66665
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_skip_previous_32.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/layout/abstract_activity.xml b/app/src/main/res/layout/abstract_activity.xml
index 56db14393..7ca9b9365 100644
--- a/app/src/main/res/layout/abstract_activity.xml
+++ b/app/src/main/res/layout/abstract_activity.xml
@@ -4,8 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fitsSystemWindows="true">
+ android:layout_height="match_parent">
Tags de pistas
Abrir en pestaña
Abrir directamente a esta pestaña
+ Notificaciones nativas multimedia de Android (5.0+)
+ Mostrar las notificaciones de reproducción como notificaciones de estilo multimedia nativas (solo en Android Lollipop y superior)
Expira: %s
Nunca expira
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 5c576865e..50909e1e1 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -8,7 +8,7 @@
Jouer
Jouer au hasard
Suivant
- Précédent
+ Jouer en dernier
Mettre en cache
Mettre en cache permanent
Supprimer
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index be1a7bfff..87ebbe071 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -284,6 +284,8 @@
Open in browser
Whether or not syncing is enabled for this server
Sync Enabled
+ If this is enabled the request headers will include Authorization: Basic
+ Authorization Basic headers
Music cache
Songs to preload (Wifi)
Songs to preload (Mobile)
@@ -495,6 +497,8 @@
If you are having battery drain problems on Android 7.0 try turning this off
Rewind Interval
Fast Forward Interval
+ Native Android media notification (5.0+)
+ Show playing notifications as native media style notifications (Android Lollipop+ only)
Shuffle By
Start Year:
@@ -665,6 +669,7 @@
Home Page
DSub cannot function without the ability to write to storage
+ This apps uses location data to get the WIFI SSID to match against your local network settings. To get rid of this message, change the local network SSID to blank.
- No songs
diff --git a/app/src/main/res/xml/authenticator.xml b/app/src/main/res/xml/authenticator.xml
index 3055240be..23e4621ad 100644
--- a/app/src/main/res/xml/authenticator.xml
+++ b/app/src/main/res/xml/authenticator.xml
@@ -1,7 +1,7 @@
\ No newline at end of file
diff --git a/app/src/main/res/xml/changelog.xml b/app/src/main/res/xml/changelog.xml
index e8654e6f5..4be2ae360 100644
--- a/app/src/main/res/xml/changelog.xml
+++ b/app/src/main/res/xml/changelog.xml
@@ -1,5 +1,17 @@
+
+ Update to Android 10 target level
+ Request location permissions if needed for local network check
+ Show new notification on secure lockscreen
+ Fix fullscreen not being fullscreen after upgrading to Android 9 target level
+
+
+ Update to Android 9 target level
+ Optionally use system default media style notification (on by default - thanks avm99963)
+ Fix not being able to use basic server auth with @ in network connection string via server setting (thanks popeen)
+ Turned DLNA casting off by default since it causes battery drain I have not been able to fix
+
Fix saving files being broken on Android 11+
Upgrade to Android 8 target level again
diff --git a/app/src/main/res/xml/mostrecent_syncadapter.xml b/app/src/main/res/xml/mostrecent_syncadapter.xml
index 0195edebb..a01725015 100644
--- a/app/src/main/res/xml/mostrecent_syncadapter.xml
+++ b/app/src/main/res/xml/mostrecent_syncadapter.xml
@@ -1,7 +1,7 @@
\ No newline at end of file
diff --git a/app/src/main/res/xml/settings_cast.xml b/app/src/main/res/xml/settings_cast.xml
index 78bafdd4d..2170d7ed8 100644
--- a/app/src/main/res/xml/settings_cast.xml
+++ b/app/src/main/res/xml/settings_cast.xml
@@ -33,9 +33,9 @@
android:title="@string/settings.other_title">
+ android:summary="@string/settings.casting.dlna_casting_enabled.summary"
+ android:title="@string/settings.casting.dlna_casting_enabled" />
\ No newline at end of file
diff --git a/app/src/main/res/xml/settings_playback.xml b/app/src/main/res/xml/settings_playback.xml
index fb3501f0c..fd6a7dda5 100644
--- a/app/src/main/res/xml/settings_playback.xml
+++ b/app/src/main/res/xml/settings_playback.xml
@@ -46,6 +46,12 @@
android:key="headsUpNotification"
android:defaultValue="false"/>
+
+