summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/src/free/java/de/danoeh/antennapod/core/service/playback/PlaybackVolumeAdaptor.java49
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java28
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/service/playback/PlaybackVolumeAdaptorTest.java230
3 files changed, 305 insertions, 2 deletions
diff --git a/core/src/free/java/de/danoeh/antennapod/core/service/playback/PlaybackVolumeAdaptor.java b/core/src/free/java/de/danoeh/antennapod/core/service/playback/PlaybackVolumeAdaptor.java
new file mode 100644
index 000000000..949f8c8cc
--- /dev/null
+++ b/core/src/free/java/de/danoeh/antennapod/core/service/playback/PlaybackVolumeAdaptor.java
@@ -0,0 +1,49 @@
+package de.danoeh.antennapod.core.service.playback;
+
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.feed.FeedPreferences;
+import de.danoeh.antennapod.core.util.playback.Playable;
+
+class PlaybackVolumeAdaptor {
+
+ public void adaptVolumeIfNecessary(PlaybackServiceMediaPlayer mediaPlayer, String affectedFeedIdentifier, FeedPreferences.VolumeReductionSetting volumeReductionSetting) {
+ Playable playable = mediaPlayer.getPlayable();
+ boolean isFeedMedia = playable instanceof FeedMedia;
+ boolean isPlayableLoaded = isPlayableLoaded(mediaPlayer.getPlayerStatus());
+
+ if (isPlayableLoaded && isFeedMedia) {
+ adaptFeedMediaVolumeIfNecessary(mediaPlayer, affectedFeedIdentifier, volumeReductionSetting, (FeedMedia) playable);
+ }
+ }
+
+ private void adaptFeedMediaVolumeIfNecessary(PlaybackServiceMediaPlayer mediaPlayer, String affectedFeedIdentifier, FeedPreferences.VolumeReductionSetting volumeReductionSetting, FeedMedia feedMedia) {
+ if (mediaBelongsToAffectedFeed(feedMedia, affectedFeedIdentifier)) {
+ FeedPreferences preferences = feedMedia.getItem().getFeed().getPreferences();
+ preferences.setVolumeReductionSetting(volumeReductionSetting);
+
+ if (mediaPlayer.getPlayerStatus() == PlayerStatus.PLAYING) {
+ forceAdaptVolume(mediaPlayer);
+ }
+ }
+ }
+
+ private static boolean isPlayableLoaded(PlayerStatus playerStatus) {
+ return playerStatus == PlayerStatus.PLAYING
+ || playerStatus == PlayerStatus.PAUSED
+ || playerStatus == PlayerStatus.SEEKING
+ || playerStatus == PlayerStatus.PREPARING
+ || playerStatus == PlayerStatus.PREPARED
+ || playerStatus == PlayerStatus.INITIALIZING;
+ }
+
+ private static boolean mediaBelongsToAffectedFeed(FeedMedia feedMedia, String affectedFeedIdentifier) {
+ return affectedFeedIdentifier != null
+ && affectedFeedIdentifier.equals(feedMedia.getItem().getFeed().getIdentifyingValue());
+ }
+
+ private static void forceAdaptVolume(PlaybackServiceMediaPlayer mediaPlayer) {
+ mediaPlayer.pause(false, false);
+ mediaPlayer.resume();
+ }
+
+}
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 ab1edc8e9..632dfd50e 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
@@ -12,7 +12,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
@@ -43,6 +42,7 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@@ -54,6 +54,7 @@ import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.feed.FeedPreferences;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.feed.SearchResult;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
@@ -66,7 +67,6 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.FeedSearcher;
-import de.danoeh.antennapod.core.util.IntList;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.core.util.QueueAccess;
@@ -80,6 +80,7 @@ import org.greenrobot.eventbus.EventBus;
* Controls the MediaPlayer that plays a FeedMedia-file
*/
public class PlaybackService extends MediaBrowserServiceCompat {
+
/**
* Logging tag
*/
@@ -131,6 +132,12 @@ public class PlaybackService extends MediaBrowserServiceCompat {
*/
public static final String ACTION_PAUSE_PLAY_CURRENT_EPISODE = "action.de.danoeh.antennapod.core.service.pausePlayCurrentEpisode";
+ /**
+ * If the PlaybackService receives this action, it will try to apply the supplied volume reduction setting.
+ */
+ public static final String ACTION_VOLUME_REDUCTION_CHANGED = "action.de.danoeh.antennapod.core.service.volumedReductionChanged";
+ public static final String EXTRA_VOLUME_REDUCTION_SETTING = "PlaybackService.VolumeReductionSettingExtra";
+ public static final String EXTRA_VOLUME_REDUCTION_AFFECTED_FEED = "PlaybackService.VolumeReductionSettingAffectedFeed";
/**
* If the PlaybackService receives this action, it will resume playback.
@@ -279,6 +286,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
registerReceiver(skipCurrentEpisodeReceiver, new IntentFilter(ACTION_SKIP_CURRENT_EPISODE));
registerReceiver(pausePlayCurrentEpisodeReceiver, new IntentFilter(ACTION_PAUSE_PLAY_CURRENT_EPISODE));
registerReceiver(pauseResumeCurrentEpisodeReceiver, new IntentFilter(ACTION_RESUME_PLAY_CURRENT_EPISODE));
+ registerReceiver(volumeReductionChangedReceiver, new IntentFilter(ACTION_VOLUME_REDUCTION_CHANGED));
taskManager = new PlaybackServiceTaskManager(this, taskManagerCallback);
flavorHelper = new PlaybackServiceFlavorHelper(PlaybackService.this, flavorHelperCallback);
@@ -1517,6 +1525,22 @@ public class PlaybackService extends MediaBrowserServiceCompat {
}
};
+ private final BroadcastReceiver volumeReductionChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (TextUtils.equals(intent.getAction(), ACTION_VOLUME_REDUCTION_CHANGED)) {
+ Log.d(TAG, "Received ACTION_VOLUME_REDUCTION_CHANGED intent");
+
+ String affectedFeed = intent.getStringExtra(EXTRA_VOLUME_REDUCTION_AFFECTED_FEED);
+ Serializable volumeReductionExtra = intent.getSerializableExtra(EXTRA_VOLUME_REDUCTION_SETTING);
+ FeedPreferences.VolumeReductionSetting volumeReductionSetting = (FeedPreferences.VolumeReductionSetting) volumeReductionExtra;
+
+ PlaybackVolumeAdaptor playbackVolumeAdaptor = new PlaybackVolumeAdaptor();
+ playbackVolumeAdaptor.adaptVolumeIfNecessary(mediaPlayer, affectedFeed, volumeReductionSetting);
+ }
+ }
+ };
+
public static MediaType getCurrentMediaType() {
return currentMediaType;
}
diff --git a/core/src/test/java/de/danoeh/antennapod/core/service/playback/PlaybackVolumeAdaptorTest.java b/core/src/test/java/de/danoeh/antennapod/core/service/playback/PlaybackVolumeAdaptorTest.java
new file mode 100644
index 000000000..9036624d8
--- /dev/null
+++ b/core/src/test/java/de/danoeh/antennapod/core/service/playback/PlaybackVolumeAdaptorTest.java
@@ -0,0 +1,230 @@
+package de.danoeh.antennapod.core.service.playback;
+
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.feed.FeedPreferences;
+import de.danoeh.antennapod.core.feed.FeedPreferences.VolumeReductionSetting;
+import de.danoeh.antennapod.core.util.playback.Playable;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class PlaybackVolumeAdaptorTest {
+
+ private static final String FEED_ID = "feedId";
+
+ private PlaybackServiceMediaPlayer mediaPlayer;
+
+ @Before
+ public void setUp() throws Exception {
+ mediaPlayer = mock(PlaybackServiceMediaPlayer.class);
+ }
+
+ @Test
+ public void noChangeIfNoFeedMediaPlaying() {
+ PlaybackVolumeAdaptor playbackVolumeAdaptor = new PlaybackVolumeAdaptor();
+
+ when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.PAUSED);
+
+ Playable noFeedMedia = mock(Playable.class);
+ when(mediaPlayer.getPlayable()).thenReturn(noFeedMedia);
+
+ playbackVolumeAdaptor.adaptVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.OFF);
+
+ verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean());
+ verify(mediaPlayer, never()).resume();
+ }
+
+ @Test
+ public void noChangeIfPlayerStatusIsError() {
+ PlaybackVolumeAdaptor playbackVolumeAdaptor = new PlaybackVolumeAdaptor();
+
+ when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.ERROR);
+
+ FeedMedia feedMedia = mock(FeedMedia.class);
+ when(mediaPlayer.getPlayable()).thenReturn(feedMedia);
+
+ playbackVolumeAdaptor.adaptVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.OFF);
+
+ verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean());
+ verify(mediaPlayer, never()).resume();
+ }
+
+ @Test
+ public void noChangeIfPlayerStatusIsIndeterminate() {
+ PlaybackVolumeAdaptor playbackVolumeAdaptor = new PlaybackVolumeAdaptor();
+
+ when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.INDETERMINATE);
+
+ FeedMedia feedMedia = mock(FeedMedia.class);
+ when(mediaPlayer.getPlayable()).thenReturn(feedMedia);
+
+ playbackVolumeAdaptor.adaptVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.OFF);
+
+ verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean());
+ verify(mediaPlayer, never()).resume();
+ }
+
+ @Test
+ public void noChangeIfPlayerStatusIsStopped() {
+ PlaybackVolumeAdaptor playbackVolumeAdaptor = new PlaybackVolumeAdaptor();
+
+ when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.STOPPED);
+
+ FeedMedia feedMedia = mock(FeedMedia.class);
+ when(mediaPlayer.getPlayable()).thenReturn(feedMedia);
+
+ playbackVolumeAdaptor.adaptVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.OFF);
+
+ verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean());
+ verify(mediaPlayer, never()).resume();
+ }
+
+ @Test
+ public void noChangeIfPlayableIsNoItemOfAffectedFeed() {
+ PlaybackVolumeAdaptor playbackVolumeAdaptor = new PlaybackVolumeAdaptor();
+
+ when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.PLAYING);
+
+ FeedMedia feedMedia = mock(FeedMedia.class);
+ when(mediaPlayer.getPlayable()).thenReturn(feedMedia);
+ Feed feed = mockFeed(feedMedia, FEED_ID);
+ when(feed.getIdentifyingValue()).thenReturn("wrongFeedId");
+
+ playbackVolumeAdaptor.adaptVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.OFF);
+
+ verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean());
+ verify(mediaPlayer, never()).resume();
+ }
+
+ @Test
+ public void adaptsPreferencesForLoadedFeedMediaIfPlayerStatusIsPaused() {
+ PlaybackVolumeAdaptor playbackVolumeAdaptor = new PlaybackVolumeAdaptor();
+
+ when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.PAUSED);
+
+ FeedMedia feedMedia = mock(FeedMedia.class);
+ when(mediaPlayer.getPlayable()).thenReturn(feedMedia);
+ FeedPreferences feedPreferences = mockFeedPreferences(feedMedia, FEED_ID);
+
+ playbackVolumeAdaptor.adaptVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.LIGHT);
+
+ verify(feedPreferences, times(1)).setVolumeReductionSetting(VolumeReductionSetting.LIGHT);
+
+ verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean());
+ verify(mediaPlayer, never()).resume();
+ }
+
+ @Test
+ public void adaptsPreferencesForLoadedFeedMediaIfPlayerStatusIsPrepared() {
+ PlaybackVolumeAdaptor playbackVolumeAdaptor = new PlaybackVolumeAdaptor();
+
+ when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.PREPARED);
+
+ FeedMedia feedMedia = mock(FeedMedia.class);
+ when(mediaPlayer.getPlayable()).thenReturn(feedMedia);
+ FeedPreferences feedPreferences = mockFeedPreferences(feedMedia, FEED_ID);
+
+ playbackVolumeAdaptor.adaptVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.LIGHT);
+
+ verify(feedPreferences, times(1)).setVolumeReductionSetting(VolumeReductionSetting.LIGHT);
+
+ verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean());
+ verify(mediaPlayer, never()).resume();
+ }
+
+ @Test
+ public void adaptsPreferencesForLoadedFeedMediaIfPlayerStatusIsInitializing() {
+ PlaybackVolumeAdaptor playbackVolumeAdaptor = new PlaybackVolumeAdaptor();
+
+ when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.INITIALIZING);
+
+ FeedMedia feedMedia = mock(FeedMedia.class);
+ when(mediaPlayer.getPlayable()).thenReturn(feedMedia);
+ FeedPreferences feedPreferences = mockFeedPreferences(feedMedia, FEED_ID);
+
+ playbackVolumeAdaptor.adaptVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.LIGHT);
+
+ verify(feedPreferences, times(1)).setVolumeReductionSetting(VolumeReductionSetting.LIGHT);
+
+ verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean());
+ verify(mediaPlayer, never()).resume();
+ }
+
+ @Test
+ public void adaptsPreferencesForLoadedFeedMediaIfPlayerStatusIsPreparing() {
+ PlaybackVolumeAdaptor playbackVolumeAdaptor = new PlaybackVolumeAdaptor();
+
+ when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.PREPARING);
+
+ FeedMedia feedMedia = mock(FeedMedia.class);
+ when(mediaPlayer.getPlayable()).thenReturn(feedMedia);
+ FeedPreferences feedPreferences = mockFeedPreferences(feedMedia, FEED_ID);
+
+ playbackVolumeAdaptor.adaptVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.LIGHT);
+
+ verify(feedPreferences, times(1)).setVolumeReductionSetting(VolumeReductionSetting.LIGHT);
+
+ verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean());
+ verify(mediaPlayer, never()).resume();
+ }
+
+ @Test
+ public void adaptsPreferencesForLoadedFeedMediaIfPlayerStatusIsSeeking() {
+ PlaybackVolumeAdaptor playbackVolumeAdaptor = new PlaybackVolumeAdaptor();
+
+ when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.SEEKING);
+
+ FeedMedia feedMedia = mock(FeedMedia.class);
+ when(mediaPlayer.getPlayable()).thenReturn(feedMedia);
+ FeedPreferences feedPreferences = mockFeedPreferences(feedMedia, FEED_ID);
+
+ playbackVolumeAdaptor.adaptVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.LIGHT);
+
+ verify(feedPreferences, times(1)).setVolumeReductionSetting(VolumeReductionSetting.LIGHT);
+
+ verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean());
+ verify(mediaPlayer, never()).resume();
+ }
+
+ @Test
+ public void adaptsPreferencesAndForcesVolumeChangeForLoadedFeedMediaIfPlayerStatusIsPlaying() {
+ PlaybackVolumeAdaptor playbackVolumeAdaptor = new PlaybackVolumeAdaptor();
+
+ when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.PLAYING);
+
+ FeedMedia feedMedia = mock(FeedMedia.class);
+ when(mediaPlayer.getPlayable()).thenReturn(feedMedia);
+ FeedPreferences feedPreferences = mockFeedPreferences(feedMedia, FEED_ID);
+
+ playbackVolumeAdaptor.adaptVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.HEAVY);
+
+ verify(feedPreferences, times(1)).setVolumeReductionSetting(VolumeReductionSetting.HEAVY);
+
+ verify(mediaPlayer, times(1)).pause(false, false);
+ verify(mediaPlayer, times(1)).resume();
+ }
+
+ private FeedPreferences mockFeedPreferences(FeedMedia feedMedia, String feedId) {
+ Feed feed = mockFeed(feedMedia, feedId);
+ FeedPreferences feedPreferences = mock(FeedPreferences.class);
+ when(feed.getPreferences()).thenReturn(feedPreferences);
+ return feedPreferences;
+ }
+
+ private Feed mockFeed(FeedMedia feedMedia, String feedId) {
+ FeedItem feedItem = mock(FeedItem.class);
+ when(feedMedia.getItem()).thenReturn(feedItem);
+ Feed feed = mock(Feed.class);
+ when(feed.getIdentifyingValue()).thenReturn(feedId);
+ when(feedItem.getFeed()).thenReturn(feed);
+ return feed;
+ }
+}