From 7f55a43e3d59015d03277fa77cf626c68e3bbded Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Fri, 31 Aug 2018 17:05:15 -0700 Subject: Fixes #879: Add support for Android O's new requestAudioFocus API --- .../java/github/daneren2005/dsub/util/Util.java | 93 ++++++++++++++-------- 1 file changed, 61 insertions(+), 32 deletions(-) (limited to 'app/src/main/java/github') 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 93004a48..5699cdf9 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Util.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Util.java @@ -19,6 +19,9 @@ package github.daneren2005.dsub.util; import android.annotation.TargetApi; import android.app.Activity; +import android.media.AudioAttributes; +import android.media.AudioFocusRequest; +import android.support.annotation.RequiresApi; import android.support.annotation.StringRes; import android.support.v7.app.AlertDialog; import android.content.ClipboardManager; @@ -113,6 +116,7 @@ public final class Util { public static final String AVRCP_METADATA_CHANGED = "com.android.music.metachanged"; private static OnAudioFocusChangeListener focusListener; + private static AudioFocusRequest audioFocusRequest; private static boolean pauseFocus = false; private static boolean lowerFocus = false; @@ -1324,43 +1328,68 @@ public final class Util { @TargetApi(8) public static void requestAudioFocus(final Context context) { - if (Build.VERSION.SDK_INT >= 8 && focusListener == null) { + if(Build.VERSION.SDK_INT >= 26) { + if(audioFocusRequest == null) { + final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + + AudioAttributes playbackAttributes = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build(); + + audioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) + .setAudioAttributes(playbackAttributes) + .setOnAudioFocusChangeListener(getAudioFocusChangeListener(context, audioManager)) + .build(); + audioManager.requestAudioFocus(audioFocusRequest); + } + } else if (Build.VERSION.SDK_INT >= 8 && focusListener == null) { final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - audioManager.requestAudioFocus(focusListener = new OnAudioFocusChangeListener() { - public void onAudioFocusChange(int focusChange) { - DownloadService downloadService = (DownloadService)context; - if((focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) && !downloadService.isRemoteEnabled()) { - if(downloadService.getPlayerState() == PlayerState.STARTED) { - Log.i(TAG, "Temporary loss of focus"); - SharedPreferences prefs = getPreferences(context); - int lossPref = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_TEMP_LOSS, "1")); - if(lossPref == 2 || (lossPref == 1 && focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK)) { - lowerFocus = true; - downloadService.setVolume(0.1f); - } else if(lossPref == 0 || (lossPref == 1 && focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT)) { - pauseFocus = true; - downloadService.pause(true); - } - } - } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { - if(pauseFocus) { - pauseFocus = false; - downloadService.start(); - } - if(lowerFocus) { - lowerFocus = false; - downloadService.setVolume(1.0f); + audioManager.requestAudioFocus(focusListener = getAudioFocusChangeListener(context, audioManager), AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); + } + } + + private static OnAudioFocusChangeListener getAudioFocusChangeListener(final Context context, final AudioManager audioManager) { + return new OnAudioFocusChangeListener() { + public void onAudioFocusChange(int focusChange) { + DownloadService downloadService = (DownloadService)context; + if((focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) && !downloadService.isRemoteEnabled()) { + if(downloadService.getPlayerState() == PlayerState.STARTED) { + Log.i(TAG, "Temporary loss of focus"); + SharedPreferences prefs = getPreferences(context); + int lossPref = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_TEMP_LOSS, "1")); + if(lossPref == 2 || (lossPref == 1 && focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK)) { + lowerFocus = true; + downloadService.setVolume(0.1f); + } else if(lossPref == 0 || (lossPref == 1 && focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT)) { + pauseFocus = true; + downloadService.pause(true); } - } else if(focusChange == AudioManager.AUDIOFOCUS_LOSS && !downloadService.isRemoteEnabled()) { - Log.i(TAG, "Permanently lost focus"); - focusListener = null; - downloadService.pause(); + } + } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { + if(pauseFocus) { + pauseFocus = false; + downloadService.start(); + } + if(lowerFocus) { + lowerFocus = false; + downloadService.setVolume(1.0f); + } + } else if(focusChange == AudioManager.AUDIOFOCUS_LOSS && !downloadService.isRemoteEnabled()) { + Log.i(TAG, "Permanently lost focus"); + focusListener = null; + downloadService.pause(); + + if(audioFocusRequest != null && Build.VERSION.SDK_INT >= 26) { + audioManager.abandonAudioFocusRequest(audioFocusRequest); + audioFocusRequest = null; + } else { audioManager.abandonAudioFocus(this); } } - }, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); - } - } + } + }; + } public static void abandonAudioFocus(Context context) { if(focusListener != null) { -- cgit v1.2.3 From 0e97692e08be98d846043e283f52f2ed815dcaf6 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Sat, 1 Sep 2018 13:51:00 -0700 Subject: Fixed #880: Use explicit startForegroundService for Android 8+ --- .../github/daneren2005/dsub/activity/SubsonicActivity.java | 4 ++-- .../daneren2005/dsub/receiver/HeadphonePlugReceiver.java | 2 +- .../daneren2005/dsub/receiver/MediaButtonIntentReceiver.java | 2 +- .../github/daneren2005/dsub/receiver/PlayActionReceiver.java | 2 +- .../daneren2005/dsub/service/AutoMediaBrowserService.java | 2 +- .../github/daneren2005/dsub/service/DownloadService.java | 12 ++++++++++++ 6 files changed, 18 insertions(+), 6 deletions(-) (limited to 'app/src/main/java/github') 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 a1c5ceef..5948064d 100644 --- a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java +++ b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java @@ -144,7 +144,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte applyTheme(); applyFullscreen(); super.onCreate(bundle); - startService(new Intent(this, DownloadService.class)); + DownloadService.startService(this); setVolumeControlStream(AudioManager.STREAM_MUSIC); if(getIntent().hasExtra(Constants.FRAGMENT_POSITION)) { @@ -1003,7 +1003,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte break; } Log.w(TAG, "DownloadService not running. Attempting to start it."); - startService(new Intent(this, DownloadService.class)); + DownloadService.startService(this); Util.sleepQuietly(50L); } diff --git a/app/src/main/java/github/daneren2005/dsub/receiver/HeadphonePlugReceiver.java b/app/src/main/java/github/daneren2005/dsub/receiver/HeadphonePlugReceiver.java index 041eb8e1..ebf50936 100644 --- a/app/src/main/java/github/daneren2005/dsub/receiver/HeadphonePlugReceiver.java +++ b/app/src/main/java/github/daneren2005/dsub/receiver/HeadphonePlugReceiver.java @@ -33,7 +33,7 @@ public class HeadphonePlugReceiver extends BroadcastReceiver { if(headphoneState == 1 && Util.shouldStartOnHeadphones(context)) { Intent start = new Intent(context, DownloadService.class); start.setAction(DownloadService.START_PLAY); - context.startService(start); + DownloadService.startService(context, start); } } } diff --git a/app/src/main/java/github/daneren2005/dsub/receiver/MediaButtonIntentReceiver.java b/app/src/main/java/github/daneren2005/dsub/receiver/MediaButtonIntentReceiver.java index 8119ef2d..0f050801 100644 --- a/app/src/main/java/github/daneren2005/dsub/receiver/MediaButtonIntentReceiver.java +++ b/app/src/main/java/github/daneren2005/dsub/receiver/MediaButtonIntentReceiver.java @@ -45,7 +45,7 @@ public class MediaButtonIntentReceiver extends BroadcastReceiver { Intent serviceIntent = new Intent(context, DownloadService.class); serviceIntent.putExtra(Intent.EXTRA_KEY_EVENT, event); - context.startService(serviceIntent); + DownloadService.startService(context, serviceIntent); if (isOrderedBroadcast()) { try { abortBroadcast(); diff --git a/app/src/main/java/github/daneren2005/dsub/receiver/PlayActionReceiver.java b/app/src/main/java/github/daneren2005/dsub/receiver/PlayActionReceiver.java index 2c04d829..aa3b9173 100644 --- a/app/src/main/java/github/daneren2005/dsub/receiver/PlayActionReceiver.java +++ b/app/src/main/java/github/daneren2005/dsub/receiver/PlayActionReceiver.java @@ -40,7 +40,7 @@ public class PlayActionReceiver extends BroadcastReceiver { start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, data.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR)); start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, data.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE)); start.putExtra(Constants.PREFERENCES_KEY_OFFLINE, data.getInt(Constants.PREFERENCES_KEY_OFFLINE)); - context.startService(start); + DownloadService.startService(context, start); } } } 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 d4e544c6..e4edabc4 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/AutoMediaBrowserService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/AutoMediaBrowserService.java @@ -524,7 +524,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { public void getDownloadService() { if(DownloadService.getInstance() == null) { - startService(new Intent(this, DownloadService.class)); + DownloadService.startService(this); } waitForDownloadService(); 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 a4ca705c..0c794c36 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -71,6 +71,7 @@ import java.util.TimerTask; import java.util.concurrent.CopyOnWriteArrayList; import android.annotation.TargetApi; +import android.app.Activity; import android.app.Service; import android.content.ComponentCallbacks2; import android.content.ComponentName; @@ -375,6 +376,17 @@ public class DownloadService extends Service { Notifications.hideDownloadingNotification(this, this, handler); } + public static void startService(Context context) { + startService(context, new Intent(context, DownloadService.class)); + } + public static void startService(Context context, Intent intent) { + PowerManager powerManager = (PowerManager) context.getSystemService(POWER_SERVICE); + if (Build.VERSION.SDK_INT < 26 || (powerManager != null && powerManager.isIgnoringBatteryOptimizations(intent.getPackage()))) { + context.startService(intent); + } else { + context.startForegroundService(intent); + } + } public static DownloadService getInstance() { return instance; } -- cgit v1.2.3 From f96b9476bf4dd7e14b38f64b4288e62771d60b4e Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Fri, 7 Sep 2018 17:02:51 -0700 Subject: Fix Android O+ crashing if something isn't played within 5 seconds of startup --- .../daneren2005/dsub/service/DownloadService.java | 6 +++++- .../github/daneren2005/dsub/util/Notifications.java | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'app/src/main/java/github') 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 0c794c36..6c3cfbd7 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -274,7 +274,7 @@ public class DownloadService extends Service { wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName()); wakeLock.setReferenceCounted(false); - WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); + WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "downloadServiceLock"); try { @@ -292,6 +292,10 @@ public class DownloadService extends Service { shufflePlayBuffer = new ShufflePlayBuffer(this); artistRadioBuffer = new ArtistRadioBuffer(this); lifecycleSupport.onCreate(); + + if(Build.VERSION.SDK_INT >= 26) { + Notifications.shutGoogleUpNotification(this); + } } @Override 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 f0bd6766..59341ebf 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Notifications.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Notifications.java @@ -51,6 +51,7 @@ public final class Notifications { // Notification IDs. public static final int NOTIFICATION_ID_PLAYING = 100; public static final int NOTIFICATION_ID_DOWNLOADING = 102; + public static final int NOTIFICATION_ID_SHUT_GOOGLE_UP = 103; public static final String NOTIFICATION_SYNC_GROUP = "github.daneren2005.dsub.sync"; private static boolean playShowing = false; @@ -447,6 +448,23 @@ public final class Notifications { return downloadingChannel; } + @TargetApi(Build.VERSION_CODES.O) + public static void shutGoogleUpNotification(final DownloadService downloadService) { + // On Android O+, service crashes if startForeground isn't called within 5 seconds of starting + getDownloadingNotificationChannel(downloadService); + + NotificationCompat.Builder builder; + builder = new NotificationCompat.Builder(downloadService) + .setSmallIcon(android.R.drawable.stat_sys_download) + .setContentTitle(downloadService.getResources().getString(R.string.download_downloading_title, 0)) + .setContentText(downloadService.getResources().getString(R.string.download_downloading_summary, "Temp")) + .setChannelId("downloading-channel"); + + final Notification notification = builder.build(); + downloadService.startForeground(NOTIFICATION_ID_SHUT_GOOGLE_UP, notification); + downloadService.stopForeground(true); + } + public static void showSyncNotification(final Context context, int stringId, String extra) { showSyncNotification(context, stringId, extra, null); } -- cgit v1.2.3 From 6eb8fcb14e96d866bbecad82a78383698ab7af0e Mon Sep 17 00:00:00 2001 From: Glenn Guy Date: Sat, 8 Sep 2018 22:57:48 +1000 Subject: AA voice search improvements Specific song requests weren't doing anything, and requests to 'play some (artist)' would queue up albums in chronological order. Single songs now working, and artist requests will shuffle which is in line with other services like spotify etc. --- .../daneren2005/dsub/util/compat/RemoteControlClientLP.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'app/src/main/java/github') 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 9f1d5ebd..1229d024 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 @@ -315,9 +315,9 @@ public class RemoteControlClientLP extends RemoteControlClientBase { SearchResult results = musicService.search(searchCritera, downloadService, null); if(results.hasArtists()) { - playFromParent(new Entry(results.getArtists().get(0))); + playFromParent(new Entry(results.getArtists().get(0)), true); } else if(results.hasAlbums()) { - playFromParent(results.getAlbums().get(0)); + playFromParent(results.getAlbums().get(0), false); } else if(results.hasSongs()) { playSong(results.getSongs().get(0)); } else { @@ -327,10 +327,10 @@ public class RemoteControlClientLP extends RemoteControlClientBase { return null; } - private void playFromParent(Entry parent) throws Exception { + private void playFromParent(Entry parent, boolean shuffle) throws Exception { List songs = new ArrayList<>(); getSongsRecursively(parent, songs); - playSongs(songs); + playSongs(songs, shuffle, false, false); } private void getSongsRecursively(Entry parent, List songs) throws Exception { MusicDirectory musicDirectory; @@ -421,7 +421,7 @@ public class RemoteControlClientLP extends RemoteControlClientBase { } private void playSong(Entry entry) { - + playSong(entry, false); } private void playSong(Entry entry, boolean resumeFromBookmark) { List entries = new ArrayList<>(); -- cgit v1.2.3