diff options
Diffstat (limited to 'core')
13 files changed, 471 insertions, 11 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java b/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java index 6a7c97b7b..61a09565f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java @@ -160,7 +160,7 @@ public class Feed extends FeedFile implements ImageResource { */ public Feed(String url, String lastUpdate, String title, String username, String password) { this(url, lastUpdate, title); - preferences = new FeedPreferences(0, true, FeedPreferences.AutoDeleteAction.GLOBAL, username, password); + preferences = new FeedPreferences(0, true, FeedPreferences.AutoDeleteAction.GLOBAL, VolumeReductionSetting.OFF, username, password); } public static Feed fromCursor(Cursor cursor) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java index 8fdf2034f..cb5a59a3b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java @@ -28,19 +28,23 @@ public class FeedPreferences { NO } private AutoDeleteAction auto_delete_action; + + private VolumeReductionSetting volumeReductionSetting; + private String username; private String password; private float feedPlaybackSpeed; - public FeedPreferences(long feedID, boolean autoDownload, AutoDeleteAction auto_delete_action, String username, String password) { - this(feedID, autoDownload, true, auto_delete_action, username, password, new FeedFilter(), SPEED_USE_GLOBAL); + public FeedPreferences(long feedID, boolean autoDownload, AutoDeleteAction auto_delete_action, VolumeReductionSetting volumeReductionSetting, String username, String password) { + this(feedID, autoDownload, true, auto_delete_action, volumeReductionSetting, username, password, new FeedFilter(), SPEED_USE_GLOBAL); } - private FeedPreferences(long feedID, boolean autoDownload, boolean keepUpdated, AutoDeleteAction auto_delete_action, String username, String password, @NonNull FeedFilter filter, float feedPlaybackSpeed) { + private FeedPreferences(long feedID, boolean autoDownload, boolean keepUpdated, AutoDeleteAction auto_delete_action, VolumeReductionSetting volumeReductionSetting, String username, String password, @NonNull FeedFilter filter, float feedPlaybackSpeed) { this.feedID = feedID; this.autoDownload = autoDownload; this.keepUpdated = keepUpdated; this.auto_delete_action = auto_delete_action; + this.volumeReductionSetting = volumeReductionSetting; this.username = username; this.password = password; this.filter = filter; @@ -52,6 +56,7 @@ public class FeedPreferences { int indexAutoDownload = cursor.getColumnIndex(PodDBAdapter.KEY_AUTO_DOWNLOAD); int indexAutoRefresh = cursor.getColumnIndex(PodDBAdapter.KEY_KEEP_UPDATED); int indexAutoDeleteAction = cursor.getColumnIndex(PodDBAdapter.KEY_AUTO_DELETE_ACTION); + int indexVolumeReduction = cursor.getColumnIndex(PodDBAdapter.KEY_FEED_VOLUME_REDUCTION); int indexUsername = cursor.getColumnIndex(PodDBAdapter.KEY_USERNAME); int indexPassword = cursor.getColumnIndex(PodDBAdapter.KEY_PASSWORD); int indexIncludeFilter = cursor.getColumnIndex(PodDBAdapter.KEY_INCLUDE_FILTER); @@ -63,12 +68,14 @@ public class FeedPreferences { boolean autoRefresh = cursor.getInt(indexAutoRefresh) > 0; int autoDeleteActionIndex = cursor.getInt(indexAutoDeleteAction); AutoDeleteAction autoDeleteAction = AutoDeleteAction.values()[autoDeleteActionIndex]; + int volumeReductionValue = cursor.getInt(indexVolumeReduction); + VolumeReductionSetting volumeReductionSetting = VolumeReductionSetting.fromInteger(volumeReductionValue); String username = cursor.getString(indexUsername); String password = cursor.getString(indexPassword); String includeFilter = cursor.getString(indexIncludeFilter); String excludeFilter = cursor.getString(indexExcludeFilter); float feedPlaybackSpeed = cursor.getFloat(indexFeedPlaybackSpeed); - return new FeedPreferences(feedId, autoDownload, autoRefresh, autoDeleteAction, username, password, new FeedFilter(includeFilter, excludeFilter), feedPlaybackSpeed); + return new FeedPreferences(feedId, autoDownload, autoRefresh, autoDeleteAction, volumeReductionSetting, username, password, new FeedFilter(includeFilter, excludeFilter), feedPlaybackSpeed); } /** @@ -144,10 +151,18 @@ public class FeedPreferences { return auto_delete_action; } + public VolumeReductionSetting getVolumeReductionSetting() { + return volumeReductionSetting; + } + public void setAutoDeleteAction(AutoDeleteAction auto_delete_action) { this.auto_delete_action = auto_delete_action; } + public void setVolumeReductionSetting(VolumeReductionSetting volumeReductionSetting) { + this.volumeReductionSetting = volumeReductionSetting; + } + public boolean getCurrentAutoDelete() { switch (auto_delete_action) { case GLOBAL: diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/VolumeReductionSetting.java b/core/src/main/java/de/danoeh/antennapod/core/feed/VolumeReductionSetting.java new file mode 100644 index 000000000..53808580a --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/VolumeReductionSetting.java @@ -0,0 +1,32 @@ +package de.danoeh.antennapod.core.feed; + +public enum VolumeReductionSetting { + OFF(0, 1.0f), + LIGHT(1, 0.5f), + HEAVY(2, 0.2f); + + private final int value; + private float reductionFactor; + + VolumeReductionSetting(int value, float reductionFactor) { + this.value = value; + this.reductionFactor = reductionFactor; + } + + public static VolumeReductionSetting fromInteger(int value) { + for (VolumeReductionSetting setting : values()) { + if (setting.value == value) { + return setting; + } + } + throw new IllegalArgumentException("Cannot map value to VolumeReductionSetting: " + value); + } + + public int toInteger() { + return value; + } + + public float getReductionFactor() { + return reductionFactor; + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java index 296046031..b6e5de254 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java @@ -21,6 +21,7 @@ import android.util.Log; import android.util.Pair; import android.webkit.URLUtil; +import de.danoeh.antennapod.core.feed.VolumeReductionSetting; import org.apache.commons.io.FileUtils; import org.greenrobot.eventbus.EventBus; import org.xml.sax.SAXException; @@ -809,7 +810,7 @@ public class DownloadService extends Service { feed.setId(request.getFeedfileId()); feed.setDownloaded(true); feed.setPreferences(new FeedPreferences(0, true, FeedPreferences.AutoDeleteAction.GLOBAL, - request.getUsername(), request.getPassword())); + VolumeReductionSetting.OFF, request.getUsername(), request.getPassword())); feed.setPageNr(request.getArguments().getInt(DownloadRequester.REQUEST_ARG_PAGE_NR, 0)); DownloadError reason = null; diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java index 1584d29d2..8ac2721b6 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java @@ -12,11 +12,11 @@ import android.util.Log; import android.util.Pair; import android.view.SurfaceHolder; -import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter; import org.antennapod.audio.MediaPlayer; import java.io.File; import java.io.IOException; +import java.util.EnumSet; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; @@ -26,13 +26,17 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; +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.preferences.PlaybackSpeedHelper; +import de.danoeh.antennapod.core.feed.VolumeReductionSetting; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.util.RewindAfterPauseUtils; import de.danoeh.antennapod.core.util.playback.AudioPlayer; import de.danoeh.antennapod.core.util.playback.IPlayer; import de.danoeh.antennapod.core.util.playback.Playable; +import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter; import de.danoeh.antennapod.core.util.playback.VideoPlayer; /** @@ -308,7 +312,10 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { acquireWifiLockIfNecessary(); setPlaybackParams(PlaybackSpeedHelper.getCurrentPlaybackSpeed(media), UserPreferences.isSkipSilence()); - setVolume(UserPreferences.getLeftVolume(), UserPreferences.getRightVolume()); + + float leftVolume = UserPreferences.getLeftVolume(); + float rightVolume = UserPreferences.getRightVolume(); + setVolume(leftVolume, rightVolume); if (playerStatus == PlayerStatus.PREPARED && media.getPosition() > 0) { int newPosition = RewindAfterPauseUtils.calculatePositionWithRewind( @@ -661,8 +668,19 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { */ private void setVolumeSync(float volumeLeft, float volumeRight) { playerLock.lock(); - mediaPlayer.setVolume(volumeLeft, volumeRight); - Log.d(TAG, "Media player volume was set to " + volumeLeft + " " + volumeRight); + if (media != null && EnumSet.of(MediaType.AUDIO, MediaType.VIDEO).contains(media.getMediaType())) { + Playable playable = getPlayable(); + if (playable instanceof FeedMedia) { + FeedMedia feedMedia = (FeedMedia) playable; + FeedPreferences preferences = feedMedia.getItem().getFeed().getPreferences(); + VolumeReductionSetting volumeReductionSetting = preferences.getVolumeReductionSetting(); + float reductionFactor = volumeReductionSetting.getReductionFactor(); + volumeLeft *= reductionFactor; + volumeRight *= reductionFactor; + } + mediaPlayer.setVolume(volumeLeft, volumeRight); + Log.d(TAG, "Media player volume was set to " + volumeLeft + " " + volumeRight); + } playerLock.unlock(); } 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 5002fb913..eb38a02d9 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 @@ -42,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; import java.util.concurrent.TimeUnit; @@ -57,6 +58,7 @@ import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.MediaType; import de.danoeh.antennapod.core.feed.SearchResult; +import de.danoeh.antennapod.core.feed.VolumeReductionSetting; import de.danoeh.antennapod.core.glide.ApGlideSettings; import de.danoeh.antennapod.core.preferences.PlaybackPreferences; import de.danoeh.antennapod.core.preferences.SleepTimerPreferences; @@ -83,6 +85,7 @@ import org.greenrobot.eventbus.EventBus; * Controls the MediaPlayer that plays a FeedMedia-file */ public class PlaybackService extends MediaBrowserServiceCompat { + /** * Logging tag */ @@ -135,6 +138,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. @@ -283,6 +292,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); @@ -1450,6 +1460,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); + VolumeReductionSetting volumeReductionSetting = (VolumeReductionSetting) volumeReductionExtra; + + PlaybackVolumeUpdater playbackVolumeUpdater = new PlaybackVolumeUpdater(); + playbackVolumeUpdater.updateVolumeIfNecessary(mediaPlayer, affectedFeed, volumeReductionSetting); + } + } + }; + public static MediaType getCurrentMediaType() { return currentMediaType; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackVolumeUpdater.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackVolumeUpdater.java new file mode 100644 index 000000000..aff742105 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackVolumeUpdater.java @@ -0,0 +1,50 @@ +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.feed.VolumeReductionSetting; +import de.danoeh.antennapod.core.util.playback.Playable; + +class PlaybackVolumeUpdater { + + public void updateVolumeIfNecessary(PlaybackServiceMediaPlayer mediaPlayer, String affectedFeedIdentifier, VolumeReductionSetting volumeReductionSetting) { + Playable playable = mediaPlayer.getPlayable(); + boolean isFeedMedia = playable instanceof FeedMedia; + boolean isPlayableLoaded = isPlayableLoaded(mediaPlayer.getPlayerStatus()); + + if (isFeedMedia && isPlayableLoaded) { + updateFeedMediaVolumeIfNecessary(mediaPlayer, affectedFeedIdentifier, volumeReductionSetting, (FeedMedia) playable); + } + } + + private void updateFeedMediaVolumeIfNecessary(PlaybackServiceMediaPlayer mediaPlayer, String affectedFeedIdentifier, VolumeReductionSetting volumeReductionSetting, FeedMedia feedMedia) { + if (mediaBelongsToAffectedFeed(feedMedia, affectedFeedIdentifier)) { + FeedPreferences preferences = feedMedia.getItem().getFeed().getPreferences(); + preferences.setVolumeReductionSetting(volumeReductionSetting); + + if (mediaPlayer.getPlayerStatus() == PlayerStatus.PLAYING) { + forceUpdateVolume(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 void forceUpdateVolume(PlaybackServiceMediaPlayer mediaPlayer) { + mediaPlayer.pause(false, false); + mediaPlayer.resume(); + } + +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java index 575b8d2ac..148252902 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java @@ -293,6 +293,9 @@ class DBUpgrader { if (oldVersion < 1070400) { db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " + PodDBAdapter.KEY_FEED_PLAYBACK_SPEED + " REAL DEFAULT " + SPEED_USE_GLOBAL); + + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + + " ADD COLUMN " + PodDBAdapter.KEY_FEED_VOLUME_REDUCTION + " INTEGER DEFAULT 0"); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java index 66f6d223d..fa72cd510 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java @@ -95,6 +95,7 @@ public class PodDBAdapter { public static final String KEY_AUTO_DOWNLOAD = "auto_download"; public static final String KEY_KEEP_UPDATED = "keep_updated"; public static final String KEY_AUTO_DELETE_ACTION = "auto_delete_action"; + public static final String KEY_FEED_VOLUME_REDUCTION = "feed_volume_reduction"; public static final String KEY_PLAYED_DURATION = "played_duration"; public static final String KEY_USERNAME = "username"; public static final String KEY_PASSWORD = "password"; @@ -140,7 +141,8 @@ public class PodDBAdapter { + KEY_HIDE + " TEXT," + KEY_LAST_UPDATE_FAILED + " INTEGER DEFAULT 0," + KEY_AUTO_DELETE_ACTION + " INTEGER DEFAULT 0," - + KEY_FEED_PLAYBACK_SPEED + " REAL DEFAULT " + SPEED_USE_GLOBAL + ")"; + + KEY_FEED_PLAYBACK_SPEED + " REAL DEFAULT " + SPEED_USE_GLOBAL + "," + + KEY_FEED_VOLUME_REDUCTION + " INTEGER DEFAULT 0)"; private static final String CREATE_TABLE_FEED_ITEMS = "CREATE TABLE " + TABLE_NAME_FEED_ITEMS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE @@ -236,6 +238,7 @@ public class PodDBAdapter { TABLE_NAME_FEEDS + "." + KEY_HIDE, TABLE_NAME_FEEDS + "." + KEY_LAST_UPDATE_FAILED, TABLE_NAME_FEEDS + "." + KEY_AUTO_DELETE_ACTION, + TABLE_NAME_FEEDS + "." + KEY_FEED_VOLUME_REDUCTION, TABLE_NAME_FEEDS + "." + KEY_INCLUDE_FILTER, TABLE_NAME_FEEDS + "." + KEY_EXCLUDE_FILTER, TABLE_NAME_FEEDS + "." + KEY_FEED_PLAYBACK_SPEED @@ -399,6 +402,7 @@ public class PodDBAdapter { values.put(KEY_AUTO_DOWNLOAD, prefs.getAutoDownload()); values.put(KEY_KEEP_UPDATED, prefs.getKeepUpdated()); values.put(KEY_AUTO_DELETE_ACTION, prefs.getAutoDeleteAction().ordinal()); + values.put(KEY_FEED_VOLUME_REDUCTION, prefs.getVolumeReductionSetting().toInteger()); values.put(KEY_USERNAME, prefs.getUsername()); values.put(KEY_PASSWORD, prefs.getPassword()); values.put(KEY_INCLUDE_FILTER, prefs.getFilter().getIncludeFilter()); diff --git a/core/src/main/res/values/arrays.xml b/core/src/main/res/values/arrays.xml index 5e7eab1ea..795d06d8d 100644 --- a/core/src/main/res/values/arrays.xml +++ b/core/src/main/res/values/arrays.xml @@ -13,6 +13,18 @@ <item>never</item> </string-array> + <string-array name="spnVolumeReductionItems"> + <item>@string/feed_volume_reduction_off</item> + <item>@string/feed_volume_reduction_light</item> + <item>@string/feed_volume_reduction_heavy</item> + </string-array> + + <string-array name="spnVolumeReductionValues"> + <item>off</item> + <item>light</item> + <item>heavy</item> + </string-array> + <string-array name="smart_mark_as_played_values"> <item>0</item> <item>15</item> diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 5a0267232..c8a22eddb 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -91,6 +91,11 @@ <string name="auto_download_apply_to_items_title">Apply to Previous Episodes</string> <string name="auto_download_apply_to_items_message">The new <i>Auto Download</i> setting will automatically be applied to new episodes.\nDo you also want to apply it to previously published episodes?</string> <string name="auto_delete_label">Auto Delete Episode</string> + <string name="feed_volume_reduction">Volume Reduction</string> + <string name="feed_volume_reduction_summary">Turn down volume for episodes of this feed: \%s</string> + <string name="feed_volume_reduction_off">Off</string> + <string name="feed_volume_reduction_light">Light</string> + <string name="feed_volume_reduction_heavy">Heavy</string> <string name="parallel_downloads_suffix">\u0020parallel downloads</string> <string name="feed_auto_download_global">Global default</string> <string name="feed_auto_download_always">Always</string> diff --git a/core/src/test/java/de/danoeh/antennapod/core/feed/VolumeReductionSettingTest.java b/core/src/test/java/de/danoeh/antennapod/core/feed/VolumeReductionSettingTest.java new file mode 100644 index 000000000..a97fb6f20 --- /dev/null +++ b/core/src/test/java/de/danoeh/antennapod/core/feed/VolumeReductionSettingTest.java @@ -0,0 +1,64 @@ +package de.danoeh.antennapod.core.feed; + +import org.junit.Test; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +public class VolumeReductionSettingTest { + + @Test + public void mapOffToInteger() { + VolumeReductionSetting setting = VolumeReductionSetting.OFF; + assertThat(setting.toInteger(), is(equalTo(0))); + } + + @Test + public void mapLightToInteger() { + VolumeReductionSetting setting = VolumeReductionSetting.LIGHT; + + assertThat(setting.toInteger(), is(equalTo(1))); + } + + @Test + public void mapHeavyToInteger() { + VolumeReductionSetting setting = VolumeReductionSetting.HEAVY; + + assertThat(setting.toInteger(), is(equalTo(2))); + } + + @Test + public void mapIntegerToVolumeReductionSetting() { + assertThat(VolumeReductionSetting.fromInteger(0), is(equalTo(VolumeReductionSetting.OFF))); + assertThat(VolumeReductionSetting.fromInteger(1), is(equalTo(VolumeReductionSetting.LIGHT))); + assertThat(VolumeReductionSetting.fromInteger(2), is(equalTo(VolumeReductionSetting.HEAVY))); + } + + @Test(expected = IllegalArgumentException.class) + public void cannotMapNegativeValues() { + VolumeReductionSetting.fromInteger(-1); + } + + @Test(expected = IllegalArgumentException.class) + public void cannotMapValuesOutOfRange() { + VolumeReductionSetting.fromInteger(3); + } + + @Test + public void noReductionIfTurnedOff() { + float reductionFactor = VolumeReductionSetting.OFF.getReductionFactor(); + assertEquals(1.0f, reductionFactor, 0.01f); + } + + @Test + public void lightReductionYieldsHigherValueThanHeavyReduction() { + float lightReductionFactor = VolumeReductionSetting.LIGHT.getReductionFactor(); + + float heavyReductionFactor = VolumeReductionSetting.HEAVY.getReductionFactor(); + + assertTrue("Light reduction must have higher factor than heavy reduction", lightReductionFactor > heavyReductionFactor); + } +}
\ No newline at end of file diff --git a/core/src/test/java/de/danoeh/antennapod/core/service/playback/PlaybackVolumeUpdaterTest.java b/core/src/test/java/de/danoeh/antennapod/core/service/playback/PlaybackVolumeUpdaterTest.java new file mode 100644 index 000000000..4ebe4e5ba --- /dev/null +++ b/core/src/test/java/de/danoeh/antennapod/core/service/playback/PlaybackVolumeUpdaterTest.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.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 PlaybackVolumeUpdaterTest { + + private static final String FEED_ID = "feedId"; + + private PlaybackServiceMediaPlayer mediaPlayer; + + @Before + public void setUp() throws Exception { + mediaPlayer = mock(PlaybackServiceMediaPlayer.class); + } + + @Test + public void noChangeIfNoFeedMediaPlaying() { + PlaybackVolumeUpdater playbackVolumeUpdater = new PlaybackVolumeUpdater(); + + when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.PAUSED); + + Playable noFeedMedia = mock(Playable.class); + when(mediaPlayer.getPlayable()).thenReturn(noFeedMedia); + + playbackVolumeUpdater.updateVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.OFF); + + verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean()); + verify(mediaPlayer, never()).resume(); + } + + @Test + public void noChangeIfPlayerStatusIsError() { + PlaybackVolumeUpdater playbackVolumeUpdater = new PlaybackVolumeUpdater(); + + when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.ERROR); + + FeedMedia feedMedia = mock(FeedMedia.class); + when(mediaPlayer.getPlayable()).thenReturn(feedMedia); + + playbackVolumeUpdater.updateVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.OFF); + + verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean()); + verify(mediaPlayer, never()).resume(); + } + + @Test + public void noChangeIfPlayerStatusIsIndeterminate() { + PlaybackVolumeUpdater playbackVolumeUpdater = new PlaybackVolumeUpdater(); + + when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.INDETERMINATE); + + FeedMedia feedMedia = mock(FeedMedia.class); + when(mediaPlayer.getPlayable()).thenReturn(feedMedia); + + playbackVolumeUpdater.updateVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.OFF); + + verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean()); + verify(mediaPlayer, never()).resume(); + } + + @Test + public void noChangeIfPlayerStatusIsStopped() { + PlaybackVolumeUpdater playbackVolumeUpdater = new PlaybackVolumeUpdater(); + + when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.STOPPED); + + FeedMedia feedMedia = mock(FeedMedia.class); + when(mediaPlayer.getPlayable()).thenReturn(feedMedia); + + playbackVolumeUpdater.updateVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.OFF); + + verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean()); + verify(mediaPlayer, never()).resume(); + } + + @Test + public void noChangeIfPlayableIsNoItemOfAffectedFeed() { + PlaybackVolumeUpdater playbackVolumeUpdater = new PlaybackVolumeUpdater(); + + 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"); + + playbackVolumeUpdater.updateVolumeIfNecessary(mediaPlayer, FEED_ID, VolumeReductionSetting.OFF); + + verify(mediaPlayer, never()).pause(anyBoolean(), anyBoolean()); + verify(mediaPlayer, never()).resume(); + } + + @Test + public void updatesPreferencesForLoadedFeedMediaIfPlayerStatusIsPaused() { + PlaybackVolumeUpdater playbackVolumeUpdater = new PlaybackVolumeUpdater(); + + when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.PAUSED); + + FeedMedia feedMedia = mock(FeedMedia.class); + when(mediaPlayer.getPlayable()).thenReturn(feedMedia); + FeedPreferences feedPreferences = mockFeedPreferences(feedMedia, FEED_ID); + + playbackVolumeUpdater.updateVolumeIfNecessary(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 updatesPreferencesForLoadedFeedMediaIfPlayerStatusIsPrepared() { + PlaybackVolumeUpdater playbackVolumeUpdater = new PlaybackVolumeUpdater(); + + when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.PREPARED); + + FeedMedia feedMedia = mock(FeedMedia.class); + when(mediaPlayer.getPlayable()).thenReturn(feedMedia); + FeedPreferences feedPreferences = mockFeedPreferences(feedMedia, FEED_ID); + + playbackVolumeUpdater.updateVolumeIfNecessary(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 updatesPreferencesForLoadedFeedMediaIfPlayerStatusIsInitializing() { + PlaybackVolumeUpdater playbackVolumeUpdater = new PlaybackVolumeUpdater(); + + when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.INITIALIZING); + + FeedMedia feedMedia = mock(FeedMedia.class); + when(mediaPlayer.getPlayable()).thenReturn(feedMedia); + FeedPreferences feedPreferences = mockFeedPreferences(feedMedia, FEED_ID); + + playbackVolumeUpdater.updateVolumeIfNecessary(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 updatesPreferencesForLoadedFeedMediaIfPlayerStatusIsPreparing() { + PlaybackVolumeUpdater playbackVolumeUpdater = new PlaybackVolumeUpdater(); + + when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.PREPARING); + + FeedMedia feedMedia = mock(FeedMedia.class); + when(mediaPlayer.getPlayable()).thenReturn(feedMedia); + FeedPreferences feedPreferences = mockFeedPreferences(feedMedia, FEED_ID); + + playbackVolumeUpdater.updateVolumeIfNecessary(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 updatesPreferencesForLoadedFeedMediaIfPlayerStatusIsSeeking() { + PlaybackVolumeUpdater playbackVolumeUpdater = new PlaybackVolumeUpdater(); + + when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.SEEKING); + + FeedMedia feedMedia = mock(FeedMedia.class); + when(mediaPlayer.getPlayable()).thenReturn(feedMedia); + FeedPreferences feedPreferences = mockFeedPreferences(feedMedia, FEED_ID); + + playbackVolumeUpdater.updateVolumeIfNecessary(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 updatesPreferencesAndForcesVolumeChangeForLoadedFeedMediaIfPlayerStatusIsPlaying() { + PlaybackVolumeUpdater playbackVolumeUpdater = new PlaybackVolumeUpdater(); + + when(mediaPlayer.getPlayerStatus()).thenReturn(PlayerStatus.PLAYING); + + FeedMedia feedMedia = mock(FeedMedia.class); + when(mediaPlayer.getPlayable()).thenReturn(feedMedia); + FeedPreferences feedPreferences = mockFeedPreferences(feedMedia, FEED_ID); + + playbackVolumeUpdater.updateVolumeIfNecessary(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; + } +} |