diff options
10 files changed, 217 insertions, 111 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java index 24c20242a..9ba4276be 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java @@ -3,6 +3,7 @@ package de.test.antennapod.ui; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; + import androidx.annotation.StringRes; import androidx.preference.PreferenceManager; import androidx.test.filters.LargeTest; @@ -30,9 +31,7 @@ import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.action.ViewActions.scrollTo; import static androidx.test.espresso.action.ViewActions.swipeDown; import static androidx.test.espresso.action.ViewActions.swipeUp; -import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.isChecked; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.isRoot; import static androidx.test.espresso.matcher.ViewMatchers.withId; @@ -40,7 +39,6 @@ import static androidx.test.espresso.matcher.ViewMatchers.withText; import static de.test.antennapod.EspressoTestUtils.clickPreference; import static de.test.antennapod.EspressoTestUtils.waitForView; import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -80,38 +78,22 @@ public class PreferencesTest { } @Test - public void testSetLockscreenButtons() { + public void testSetNotificationButtons() { clickPreference(R.string.user_interface_label); - String[] buttons = res.getStringArray(R.array.compact_notification_buttons_options); - clickPreference(R.string.pref_compact_notification_buttons_title); + String[] buttons = res.getStringArray(R.array.full_notification_buttons_options); + clickPreference(R.string.pref_full_notification_buttons_title); // First uncheck checkboxes - onView(withText(buttons[0])).perform(click()); - onView(withText(buttons[1])).perform(click()); - - // Now try to check all checkboxes - onView(withText(buttons[0])).perform(click()); onView(withText(buttons[1])).perform(click()); onView(withText(buttons[2])).perform(click()); - // Make sure that the third checkbox is unchecked - onView(withText(buttons[2])).check(matches(not(isChecked()))); - - String snackBarText = String.format(res.getString( - R.string.pref_compact_notification_buttons_dialog_error), 2); - Awaitility.await().ignoreExceptions().atMost(4000, MILLISECONDS) - .until(() -> { - onView(withText(snackBarText)).check(doesNotExist()); - return true; - }); - onView(withText(R.string.confirm_label)).perform(click()); Awaitility.await().atMost(1000, MILLISECONDS) - .until(UserPreferences::showRewindOnCompactNotification); + .until(() -> UserPreferences.showSkipOnFullNotification()); Awaitility.await().atMost(1000, MILLISECONDS) - .until(UserPreferences::showFastForwardOnCompactNotification); + .until(() -> UserPreferences.showNextChapterOnFullNotification()); Awaitility.await().atMost(1000, MILLISECONDS) - .until(() -> !UserPreferences.showSkipOnCompactNotification()); + .until(() -> !UserPreferences.showPlaybackSpeedOnFullNotification()); } @Test diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java index c8521caab..0f3320e98 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java @@ -1,8 +1,10 @@ package de.danoeh.antennapod.fragment.preferences; import android.content.Context; +import android.content.DialogInterface; import android.os.Build; import android.os.Bundle; +import android.widget.Button; import android.widget.ListView; import androidx.appcompat.app.AlertDialog; import androidx.core.app.ActivityCompat; @@ -64,9 +66,9 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat { return true; }); - findPreference(UserPreferences.PREF_COMPACT_NOTIFICATION_BUTTONS) + findPreference(UserPreferences.PREF_FULL_NOTIFICATION_BUTTONS) .setOnPreferenceClickListener(preference -> { - showNotificationButtonsDialog(); + showFullNotificationButtonsDialog(); return true; }); findPreference(UserPreferences.PREF_FILTER_FEED) @@ -91,48 +93,85 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat { } } - private void showNotificationButtonsDialog() { + + private void showFullNotificationButtonsDialog() { final Context context = getActivity(); - final List<Integer> preferredButtons = UserPreferences.getCompactNotificationButtons(); + + final List<Integer> preferredButtons = UserPreferences.getFullNotificationButtons(); final String[] allButtonNames = context.getResources().getStringArray( - R.array.compact_notification_buttons_options); + R.array.full_notification_buttons_options); + final int[] buttonIDs = {2, 3, 4}; + final int exactItems = 2; + final DialogInterface.OnClickListener completeListener = (dialog, which) -> + UserPreferences.setFullNotificationButtons(preferredButtons); + final String title = context.getResources().getString( + R.string.pref_full_notification_buttons_title); + + showNotificationButtonsDialog(preferredButtons, allButtonNames, buttonIDs, title, + exactItems, completeListener + ); + } + + private void showNotificationButtonsDialog(List<Integer> preferredButtons, + String[] allButtonNames, int[] buttonIds, String title, + int exactItems, DialogInterface.OnClickListener completeListener) { boolean[] checked = new boolean[allButtonNames.length]; // booleans default to false in java + final Context context = getActivity(); + + // Clear buttons that are not part of the setting anymore + for (int i = preferredButtons.size() - 1; i >= 0; i--) { + boolean isValid = false; + for (int j = 0; j < checked.length; j++) { + if (buttonIds[j] == preferredButtons.get(i)) { + isValid = true; + } + } + + if (!isValid) { + preferredButtons.remove(i); + } + } + for(int i=0; i < checked.length; i++) { - if(preferredButtons.contains(i)) { + if (preferredButtons.contains(buttonIds[i])) { checked[i] = true; } } MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context); - builder.setTitle(String.format(context.getResources().getString( - R.string.pref_compact_notification_buttons_dialog_title), 2)); + builder.setTitle(title); builder.setMultiChoiceItems(allButtonNames, checked, (dialog, which, isChecked) -> { checked[which] = isChecked; if (isChecked) { - if (preferredButtons.size() < 2) { - preferredButtons.add(which); - } else { - // Only allow a maximum of two selections. This is because the notification - // on the lock screen can only display 3 buttons, and the play/pause button - // is always included. - checked[which] = false; - ListView selectionView = ((AlertDialog) dialog).getListView(); - selectionView.setItemChecked(which, false); - Snackbar.make( - selectionView, - String.format(context.getResources().getString( - R.string.pref_compact_notification_buttons_dialog_error), 2), - Snackbar.LENGTH_SHORT).show(); - } + preferredButtons.add(buttonIds[which]); } else { - preferredButtons.remove((Integer) which); + preferredButtons.remove((Integer) buttonIds[which]); } }); - builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> - UserPreferences.setCompactNotificationButtons(preferredButtons)); + builder.setPositiveButton(R.string.confirm_label, null); builder.setNegativeButton(R.string.cancel_label, null); - builder.create().show(); + final AlertDialog dialog = builder.create(); + + dialog.show(); + + Button positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE); + + positiveButton.setOnClickListener(v -> { + if (preferredButtons.size() != exactItems) { + ListView selectionView = dialog.getListView(); + Snackbar.make( + selectionView, + String.format(context.getResources().getString( + R.string.pref_compact_notification_buttons_dialog_error_exact), exactItems), + Snackbar.LENGTH_SHORT).show(); + + } else { + completeListener.onClick(dialog, AlertDialog.BUTTON_POSITIVE); + dialog.cancel(); + } + } + ); } } diff --git a/app/src/main/res/xml/preferences_user_interface.xml b/app/src/main/res/xml/preferences_user_interface.xml index 733649ce1..5cd25d59f 100644 --- a/app/src/main/res/xml/preferences_user_interface.xml +++ b/app/src/main/res/xml/preferences_user_interface.xml @@ -70,9 +70,9 @@ android:summary="@string/pref_persistNotify_sum" android:title="@string/pref_persistNotify_title"/> <Preference - android:key="prefCompactNotificationButtons" - android:summary="@string/pref_compact_notification_buttons_sum" - android:title="@string/pref_compact_notification_buttons_title"/> + android:key="prefFullNotificationButtons" + android:summary="@string/pref_full_notification_buttons_sum" + android:title="@string/pref_full_notification_buttons_title"/> </PreferenceCategory> <PreferenceCategory android:title="@string/behavior"> <de.danoeh.antennapod.preferences.MaterialListPreference diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java index 08bdd39bc..161af58e1 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java +++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java @@ -17,6 +17,8 @@ import de.danoeh.antennapod.core.ClientConfigurator; public class MediaButtonReceiver extends BroadcastReceiver { private static final String TAG = "MediaButtonReceiver"; public static final String EXTRA_KEYCODE = "de.danoeh.antennapod.core.service.extra.MediaButtonReceiver.KEYCODE"; + public static final String EXTRA_CUSTOM_ACTION = + "de.danoeh.antennapod.core.service.extra.MediaButtonReceiver.CUSTOM_ACTION"; public static final String EXTRA_SOURCE = "de.danoeh.antennapod.core.service.extra.MediaButtonReceiver.SOURCE"; public static final String EXTRA_HARDWAREBUTTON = "de.danoeh.antennapod.core.service.extra.MediaButtonReceiver.HARDWAREBUTTON"; diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index 3ef2e2214..b26cf4814 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -47,6 +47,20 @@ import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; import androidx.media.MediaBrowserServiceCompat; +import de.danoeh.antennapod.core.service.QuickSettingsTileService; +import de.danoeh.antennapod.core.util.ChapterUtils; +import de.danoeh.antennapod.core.util.playback.PlayableUtils; +import de.danoeh.antennapod.event.playback.BufferUpdateEvent; +import de.danoeh.antennapod.event.playback.PlaybackServiceEvent; +import de.danoeh.antennapod.event.PlayerErrorEvent; +import de.danoeh.antennapod.event.playback.SleepTimerUpdatedEvent; +import de.danoeh.antennapod.model.feed.Chapter; +import de.danoeh.antennapod.model.feed.FeedItemFilter; +import de.danoeh.antennapod.playback.base.PlaybackServiceMediaPlayer; +import de.danoeh.antennapod.playback.base.PlayerStatus; +import de.danoeh.antennapod.playback.cast.CastPsmp; +import de.danoeh.antennapod.playback.cast.CastStateListener; + import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -126,6 +140,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { private static final String CUSTOM_ACTION_REWIND = "action.de.danoeh.antennapod.core.service.rewind"; private static final String CUSTOM_ACTION_CHANGE_PLAYBACK_SPEED = "action.de.danoeh.antennapod.core.service.changePlaybackSpeed"; + public static final String CUSTOM_ACTION_NEXT_CHAPTER = "action.de.danoeh.antennapod.core.service.next_chapter"; /** * Set a max number of episodes to load for Android Auto, otherwise there could be performance issues @@ -482,9 +497,10 @@ public class PlaybackService extends MediaBrowserServiceCompat { notificationManager.cancel(R.id.notification_streaming_confirmation); final int keycode = intent.getIntExtra(MediaButtonReceiver.EXTRA_KEYCODE, -1); + final String customAction = intent.getStringExtra(MediaButtonReceiver.EXTRA_CUSTOM_ACTION); final boolean hardwareButton = intent.getBooleanExtra(MediaButtonReceiver.EXTRA_HARDWAREBUTTON, false); Playable playable = intent.getParcelableExtra(PlaybackServiceInterface.EXTRA_PLAYABLE); - if (keycode == -1 && playable == null) { + if (keycode == -1 && playable == null && customAction == null) { Log.e(TAG, "PlaybackService was started with no arguments"); stateManager.stopService(); return Service.START_NOT_STICKY; @@ -508,7 +524,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { stateManager.stopService(); return Service.START_NOT_STICKY; } - } else { + } else if (playable != null) { stateManager.validStartCommandWasReceived(); boolean allowStreamThisTime = intent.getBooleanExtra( PlaybackServiceInterface.EXTRA_ALLOW_STREAM_THIS_TIME, false); @@ -536,6 +552,8 @@ public class PlaybackService extends MediaBrowserServiceCompat { stateManager.stopService(); }); return Service.START_NOT_STICKY; + } else { + mediaSession.getController().getTransportControls().sendCustomAction(customAction, null); } } @@ -783,6 +801,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { @Override public void onChapterLoaded(Playable media) { sendNotificationBroadcast(PlaybackServiceInterface.NOTIFICATION_TYPE_RELOAD, 0); + updateMediaSession(mediaPlayer.getPlayerStatus()); } }; @@ -1250,20 +1269,35 @@ public class PlaybackService extends MediaBrowserServiceCompat { WearMediaSession.addWearExtrasToAction(fastForwardBuilder); sessionState.addCustomAction(fastForwardBuilder.build()); - sessionState.addCustomAction( - new PlaybackStateCompat.CustomAction.Builder( - CUSTOM_ACTION_CHANGE_PLAYBACK_SPEED, - getString(R.string.playback_speed), - R.drawable.ic_notification_playback_speed + if (UserPreferences.showPlaybackSpeedOnFullNotification()) { + sessionState.addCustomAction( + new PlaybackStateCompat.CustomAction.Builder( + CUSTOM_ACTION_CHANGE_PLAYBACK_SPEED, + getString(R.string.playback_speed), + R.drawable.ic_notification_playback_speed ).build() - ); - sessionState.addCustomAction( + ); + } + + if (UserPreferences.showNextChapterOnFullNotification()) { + if (getPlayable() != null && getPlayable().getChapters() != null) { + sessionState.addCustomAction( + new PlaybackStateCompat.CustomAction.Builder( + CUSTOM_ACTION_NEXT_CHAPTER, + getString(R.string.next_chapter), R.drawable.ic_notification_next_chapter) + .build()); + } + } + + if (UserPreferences.showSkipOnFullNotification()) { + sessionState.addCustomAction( new PlaybackStateCompat.CustomAction.Builder( - CUSTOM_ACTION_SKIP_TO_NEXT, - getString(R.string.skip_episode_label), - R.drawable.ic_notification_skip + CUSTOM_ACTION_SKIP_TO_NEXT, + getString(R.string.skip_episode_label), + R.drawable.ic_notification_skip ).build() - ); + ); + } WearMediaSession.mediaSessionSetExtraForWear(mediaSession); @@ -1812,6 +1846,26 @@ public class PlaybackService extends MediaBrowserServiceCompat { seekDelta(-UserPreferences.getRewindSecs() * 1000); } + public void onNextChapter() { + List<Chapter> chapters = mediaPlayer.getPlayable().getChapters(); + if (chapters == null) { + // No chapters, just fallback to next episode + mediaPlayer.skip(); + return; + } + + int nextChapter = ChapterUtils.getCurrentChapterIndex( + mediaPlayer.getPlayable(), mediaPlayer.getPosition()) + 1; + + if (chapters.size() < nextChapter + 1) { + // We are on the last chapter, just fallback to the next episode + mediaPlayer.skip(); + return; + } + + mediaPlayer.seekTo((int) chapters.get(nextChapter).getStart()); + } + @Override public void onFastForward() { Log.d(TAG, "onFastForward()"); @@ -1884,6 +1938,8 @@ public class PlaybackService extends MediaBrowserServiceCompat { onRewind(); } else if (CUSTOM_ACTION_SKIP_TO_NEXT.equals(action)) { mediaPlayer.skip(); + } else if (CUSTOM_ACTION_NEXT_CHAPTER.equals(action)) { + onNextChapter(); } else if (CUSTOM_ACTION_CHANGE_PLAYBACK_SPEED.equals(action)) { List<Float> selectedSpeeds = UserPreferences.getPlaybackSpeedArray(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java index fe98dbc8f..471dc7454 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java @@ -175,14 +175,12 @@ public class PlaybackServiceNotificationBuilder { ArrayList<Integer> compactActionList = new ArrayList<>(); int numActions = 0; // we start and 0 and then increment by 1 for each call to addAction - // always let them rewind + PendingIntent rewindButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_REWIND, numActions); notification.addAction(R.drawable.ic_notification_fast_rewind, context.getString(R.string.rewind_label), rewindButtonPendingIntent); - if (UserPreferences.showRewindOnCompactNotification()) { - compactActionList.add(numActions); - } + compactActionList.add(numActions); numActions++; if (playerStatus == PlayerStatus.PLAYING) { @@ -205,19 +203,24 @@ public class PlaybackServiceNotificationBuilder { KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, numActions); notification.addAction(R.drawable.ic_notification_fast_forward, context.getString(R.string.fast_forward_label), ffButtonPendingIntent); - if (UserPreferences.showFastForwardOnCompactNotification()) { - compactActionList.add(numActions); - } + compactActionList.add(numActions); numActions++; - PendingIntent skipButtonPendingIntent = getPendingIntentForMediaAction( - KeyEvent.KEYCODE_MEDIA_NEXT, numActions); - notification.addAction(R.drawable.ic_notification_skip, context.getString(R.string.skip_episode_label), - skipButtonPendingIntent); - if (UserPreferences.showSkipOnCompactNotification()) { - compactActionList.add(numActions); + if (UserPreferences.showNextChapterOnFullNotification() && playable.getChapters() != null) { + PendingIntent nextChapterPendingIntent = getPendingIntentForCustomMediaAction( + PlaybackService.CUSTOM_ACTION_NEXT_CHAPTER, numActions); + notification.addAction(R.drawable.ic_notification_next_chapter, context.getString(R.string.next_chapter), + nextChapterPendingIntent); + numActions++; + } + + if (UserPreferences.showSkipOnFullNotification()) { + PendingIntent skipButtonPendingIntent = getPendingIntentForMediaAction( + KeyEvent.KEYCODE_MEDIA_NEXT, numActions); + notification.addAction(R.drawable.ic_notification_skip, context.getString(R.string.skip_episode_label), + skipButtonPendingIntent); + numActions++; } - numActions++; PendingIntent stopButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_STOP, numActions); @@ -242,6 +245,20 @@ public class PlaybackServiceNotificationBuilder { } } + private PendingIntent getPendingIntentForCustomMediaAction(String action, int requestCode) { + Intent intent = new Intent(context, PlaybackService.class); + intent.setAction("MediaAction" + action); + intent.putExtra(MediaButtonReceiver.EXTRA_CUSTOM_ACTION, action); + + if (Build.VERSION.SDK_INT >= 26) { + return PendingIntent.getForegroundService(context, requestCode, intent, + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); + } else { + return PendingIntent.getService(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT + | (Build.VERSION.SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0)); + } + } + public void setMediaSessionToken(MediaSessionCompat.Token mediaSessionToken) { this.mediaSessionToken = mediaSessionToken; } @@ -253,4 +270,4 @@ public class PlaybackServiceNotificationBuilder { public PlayerStatus getPlayerStatus() { return playerStatus; } -}
\ No newline at end of file +} diff --git a/core/src/main/res/values/arrays.xml b/core/src/main/res/values/arrays.xml index f72a2e108..7eeab886a 100644 --- a/core/src/main/res/values/arrays.xml +++ b/core/src/main/res/values/arrays.xml @@ -246,10 +246,10 @@ <item>DownloadsSection</item> </string-array> - <string-array name="compact_notification_buttons_options"> - <item>@string/rewind_label</item> - <item>@string/fast_forward_label</item> + <string-array name="full_notification_buttons_options"> <item>@string/skip_episode_label</item> + <item>@string/next_chapter</item> + <item>@string/playback_speed</item> </string-array> <string-array name="default_page_values"> diff --git a/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java b/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java index 7b15584ba..b454ee5a1 100644 --- a/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java +++ b/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java @@ -54,7 +54,7 @@ public class UserPreferences { public static final String PREF_USE_EPISODE_COVER = "prefEpisodeCover"; public static final String PREF_SHOW_TIME_LEFT = "showTimeLeft"; private static final String PREF_PERSISTENT_NOTIFICATION = "prefPersistNotify"; - public static final String PREF_COMPACT_NOTIFICATION_BUTTONS = "prefCompactNotificationButtons"; + public static final String PREF_FULL_NOTIFICATION_BUTTONS = "prefFullNotificationButtons"; private static final String PREF_SHOW_DOWNLOAD_REPORT = "prefShowDownloadReport"; public static final String PREF_DEFAULT_PAGE = "prefDefaultPage"; public static final String PREF_FILTER_FEED = "prefSubscriptionsFilter"; @@ -127,9 +127,12 @@ public class UserPreferences { public static final int EPISODE_CLEANUP_DEFAULT = 0; // Constants - private static final int NOTIFICATION_BUTTON_REWIND = 0; - private static final int NOTIFICATION_BUTTON_FAST_FORWARD = 1; - private static final int NOTIFICATION_BUTTON_SKIP = 2; + public static final int NOTIFICATION_BUTTON_REWIND = 0; + public static final int NOTIFICATION_BUTTON_FAST_FORWARD = 1; + public static final int NOTIFICATION_BUTTON_SKIP = 2; + + public static final int NOTIFICATION_BUTTON_NEXT_CHAPTER = 3; + public static final int NOTIFICATION_BUTTON_PLAYBACK_SPEED = 4; public static final int EPISODE_CACHE_SIZE_UNLIMITED = -1; public static final int FEED_ORDER_COUNTER = 0; public static final int FEED_ORDER_ALPHABETICAL = 1; @@ -195,11 +198,11 @@ public class UserPreferences { return new ArrayList<>(Arrays.asList(TextUtils.split(hiddenItems, ","))); } - public static List<Integer> getCompactNotificationButtons() { + public static List<Integer> getFullNotificationButtons() { String[] buttons = TextUtils.split( - prefs.getString(PREF_COMPACT_NOTIFICATION_BUTTONS, - NOTIFICATION_BUTTON_REWIND + "," + NOTIFICATION_BUTTON_FAST_FORWARD), - ","); + prefs.getString(PREF_FULL_NOTIFICATION_BUTTONS, + NOTIFICATION_BUTTON_SKIP + "," + NOTIFICATION_BUTTON_PLAYBACK_SPEED), ","); + List<Integer> notificationButtons = new ArrayList<>(); for (String button : buttons) { notificationButtons.add(Integer.parseInt(button)); @@ -208,27 +211,28 @@ public class UserPreferences { } /** - * Helper function to return whether the specified button should be shown on compact + * Helper function to return whether the specified button should be shown on full * notifications. * - * @param buttonId Either NOTIFICATION_BUTTON_REWIND, NOTIFICATION_BUTTON_FAST_FORWARD or - * NOTIFICATION_BUTTON_SKIP. + * @param buttonId Either NOTIFICATION_BUTTON_REWIND, NOTIFICATION_BUTTON_FAST_FORWARD, + * NOTIFICATION_BUTTON_SKIP, NOTIFICATION_BUTTON_PLAYBACK_SPEED + * or NOTIFICATION_BUTTON_NEXT_CHAPTER. * @return {@code true} if button should be shown, {@code false} otherwise */ - private static boolean showButtonOnCompactNotification(int buttonId) { - return getCompactNotificationButtons().contains(buttonId); + private static boolean showButtonOnFullNotification(int buttonId) { + return getFullNotificationButtons().contains(buttonId); } - public static boolean showRewindOnCompactNotification() { - return showButtonOnCompactNotification(NOTIFICATION_BUTTON_REWIND); + public static boolean showSkipOnFullNotification() { + return showButtonOnFullNotification(NOTIFICATION_BUTTON_SKIP); } - public static boolean showFastForwardOnCompactNotification() { - return showButtonOnCompactNotification(NOTIFICATION_BUTTON_FAST_FORWARD); + public static boolean showNextChapterOnFullNotification() { + return showButtonOnFullNotification(NOTIFICATION_BUTTON_NEXT_CHAPTER); } - public static boolean showSkipOnCompactNotification() { - return showButtonOnCompactNotification(NOTIFICATION_BUTTON_SKIP); + public static boolean showPlaybackSpeedOnFullNotification() { + return showButtonOnFullNotification(NOTIFICATION_BUTTON_PLAYBACK_SPEED); } public static int getFeedOrder() { @@ -653,10 +657,10 @@ public class UserPreferences { .apply(); } - public static void setCompactNotificationButtons(List<Integer> items) { + public static void setFullNotificationButtons(List<Integer> items) { String str = TextUtils.join(",", items); prefs.edit() - .putString(PREF_COMPACT_NOTIFICATION_BUTTONS, str) + .putString(PREF_FULL_NOTIFICATION_BUTTONS, str) .apply(); } diff --git a/ui/i18n/src/main/res/values/strings.xml b/ui/i18n/src/main/res/values/strings.xml index d7b6aa6cc..ab65b6c41 100644 --- a/ui/i18n/src/main/res/values/strings.xml +++ b/ui/i18n/src/main/res/values/strings.xml @@ -489,10 +489,9 @@ <string name="pref_expandNotify_sum">This usually expands the notification to show playback buttons.</string> <string name="pref_persistNotify_title">Persistent playback controls</string> <string name="pref_persistNotify_sum">Keep notification and lockscreen controls when playback is paused</string> - <string name="pref_compact_notification_buttons_title">Set compact notification buttons</string> - <string name="pref_compact_notification_buttons_sum">Change the playback buttons when the notification is collapsed. The play/pause button is always included.</string> - <string name="pref_compact_notification_buttons_dialog_title">Select a maximum of %1$d items</string> - <string name="pref_compact_notification_buttons_dialog_error">You can only select a maximum of %1$d items.</string> + <string name="pref_compact_notification_buttons_dialog_error_exact">You must select exactly %1$d items.</string> + <string name="pref_full_notification_buttons_title">Set notification buttons</string> + <string name="pref_full_notification_buttons_sum">Change the playback buttons on the playback notification.</string> <string name="pref_enqueue_location_title">Enqueue location</string> <string name="pref_enqueue_location_sum">Add episodes to: %1$s</string> <string name="enqueue_location_back">Back</string> diff --git a/ui/png-icons/src/main/res/drawable/ic_notification_next_chapter.xml b/ui/png-icons/src/main/res/drawable/ic_notification_next_chapter.xml new file mode 100644 index 000000000..cb55e93a9 --- /dev/null +++ b/ui/png-icons/src/main/res/drawable/ic_notification_next_chapter.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path android:fillColor="#fff" android:pathData="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4M8,8V16L13,12M14,8V16H16V8" />
+</vector>
|