summaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'app/src')
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java135
-rw-r--r--app/src/main/AndroidManifest.xml11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java647
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/CastEnabledActivity.java237
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java83
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java26
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java130
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java620
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java18
-rw-r--r--app/src/main/res/layout/external_player_fragment.xml24
-rw-r--r--app/src/main/res/layout/mediaplayerinfo_activity.xml (renamed from app/src/main/res/layout/audioplayer_activity.xml)15
-rw-r--r--app/src/main/res/menu/cast_enabled.xml10
-rw-r--r--app/src/main/res/xml/preferences.xml9
20 files changed, 1246 insertions, 759 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
index 7dac89e9b..195dccdda 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
@@ -21,13 +21,14 @@ 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.service.playback.PlaybackServiceMediaPlayer;
+import de.danoeh.antennapod.core.service.playback.LocalPSMP;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.test.antennapod.util.service.download.HTTPBin;
/**
- * Test class for PlaybackServiceMediaPlayer
+ * Test class for LocalPSMP
*/
public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
private static final String TAG = "PlaybackServiceMediaPlayerTest";
@@ -85,7 +86,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
assertEquals(0, httpServer.serveFile(dest));
}
- private void checkPSMPInfo(PlaybackServiceMediaPlayer.PSMPInfo info) {
+ private void checkPSMPInfo(LocalPSMP.PSMPInfo info) {
try {
switch (info.playerStatus) {
case PLAYING:
@@ -111,7 +112,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
public void testInit() {
final Context c = getInstrumentation().getTargetContext();
- PlaybackServiceMediaPlayer psmp = new PlaybackServiceMediaPlayer(c, defaultCallback);
+ PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, defaultCallback);
psmp.shutdown();
}
@@ -139,7 +140,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
final CountDownLatch countDownLatch = new CountDownLatch(2);
PlaybackServiceMediaPlayer.PSMPCallback callback = new PlaybackServiceMediaPlayer.PSMPCallback() {
@Override
- public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
+ public void statusChanged(LocalPSMP.PSMPInfo newInfo) {
try {
checkPSMPInfo(newInfo);
if (newInfo.playerStatus == PlayerStatus.ERROR)
@@ -175,7 +176,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public void updateMediaSessionMetadata(Playable p) {
+ public void reloadUI() {
}
@@ -185,7 +186,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean onMediaPlayerInfo(int code) {
+ public boolean onMediaPlayerInfo(int code, int resourceId) {
return false;
}
@@ -195,12 +196,12 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped) {
+ public boolean endPlayback(Playable p, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
return false;
}
};
- PlaybackServiceMediaPlayer psmp = new PlaybackServiceMediaPlayer(c, callback);
+ PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, null);
psmp.playMediaObject(p, true, false, false);
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
@@ -218,7 +219,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
final CountDownLatch countDownLatch = new CountDownLatch(2);
PlaybackServiceMediaPlayer.PSMPCallback callback = new PlaybackServiceMediaPlayer.PSMPCallback() {
@Override
- public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
+ public void statusChanged(LocalPSMP.PSMPInfo newInfo) {
try {
checkPSMPInfo(newInfo);
if (newInfo.playerStatus == PlayerStatus.ERROR)
@@ -254,7 +255,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public void updateMediaSessionMetadata(Playable p) {
+ public void reloadUI() {
}
@@ -264,7 +265,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean onMediaPlayerInfo(int code) {
+ public boolean onMediaPlayerInfo(int code, int resourceId) {
return false;
}
@@ -274,11 +275,11 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped) {
+ public boolean endPlayback(Playable p, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
return false;
}
};
- PlaybackServiceMediaPlayer psmp = new PlaybackServiceMediaPlayer(c, callback);
+ PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, null);
psmp.playMediaObject(p, true, true, false);
@@ -297,7 +298,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
final CountDownLatch countDownLatch = new CountDownLatch(4);
PlaybackServiceMediaPlayer.PSMPCallback callback = new PlaybackServiceMediaPlayer.PSMPCallback() {
@Override
- public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
+ public void statusChanged(LocalPSMP.PSMPInfo newInfo) {
try {
checkPSMPInfo(newInfo);
if (newInfo.playerStatus == PlayerStatus.ERROR)
@@ -336,7 +337,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public void updateMediaSessionMetadata(Playable p) {
+ public void reloadUI() {
}
@@ -346,7 +347,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean onMediaPlayerInfo(int code) {
+ public boolean onMediaPlayerInfo(int code, int resourceId) {
return false;
}
@@ -356,11 +357,11 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped) {
+ public boolean endPlayback(Playable p, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
return false;
}
};
- PlaybackServiceMediaPlayer psmp = new PlaybackServiceMediaPlayer(c, callback);
+ PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, null);
psmp.playMediaObject(p, true, false, true);
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
@@ -377,7 +378,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
final CountDownLatch countDownLatch = new CountDownLatch(5);
PlaybackServiceMediaPlayer.PSMPCallback callback = new PlaybackServiceMediaPlayer.PSMPCallback() {
@Override
- public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
+ public void statusChanged(LocalPSMP.PSMPInfo newInfo) {
try {
checkPSMPInfo(newInfo);
if (newInfo.playerStatus == PlayerStatus.ERROR)
@@ -419,7 +420,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public void updateMediaSessionMetadata(Playable p) {
+ public void reloadUI() {
}
@@ -429,7 +430,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean onMediaPlayerInfo(int code) {
+ public boolean onMediaPlayerInfo(int code, int resourceId) {
return false;
}
@@ -439,12 +440,12 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped) {
+ public boolean endPlayback(Playable p, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
return false;
}
};
- PlaybackServiceMediaPlayer psmp = new PlaybackServiceMediaPlayer(c, callback);
+ PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, null);
psmp.playMediaObject(p, true, true, true);
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
@@ -460,7 +461,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
final CountDownLatch countDownLatch = new CountDownLatch(2);
PlaybackServiceMediaPlayer.PSMPCallback callback = new PlaybackServiceMediaPlayer.PSMPCallback() {
@Override
- public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
+ public void statusChanged(LocalPSMP.PSMPInfo newInfo) {
try {
checkPSMPInfo(newInfo);
if (newInfo.playerStatus == PlayerStatus.ERROR)
@@ -496,7 +497,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public void updateMediaSessionMetadata(Playable p) {
+ public void reloadUI() {
}
@@ -506,7 +507,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean onMediaPlayerInfo(int code) {
+ public boolean onMediaPlayerInfo(int code, int resourceId) {
return false;
}
@@ -516,12 +517,12 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped) {
+ public boolean endPlayback(Playable p, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
return false;
}
};
- PlaybackServiceMediaPlayer psmp = new PlaybackServiceMediaPlayer(c, callback);
+ PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL);
psmp.playMediaObject(p, false, false, false);
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
@@ -538,7 +539,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
final CountDownLatch countDownLatch = new CountDownLatch(2);
PlaybackServiceMediaPlayer.PSMPCallback callback = new PlaybackServiceMediaPlayer.PSMPCallback() {
@Override
- public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
+ public void statusChanged(LocalPSMP.PSMPInfo newInfo) {
try {
checkPSMPInfo(newInfo);
if (newInfo.playerStatus == PlayerStatus.ERROR)
@@ -574,7 +575,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public void updateMediaSessionMetadata(Playable p) {
+ public void reloadUI() {
}
@@ -584,7 +585,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean onMediaPlayerInfo(int code) {
+ public boolean onMediaPlayerInfo(int code, int resourceId) {
return false;
}
@@ -594,11 +595,11 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped) {
+ public boolean endPlayback(Playable p, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
return false;
}
};
- PlaybackServiceMediaPlayer psmp = new PlaybackServiceMediaPlayer(c, callback);
+ PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL);
psmp.playMediaObject(p, false, true, false);
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
@@ -615,7 +616,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
final CountDownLatch countDownLatch = new CountDownLatch(4);
PlaybackServiceMediaPlayer.PSMPCallback callback = new PlaybackServiceMediaPlayer.PSMPCallback() {
@Override
- public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
+ public void statusChanged(LocalPSMP.PSMPInfo newInfo) {
try {
checkPSMPInfo(newInfo);
if (newInfo.playerStatus == PlayerStatus.ERROR)
@@ -654,7 +655,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public void updateMediaSessionMetadata(Playable p) {
+ public void reloadUI() {
}
@@ -664,7 +665,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean onMediaPlayerInfo(int code) {
+ public boolean onMediaPlayerInfo(int code, int resourceId) {
return false;
}
@@ -674,11 +675,11 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped) {
+ public boolean endPlayback(Playable p, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
return false;
}
};
- PlaybackServiceMediaPlayer psmp = new PlaybackServiceMediaPlayer(c, callback);
+ PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL);
psmp.playMediaObject(p, false, false, true);
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
@@ -694,7 +695,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
final CountDownLatch countDownLatch = new CountDownLatch(5);
PlaybackServiceMediaPlayer.PSMPCallback callback = new PlaybackServiceMediaPlayer.PSMPCallback() {
@Override
- public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
+ public void statusChanged(LocalPSMP.PSMPInfo newInfo) {
try {
checkPSMPInfo(newInfo);
if (newInfo.playerStatus == PlayerStatus.ERROR)
@@ -737,7 +738,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public void updateMediaSessionMetadata(Playable p) {
+ public void reloadUI() {
}
@@ -747,7 +748,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean onMediaPlayerInfo(int code) {
+ public boolean onMediaPlayerInfo(int code, int resourceId) {
return false;
}
@@ -757,11 +758,11 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped) {
+ public boolean endPlayback(Playable p, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
return false;
}
};
- PlaybackServiceMediaPlayer psmp = new PlaybackServiceMediaPlayer(c, callback);
+ PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL);
psmp.playMediaObject(p, false, true, true);
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
@@ -775,7 +776,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
private final PlaybackServiceMediaPlayer.PSMPCallback defaultCallback = new PlaybackServiceMediaPlayer.PSMPCallback() {
@Override
- public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
+ public void statusChanged(LocalPSMP.PSMPInfo newInfo) {
checkPSMPInfo(newInfo);
}
@@ -795,7 +796,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public void updateMediaSessionMetadata(Playable p) {
+ public void reloadUI() {
}
@@ -805,7 +806,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean onMediaPlayerInfo(int code) { return false; }
+ public boolean onMediaPlayerInfo(int code, int resourceId) { return false; }
@Override
public boolean onMediaPlayerError(Object inObj, int what, int extra) {
@@ -813,7 +814,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped) {
+ public boolean endPlayback(Playable p, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
return false;
}
};
@@ -825,7 +826,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
PlaybackServiceMediaPlayer.PSMPCallback callback = new PlaybackServiceMediaPlayer.PSMPCallback() {
@Override
- public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
+ public void statusChanged(LocalPSMP.PSMPInfo newInfo) {
checkPSMPInfo(newInfo);
if (newInfo.playerStatus == PlayerStatus.ERROR) {
if (assertionError == null)
@@ -873,7 +874,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public void updateMediaSessionMetadata(Playable p) {
+ public void reloadUI() {
}
@@ -883,7 +884,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean onMediaPlayerInfo(int code) {
+ public boolean onMediaPlayerInfo(int code, int resourceId) {
return false;
}
@@ -895,11 +896,11 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped) {
+ public boolean endPlayback(Playable p, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
return false;
}
};
- PlaybackServiceMediaPlayer psmp = new PlaybackServiceMediaPlayer(c, callback);
+ PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL);
if (initialState == PlayerStatus.PLAYING) {
psmp.playMediaObject(p, stream, true, true);
@@ -956,7 +957,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
PlaybackServiceMediaPlayer.PSMPCallback callback = new PlaybackServiceMediaPlayer.PSMPCallback() {
@Override
- public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
+ public void statusChanged(LocalPSMP.PSMPInfo newInfo) {
checkPSMPInfo(newInfo);
if (newInfo.playerStatus == PlayerStatus.ERROR) {
if (assertionError == null)
@@ -988,7 +989,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public void updateMediaSessionMetadata(Playable p) {
+ public void reloadUI() {
}
@@ -998,7 +999,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean onMediaPlayerInfo(int code) {
+ public boolean onMediaPlayerInfo(int code, int resourceId) {
return false;
}
@@ -1011,11 +1012,11 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped) {
+ public boolean endPlayback(Playable p, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
return false;
}
};
- PlaybackServiceMediaPlayer psmp = new PlaybackServiceMediaPlayer(c, callback);
+ PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
if (initialState == PlayerStatus.PREPARED || initialState == PlayerStatus.PLAYING || initialState == PlayerStatus.PAUSED) {
boolean startWhenPrepared = (initialState != PlayerStatus.PREPARED);
psmp.playMediaObject(writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL), false, startWhenPrepared, true);
@@ -1049,7 +1050,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
final CountDownLatch countDownLatch = new CountDownLatch(latchCount);
PlaybackServiceMediaPlayer.PSMPCallback callback = new PlaybackServiceMediaPlayer.PSMPCallback() {
@Override
- public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
+ public void statusChanged(LocalPSMP.PSMPInfo newInfo) {
checkPSMPInfo(newInfo);
if (newInfo.playerStatus == PlayerStatus.ERROR) {
if (assertionError == null)
@@ -1080,7 +1081,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public void updateMediaSessionMetadata(Playable p) {
+ public void reloadUI() {
}
@@ -1090,7 +1091,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean onMediaPlayerInfo(int code) {
+ public boolean onMediaPlayerInfo(int code, int resourceId) {
return false;
}
@@ -1102,11 +1103,11 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped) {
+ public boolean endPlayback(Playable p, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
return false;
}
};
- PlaybackServiceMediaPlayer psmp = new PlaybackServiceMediaPlayer(c, callback);
+ PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL);
if (initialState == PlayerStatus.INITIALIZED
|| initialState == PlayerStatus.PLAYING
@@ -1154,7 +1155,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
final CountDownLatch countDownLatch = new CountDownLatch(latchCount);
PlaybackServiceMediaPlayer.PSMPCallback callback = new PlaybackServiceMediaPlayer.PSMPCallback() {
@Override
- public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
+ public void statusChanged(LocalPSMP.PSMPInfo newInfo) {
checkPSMPInfo(newInfo);
if (newInfo.playerStatus == PlayerStatus.ERROR) {
if (assertionError == null)
@@ -1184,7 +1185,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public void updateMediaSessionMetadata(Playable p) {
+ public void reloadUI() {
}
@@ -1194,7 +1195,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean onMediaPlayerInfo(int code) {
+ public boolean onMediaPlayerInfo(int code, int resourceId) {
return false;
}
@@ -1206,11 +1207,11 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
- public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped) {
+ public boolean endPlayback(Playable p, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
return false;
}
};
- PlaybackServiceMediaPlayer psmp = new PlaybackServiceMediaPlayer(c, callback);
+ PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL);
boolean prepareImmediately = initialState != PlayerStatus.INITIALIZED;
boolean startImmediately = initialState != PlayerStatus.PREPARED;
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 005ba604f..65c9f8ec4 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -41,6 +41,10 @@
android:name="com.google.android.backup.api_key"
android:value="AEdPqrEAAAAI3a05VToCTlqBymJrbFGaKQMvF-bBAuLsOdavBA"/>
+ <meta-data
+ android:name="com.google.android.gms.version"
+ android:value="@integer/google_play_services_version" />
+
<activity
android:name=".activity.MainActivity"
android:configChanges="keyboardHidden|orientation"
@@ -67,6 +71,13 @@
<data android:mimeType="audio/*"/>
</intent-filter>
</activity>
+ <activity
+ android:name=".activity.CastplayerActivity"
+ android:launchMode="singleTop">
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value="de.danoeh.antennapod.activity.MainActivity"/>
+ </activity>
<activity
android:name=".activity.DownloadAuthenticationActivity"
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
index 292f3d9b6..ca214de9e 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -1,166 +1,27 @@
package de.danoeh.antennapod.activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.res.Configuration;
-import android.os.Build;
-import android.support.annotation.Nullable;
-import android.support.design.widget.AppBarLayout;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.support.v4.widget.DrawerLayout;
-import android.support.v7.app.ActionBarDrawerToggle;
-import android.support.v7.widget.Toolbar;
+import android.support.v4.view.ViewCompat;
import android.text.TextUtils;
import android.util.Log;
-import android.util.TypedValue;
-import android.view.ContextMenu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import com.viewpagerindicator.CirclePageIndicator;
-
-import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.adapter.ChaptersListAdapter;
-import de.danoeh.antennapod.adapter.NavListAdapter;
-import de.danoeh.antennapod.core.asynctask.FeedRemover;
-import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
-import de.danoeh.antennapod.core.feed.EventDistributor;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.core.service.playback.PlayerStatus;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
-import de.danoeh.antennapod.core.util.playback.Playable;
-import de.danoeh.antennapod.core.util.playback.PlaybackController;
-import de.danoeh.antennapod.fragment.AddFeedFragment;
-import de.danoeh.antennapod.fragment.ChaptersFragment;
-import de.danoeh.antennapod.fragment.CoverFragment;
-import de.danoeh.antennapod.fragment.DownloadsFragment;
-import de.danoeh.antennapod.fragment.EpisodesFragment;
-import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
-import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
-import de.danoeh.antennapod.fragment.QueueFragment;
-import de.danoeh.antennapod.fragment.SubscriptionFragment;
-import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
-import de.danoeh.antennapod.preferences.PreferenceController;
-import rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import de.danoeh.antennapod.dialog.VariableSpeedDialog;
/**
* Activity for playing audio files.
*/
-public class AudioplayerActivity extends MediaplayerActivity implements NavDrawerActivity {
-
- private static final int POS_COVER = 0;
- private static final int POS_DESCR = 1;
- private static final int POS_CHAPTERS = 2;
- private static final int NUM_CONTENT_FRAGMENTS = 3;
-
- final String TAG = "AudioplayerActivity";
- private static final String PREFS = "AudioPlayerActivityPreferences";
- private static final String PREF_KEY_SELECTED_FRAGMENT_POSITION = "selectedFragmentPosition";
-
- public static final String[] NAV_DRAWER_TAGS = {
- QueueFragment.TAG,
- EpisodesFragment.TAG,
- SubscriptionFragment.TAG,
- DownloadsFragment.TAG,
- PlaybackHistoryFragment.TAG,
- AddFeedFragment.TAG,
- NavListAdapter.SUBSCRIPTION_LIST_TAG
- };
+public class AudioplayerActivity extends MediaplayerInfoActivity {
+ public static final String TAG = "AudioPlayerActivity";
private AtomicBoolean isSetup = new AtomicBoolean(false);
- private DrawerLayout drawerLayout;
- private NavListAdapter navAdapter;
- private ListView navList;
- private View navDrawer;
- private ActionBarDrawerToggle drawerToggle;
- private int mPosition = -1;
-
- private Playable media;
- private ViewPager pager;
- private AudioplayerPagerAdapter pagerAdapter;
-
- private Subscription subscription;
-
- @Override
- protected void onStop() {
- super.onStop();
- Log.d(TAG, "onStop()");
- if(pagerAdapter != null) {
- pagerAdapter.setController(null);
- }
- if(subscription != null) {
- subscription.unsubscribe();
- }
- EventDistributor.getInstance().unregister(contentUpdate);
- saveCurrentFragment();
- }
-
- @Override
- public void onDestroy() {
- Log.d(TAG, "onDestroy()");
- super.onDestroy();
- // don't risk creating memory leaks
- drawerLayout = null;
- navAdapter = null;
- navList = null;
- navDrawer = null;
- drawerToggle = null;
- pager = null;
- pagerAdapter = null;
- }
-
- @Override
- protected void chooseTheme() {
- setTheme(UserPreferences.getNoTitleTheme());
- }
-
- private void saveCurrentFragment() {
- if(pager == null) {
- return;
- }
- Log.d(TAG, "Saving preferences");
- SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
- prefs.edit()
- .putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, pager.getCurrentItem())
- .commit();
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- if(drawerToggle != null) {
- drawerToggle.onConfigurationChanged(newConfig);
- }
- }
-
- private void loadLastFragment() {
- Log.d(TAG, "Restoring instance state");
- SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
- int lastPosition = prefs.getInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, -1);
- pager.setCurrentItem(lastPosition);
- }
-
@Override
protected void onResume() {
super.onResume();
@@ -177,456 +38,116 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY,
true);
startService(launchIntent);
+ } else if (PlaybackService.isCasting()) {
+ Intent intent = PlaybackService.getPlayerActivityIntent(this);
+ if (!intent.getComponent().getClassName().equals(AudioplayerActivity.class.getName())) {
+ saveCurrentFragment();
+ finish();
+ startActivity(intent);
+ }
}
- if(pagerAdapter != null && controller != null && controller.getMedia() != media) {
- media = controller.getMedia();
- pagerAdapter.onMediaChanged(media);
- pagerAdapter.setController(controller);
- }
-
- EventDistributor.getInstance().register(contentUpdate);
- loadData();
}
@Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- setIntent(intent);
- }
-
- @Override
- protected void onAwaitingVideoSurface() {
- Log.d(TAG, "onAwaitingVideoSurface was called in audio player -> switching to video player");
- startActivity(new Intent(this, VideoplayerActivity.class));
- }
+ protected void onReloadNotification(int notificationCode) {
+ if (notificationCode == PlaybackService.EXTRA_CODE_CAST) {
+ Log.d(TAG, "ReloadNotification received, switching to Castplayer now");
+ saveCurrentFragment();
+ finish();
+ startActivity(new Intent(this, CastplayerActivity.class));
- @Override
- protected void postStatusMsg(int resId) {
- if (resId == R.string.player_preparing_msg
- || resId == R.string.player_seeking_msg
- || resId == R.string.player_buffering_msg) {
- // TODO Show progress bar here
+ } else {
+ super.onReloadNotification(notificationCode);
}
}
@Override
- protected void clearStatusMsg() {
- // TODO Hide progress bar here
- }
-
-
- @Override
- protected void setupGUI() {
- if(isSetup.getAndSet(true)) {
+ protected void updatePlaybackSpeedButton() {
+ if(butPlaybackSpeed == null) {
return;
}
- super.setupGUI();
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- getSupportActionBar().setTitle("");
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- findViewById(R.id.shadow).setVisibility(View.GONE);
- AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appBar);
- float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources().getDisplayMetrics());
- appBarLayout.setElevation(px);
+ if (controller == null) {
+ butPlaybackSpeed.setVisibility(View.GONE);
+ return;
}
- drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
- navList = (ListView) findViewById(R.id.nav_list);
- navDrawer = findViewById(R.id.nav_layout);
-
- drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close);
- drawerToggle.setDrawerIndicatorEnabled(false);
- drawerLayout.setDrawerListener(drawerToggle);
-
- navAdapter = new NavListAdapter(itemAccess, this);
- navList.setAdapter(navAdapter);
- navList.setOnItemClickListener((parent, view, position, id) -> {
- int viewType = parent.getAdapter().getItemViewType(position);
- if (viewType != NavListAdapter.VIEW_TYPE_SECTION_DIVIDER) {
- Intent intent = new Intent(AudioplayerActivity.this, MainActivity.class);
- intent.putExtra(MainActivity.EXTRA_NAV_TYPE, viewType);
- intent.putExtra(MainActivity.EXTRA_NAV_INDEX, position);
- startActivity(intent);
- }
- drawerLayout.closeDrawer(navDrawer);
- });
- navList.setOnItemLongClickListener((parent, view, position, id) -> {
- if (position < navAdapter.getTags().size()) {
- showDrawerPreferencesDialog();
- return true;
- } else {
- mPosition = position;
- return false;
- }
- });
- registerForContextMenu(navList);
- drawerToggle.syncState();
-
- findViewById(R.id.nav_settings).setOnClickListener(v -> {
- drawerLayout.closeDrawer(navDrawer);
- startActivity(new Intent(AudioplayerActivity.this, PreferenceController.getPreferenceActivity()));
- });
-
- pager = (ViewPager) findViewById(R.id.pager);
- pagerAdapter = new AudioplayerPagerAdapter(getSupportFragmentManager(), media);
- pagerAdapter.setController(controller);
- pager.setAdapter(pagerAdapter);
- CirclePageIndicator pageIndicator = (CirclePageIndicator) findViewById(R.id.page_indicator);
- pageIndicator.setViewPager(pager);
- loadLastFragment();
- pager.onSaveInstanceState();
- }
-
- @Override
- protected void onPositionObserverUpdate() {
- super.onPositionObserverUpdate();
- notifyMediaPositionChanged();
+ updatePlaybackSpeedButtonText();
+ ViewCompat.setAlpha(butPlaybackSpeed, controller.canSetPlaybackSpeed() ? 1.0f : 0.5f);
+ butPlaybackSpeed.setVisibility(View.VISIBLE);
}
@Override
- protected boolean loadMediaInfo() {
- if (!super.loadMediaInfo()) {
- return false;
- }
- if(controller.getMedia() != media) {
- media = controller.getMedia();
- pagerAdapter.onMediaChanged(media);
+ protected void updatePlaybackSpeedButtonText() {
+ if(butPlaybackSpeed == null) {
+ return;
}
- return true;
- }
-
- public void notifyMediaPositionChanged() {
- if(pagerAdapter == null) {
+ if (controller == null) {
+ butPlaybackSpeed.setVisibility(View.GONE);
return;
}
- ChaptersFragment chaptersFragment = pagerAdapter.getChaptersFragment();
- if(chaptersFragment != null) {
- ChaptersListAdapter adapter = (ChaptersListAdapter) chaptersFragment.getListAdapter();
- if (adapter != null) {
- adapter.notifyDataSetChanged();
+ float speed = 1.0f;
+ if(controller.canSetPlaybackSpeed()) {
+ try {
+ // we can only retrieve the playback speed from the controller/playback service
+ // once mediaplayer has been initialized
+ speed = Float.parseFloat(UserPreferences.getPlaybackSpeed());
+ } catch (NumberFormatException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ UserPreferences.setPlaybackSpeed(String.valueOf(speed));
}
}
+ String speedStr = String.format("%.2fx", speed);
+ butPlaybackSpeed.setText(speedStr);
}
@Override
- protected void onReloadNotification(int notificationCode) {
- if (notificationCode == PlaybackService.EXTRA_CODE_VIDEO) {
- Log.d(TAG, "ReloadNotification received, switching to Videoplayer now");
- finish();
- startActivity(new Intent(this, VideoplayerActivity.class));
-
- }
- }
-
- @Override
- protected void onBufferStart() {
- postStatusMsg(R.string.player_buffering_msg);
- }
-
- @Override
- protected void onBufferEnd() {
- clearStatusMsg();
- }
-
- public PlaybackController getPlaybackController() {
- return controller;
- }
-
- @Override
- public boolean isDrawerOpen() {
- return drawerLayout != null && navDrawer != null && drawerLayout.isDrawerOpen(navDrawer);
- }
-
- @Override
- protected int getContentViewResourceId() {
- return R.layout.audioplayer_activity;
- }
-
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- return drawerToggle != null && drawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, v, menuInfo);
- if(v.getId() != R.id.nav_list) {
- return;
- }
- AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
- int position = adapterInfo.position;
- if(position < navAdapter.getSubscriptionOffset()) {
+ protected void setupGUI() {
+ if(isSetup.getAndSet(true)) {
return;
}
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.nav_feed_context, menu);
- Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
- menu.setHeaderTitle(feed.getTitle());
- // episodes are not loaded, so we cannot check if the podcast has new or unplayed ones!
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- final int position = mPosition;
- mPosition = -1; // reset
- if(position < 0) {
- return false;
- }
- Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
- switch(item.getItemId()) {
- case R.id.mark_all_seen_item:
- DBWriter.markFeedSeen(feed.getId());
- return true;
- case R.id.mark_all_read_item:
- DBWriter.markFeedRead(feed.getId());
- return true;
- case R.id.remove_item:
- final FeedRemover remover = new FeedRemover(this, feed) {
- @Override
- protected void onPostExecute(Void result) {
- super.onPostExecute(result);
+ super.setupGUI();
+ if(butCastDisconnect != null) {
+ butCastDisconnect.setVisibility(View.GONE);
+ }
+ if(butPlaybackSpeed != null) {
+ butPlaybackSpeed.setOnClickListener(v -> {
+ if (controller == null) {
+ return;
+ }
+ if (controller.canSetPlaybackSpeed()) {
+ String[] availableSpeeds = UserPreferences.getPlaybackSpeedArray();
+ String currentSpeed = UserPreferences.getPlaybackSpeed();
+
+ // Provide initial value in case the speed list has changed
+ // out from under us
+ // and our current speed isn't in the new list
+ String newSpeed;
+ if (availableSpeeds.length > 0) {
+ newSpeed = availableSpeeds[0];
+ } else {
+ newSpeed = "1.00";
}
- };
- ConfirmationDialog conDialog = new ConfirmationDialog(this,
- R.string.remove_feed_label,
- R.string.feed_delete_confirmation_msg) {
- @Override
- public void onConfirmButtonPressed(
- DialogInterface dialog) {
- dialog.dismiss();
- if (controller != null) {
- Playable playable = controller.getMedia();
- if (playable != null && playable instanceof FeedMedia) {
- FeedMedia media = (FeedMedia) playable;
- if (media.getItem().getFeed().getId() == feed.getId()) {
- Log.d(TAG, "Currently playing episode is about to be deleted, skipping");
- remover.skipOnCompletion = true;
- if(controller.getStatus() == PlayerStatus.PLAYING) {
- sendBroadcast(new Intent(
- PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE));
- }
- }
+
+ for (int i = 0; i < availableSpeeds.length; i++) {
+ if (availableSpeeds[i].equals(currentSpeed)) {
+ if (i == availableSpeeds.length - 1) {
+ newSpeed = availableSpeeds[0];
+ } else {
+ newSpeed = availableSpeeds[i + 1];
}
+ break;
}
- remover.executeAsync();
}
- };
- conDialog.createNewDialog().show();
+ UserPreferences.setPlaybackSpeed(newSpeed);
+ controller.setPlaybackSpeed(Float.parseFloat(newSpeed));
+ } else {
+ VariableSpeedDialog.showGetPluginDialog(this);
+ }
+ });
+ butPlaybackSpeed.setOnLongClickListener(v -> {
+ VariableSpeedDialog.showDialog(this);
return true;
- default:
- return super.onContextItemSelected(item);
+ });
+ butPlaybackSpeed.setVisibility(View.VISIBLE);
}
}
-
- @Override
- public void onBackPressed() {
- if(isDrawerOpen()) {
- drawerLayout.closeDrawer(navDrawer);
- } else if (pager == null || pager.getCurrentItem() == 0) {
- // If the user is currently looking at the first step, allow the system to handle the
- // Back button. This calls finish() on this activity and pops the back stack.
- super.onBackPressed();
- } else {
- // Otherwise, select the previous step.
- pager.setCurrentItem(pager.getCurrentItem() - 1);
- }
- }
-
- public void showDrawerPreferencesDialog() {
- final List<String> hiddenDrawerItems = UserPreferences.getHiddenDrawerItems();
- String[] navLabels = new String[NAV_DRAWER_TAGS.length];
- final boolean[] checked = new boolean[NAV_DRAWER_TAGS.length];
- for (int i = 0; i < NAV_DRAWER_TAGS.length; i++) {
- String tag = NAV_DRAWER_TAGS[i];
- navLabels[i] = navAdapter.getLabel(tag);
- if (!hiddenDrawerItems.contains(tag)) {
- checked[i] = true;
- }
- }
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.drawer_preferences);
- builder.setMultiChoiceItems(navLabels, checked, (dialog, which, isChecked) -> {
- if (isChecked) {
- hiddenDrawerItems.remove(NAV_DRAWER_TAGS[which]);
- } else {
- hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]);
- }
- });
- builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
- UserPreferences.setHiddenDrawerItems(hiddenDrawerItems);
- });
- builder.setNegativeButton(R.string.cancel_label, null);
- builder.create().show();
- }
-
- private DBReader.NavDrawerData navDrawerData;
-
- private void loadData() {
- subscription = Observable.fromCallable(DBReader::getNavDrawerData)
- .subscribeOn(Schedulers.newThread())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> {
- navDrawerData = result;
- if (navAdapter != null) {
- navAdapter.notifyDataSetChanged();
- }
- }, error -> {
- Log.e(TAG, Log.getStackTraceString(error));
- });
- }
-
-
-
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
-
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((EventDistributor.FEED_LIST_UPDATE & arg) != 0) {
- Log.d(TAG, "Received contentUpdate Intent.");
- loadData();
- }
- }
- };
-
- private final NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() {
- @Override
- public int getCount() {
- if (navDrawerData != null) {
- return navDrawerData.feeds.size();
- } else {
- return 0;
- }
- }
-
- @Override
- public Feed getItem(int position) {
- if (navDrawerData != null && 0 <= position && position < navDrawerData.feeds.size()) {
- return navDrawerData.feeds.get(position);
- } else {
- return null;
- }
- }
-
- @Override
- public int getSelectedItemIndex() {
- return -1;
- }
-
- @Override
- public int getQueueSize() {
- return (navDrawerData != null) ? navDrawerData.queueSize : 0;
- }
-
- @Override
- public int getNumberOfNewItems() {
- return (navDrawerData != null) ? navDrawerData.numNewItems : 0;
- }
-
- @Override
- public int getNumberOfDownloadedItems() {
- return (navDrawerData != null) ? navDrawerData.numDownloadedItems : 0;
- }
-
- @Override
- public int getReclaimableItems() {
- return (navDrawerData != null) ? navDrawerData.reclaimableSpace : 0;
- }
-
- @Override
- public int getFeedCounter(long feedId) {
- return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0;
- }
-
- @Override
- public int getFeedCounterSum() {
- if(navDrawerData == null) {
- return 0;
- }
- int sum = 0;
- for(int counter : navDrawerData.feedCounters.values()) {
- sum += counter;
- }
- return sum;
- }
- };
-
- public interface AudioplayerContentFragment {
- void onMediaChanged(Playable media);
- }
-
- private static class AudioplayerPagerAdapter extends FragmentStatePagerAdapter {
-
- private static final String TAG = "AudioplayerPagerAdapter";
-
- private Playable media;
- private PlaybackController controller;
-
- public AudioplayerPagerAdapter(FragmentManager fm, Playable media) {
- super(fm);
- this.media = media;
- }
-
- private CoverFragment coverFragment;
- private ItemDescriptionFragment itemDescriptionFragment;
- private ChaptersFragment chaptersFragment;
-
- public void onMediaChanged(Playable media) {
- this.media = media;
- if(coverFragment != null) {
- coverFragment.onMediaChanged(media);
- }
- if(itemDescriptionFragment != null) {
- itemDescriptionFragment.onMediaChanged(media);
- }
- if(chaptersFragment != null) {
- chaptersFragment.onMediaChanged(media);
- }
- }
-
- public void setController(PlaybackController controller) {
- this.controller = controller;
- if(chaptersFragment != null) {
- chaptersFragment.setController(controller);
- }
- }
-
- @Nullable
- public ChaptersFragment getChaptersFragment() {
- return chaptersFragment;
- }
-
- @Override
- public Fragment getItem(int position) {
- Log.d(TAG, "getItem(" + position + ")");
- switch (position) {
- case POS_COVER:
- if(coverFragment == null) {
- coverFragment = CoverFragment.newInstance(media);
- }
- return coverFragment;
- case POS_DESCR:
- if(itemDescriptionFragment == null) {
- itemDescriptionFragment = ItemDescriptionFragment.newInstance(media, true, true);
- }
- return itemDescriptionFragment;
- case POS_CHAPTERS:
- if(chaptersFragment == null) {
- chaptersFragment = ChaptersFragment.newInstance(media);
- chaptersFragment.setController(controller);
- }
- return chaptersFragment;
- default:
- return null;
- }
- }
-
- @Override
- public int getCount() {
- return NUM_CONTENT_FRAGMENTS;
- }
- }
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/CastEnabledActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/CastEnabledActivity.java
new file mode 100644
index 000000000..b8856c295
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/activity/CastEnabledActivity.java
@@ -0,0 +1,237 @@
+package de.danoeh.antennapod.activity;
+
+import android.content.SharedPreferences;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.annotation.CallSuper;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.google.android.gms.cast.ApplicationMetadata;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.cast.CastConsumer;
+import de.danoeh.antennapod.core.cast.CastManager;
+import de.danoeh.antennapod.core.cast.DefaultCastConsumer;
+import de.danoeh.antennapod.core.cast.SwitchableMediaRouteActionProvider;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.service.playback.PlaybackService;
+
+/**
+ * Activity that allows for showing the MediaRouter button whenever there's a cast device in the
+ * network.
+ */
+public abstract class CastEnabledActivity extends AppCompatActivity
+ implements SharedPreferences.OnSharedPreferenceChangeListener {
+ public static final String TAG = "CastEnabledActivity";
+
+ protected CastManager castManager;
+ protected SwitchableMediaRouteActionProvider mediaRouteActionProvider;
+ private final CastButtonVisibilityManager castButtonVisibilityManager = new CastButtonVisibilityManager();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).
+ registerOnSharedPreferenceChangeListener(this);
+
+ castManager = CastManager.getInstance();
+ castManager.addCastConsumer(castConsumer);
+ castButtonVisibilityManager.setPrefEnabled(UserPreferences.isCastEnabled());
+ onCastConnectionChanged(castManager.isConnected());
+ }
+
+ @Override
+ protected void onDestroy() {
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
+ .unregisterOnSharedPreferenceChangeListener(this);
+ castManager.removeCastConsumer(castConsumer);
+ super.onDestroy();
+ }
+
+ @Override
+ @CallSuper
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ getMenuInflater().inflate(R.menu.cast_enabled, menu);
+ castButtonVisibilityManager.setMenu(menu);
+ return true;
+ }
+
+ @Override
+ @CallSuper
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ mediaRouteActionProvider = castManager
+ .addMediaRouterButton(menu.findItem(R.id.media_route_menu_item));
+ mediaRouteActionProvider.setEnabled(castButtonVisibilityManager.shouldEnable());
+ return true;
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ castButtonVisibilityManager.setResumed(true);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ castButtonVisibilityManager.setResumed(false);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (UserPreferences.PREF_CAST_ENABLED.equals(key)) {
+ boolean newValue = UserPreferences.isCastEnabled();
+ Log.d(TAG, "onSharedPreferenceChanged(), isCastEnabled set to " + newValue);
+ castButtonVisibilityManager.setPrefEnabled(newValue);
+ // PlaybackService has its own listener, so if it's active we don't have to take action here.
+ if (!newValue && !PlaybackService.isRunning) {
+ CastManager.getInstance().disconnect();
+ }
+ }
+ }
+
+ CastConsumer castConsumer = new DefaultCastConsumer() {
+ @Override
+ public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) {
+ onCastConnectionChanged(true);
+ }
+
+ @Override
+ public void onDisconnected() {
+ onCastConnectionChanged(false);
+ }
+ };
+
+ private void onCastConnectionChanged(boolean connected) {
+ if (connected) {
+ castButtonVisibilityManager.onConnected();
+ setVolumeControlStream(AudioManager.USE_DEFAULT_STREAM_TYPE);
+ } else {
+ castButtonVisibilityManager.onDisconnected();
+ setVolumeControlStream(AudioManager.STREAM_MUSIC);
+ }
+ }
+
+ /**
+ * Should be called by any activity or fragment for which the cast button should be shown.
+ *
+ * @param showAsAction refer to {@link MenuItem#setShowAsAction(int)}
+ */
+ public final void requestCastButton(int showAsAction) {
+ castButtonVisibilityManager.requestCastButton(showAsAction);
+ }
+
+ private class CastButtonVisibilityManager {
+ private volatile boolean prefEnabled = false;
+ private volatile boolean viewRequested = false;
+ private volatile boolean resumed = false;
+ private volatile boolean connected = false;
+ private volatile int showAsAction = MenuItem.SHOW_AS_ACTION_IF_ROOM;
+ private Menu menu;
+
+ public synchronized void setPrefEnabled(boolean newValue) {
+ if (prefEnabled != newValue && resumed && (viewRequested || connected)) {
+ if (newValue) {
+ castManager.incrementUiCounter();
+ } else {
+ castManager.decrementUiCounter();
+ }
+ }
+ prefEnabled = newValue;
+ if (mediaRouteActionProvider != null) {
+ mediaRouteActionProvider.setEnabled(prefEnabled && (viewRequested || connected));
+ }
+ }
+
+ public synchronized void setResumed(boolean newValue) {
+ if (resumed == newValue) {
+ Log.e(TAG, "resumed should never change to the same value");
+ return;
+ }
+ resumed = newValue;
+ if (prefEnabled && (viewRequested || connected)) {
+ if (resumed) {
+ castManager.incrementUiCounter();
+ } else {
+ castManager.decrementUiCounter();
+ }
+ }
+ }
+
+ public synchronized void setViewRequested(boolean newValue) {
+ if (viewRequested != newValue && resumed && prefEnabled && !connected) {
+ if (newValue) {
+ castManager.incrementUiCounter();
+ } else {
+ castManager.decrementUiCounter();
+ }
+ }
+ viewRequested = newValue;
+ if (mediaRouteActionProvider != null) {
+ mediaRouteActionProvider.setEnabled(prefEnabled && (viewRequested || connected));
+ }
+ }
+
+ public synchronized void setConnected(boolean newValue) {
+ if (connected != newValue && resumed && prefEnabled && !prefEnabled) {
+ if (newValue) {
+ castManager.incrementUiCounter();
+ } else {
+ castManager.decrementUiCounter();
+ }
+ }
+ connected = newValue;
+ if (mediaRouteActionProvider != null) {
+ mediaRouteActionProvider.setEnabled(prefEnabled && (viewRequested || connected));
+ }
+ }
+
+ public synchronized boolean shouldEnable() {
+ return prefEnabled && viewRequested;
+ }
+
+ public void setMenu(Menu menu) {
+ setViewRequested(false);
+ showAsAction = MenuItem.SHOW_AS_ACTION_IF_ROOM;
+ this.menu = menu;
+ setShowAsAction();
+ }
+
+ public void requestCastButton(int showAsAction) {
+ setViewRequested(true);
+ this.showAsAction = showAsAction;
+ setShowAsAction();
+ }
+
+ public void onConnected() {
+ setConnected(true);
+ setShowAsAction();
+ }
+
+ public void onDisconnected() {
+ setConnected(false);
+ setShowAsAction();
+ }
+
+ private void setShowAsAction() {
+ if (menu == null) {
+ Log.d(TAG, "setShowAsAction() without a menu");
+ return;
+ }
+ MenuItem item = menu.findItem(R.id.media_route_menu_item);
+ if (item == null) {
+ Log.e(TAG, "setShowAsAction(), but cast button not inflated");
+ return;
+ }
+ MenuItemCompat.setShowAsAction(item, connected? MenuItem.SHOW_AS_ACTION_ALWAYS : showAsAction);
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java
new file mode 100644
index 000000000..1ca4d095f
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java
@@ -0,0 +1,83 @@
+package de.danoeh.antennapod.activity;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import de.danoeh.antennapod.core.service.playback.PlaybackService;
+
+/**
+ * Activity for controlling the remote playback on a Cast device.
+ */
+public class CastplayerActivity extends MediaplayerInfoActivity {
+ public static final String TAG = "CastPlayerActivity";
+
+ private AtomicBoolean isSetup = new AtomicBoolean(false);
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (!PlaybackService.isCasting()) {
+ Intent intent = PlaybackService.getPlayerActivityIntent(this);
+ if (!intent.getComponent().getClassName().equals(CastplayerActivity.class.getName())) {
+ finish();
+ startActivity(intent);
+ }
+ }
+ }
+
+ @Override
+ protected void onReloadNotification(int notificationCode) {
+ if (notificationCode == PlaybackService.EXTRA_CODE_AUDIO) {
+ Log.d(TAG, "ReloadNotification received, switching to Audioplayer now");
+ saveCurrentFragment();
+ finish();
+ startActivity(new Intent(this, AudioplayerActivity.class));
+ } else {
+ super.onReloadNotification(notificationCode);
+ }
+ }
+
+ @Override
+ protected void setupGUI() {
+ if(isSetup.getAndSet(true)) {
+ return;
+ }
+ super.setupGUI();
+ if (butPlaybackSpeed != null) {
+ butPlaybackSpeed.setVisibility(View.GONE);
+ }
+ if (butCastDisconnect != null) {
+ butCastDisconnect.setOnClickListener(v -> castManager.disconnect());
+ butCastDisconnect.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ if (!PlaybackService.isCasting()) {
+ Intent intent = PlaybackService.getPlayerActivityIntent(this);
+ if (!intent.getComponent().getClassName().equals(CastplayerActivity.class.getName())) {
+ saveCurrentFragment();
+ finish();
+ startActivity(intent);
+ }
+ }
+ super.onResume();
+ }
+
+ @Override
+ protected void onBufferStart() {
+ //sbPosition.setIndeterminate(true);
+ sbPosition.setEnabled(false);
+ }
+
+ @Override
+ protected void onBufferEnd() {
+ //sbPosition.setIndeterminate(false);
+ sbPosition.setEnabled(true);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
index 8599eb4f4..b7c7d86c7 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -7,7 +7,6 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.database.DataSetObserver;
-import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -17,11 +16,11 @@ import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.util.TypedValue;
import android.view.ContextMenu;
+import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
@@ -70,7 +69,7 @@ import rx.schedulers.Schedulers;
/**
* The activity that is shown when the user launches the app.
*/
-public class MainActivity extends AppCompatActivity implements NavDrawerActivity {
+public class MainActivity extends CastEnabledActivity implements NavDrawerActivity {
private static final String TAG = "MainActivity";
@@ -123,7 +122,6 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity
super.onCreate(savedInstanceState);
StorageUtils.checkStorageAvailability(this);
setContentView(R.layout.main);
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
@@ -507,6 +505,26 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity
}
@Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ boolean retVal = super.onCreateOptionsMenu(menu);
+ switch (getLastNavFragment()) {
+ case QueueFragment.TAG:
+ case EpisodesFragment.TAG:
+ requestCastButton(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ return retVal;
+ case DownloadsFragment.TAG:
+ case PlaybackHistoryFragment.TAG:
+ case AddFeedFragment.TAG:
+ case SubscriptionFragment.TAG:
+ return retVal;
+ default:
+ requestCastButton(MenuItem.SHOW_AS_ACTION_NEVER);
+ return retVal;
+ }
+
+ }
+
+ @Override
public boolean onOptionsItemSelected(MenuItem item) {
if (drawerToggle.onOptionsItemSelected(item)) {
return true;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
index 4911f61bc..8ee91c7a3 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -6,13 +6,10 @@ import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PixelFormat;
-import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.support.v4.view.ViewCompat;
import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@@ -58,7 +55,7 @@ import rx.schedulers.Schedulers;
* Provides general features which are both needed for playing audio and video
* files.
*/
-public abstract class MediaplayerActivity extends AppCompatActivity implements OnSeekBarChangeListener {
+public abstract class MediaplayerActivity extends CastEnabledActivity implements OnSeekBarChangeListener {
private static final String TAG = "MediaplayerActivity";
private static final String PREFS = "MediaPlayerActivityPreferences";
private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft";
@@ -68,7 +65,6 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
protected TextView txtvPosition;
protected TextView txtvLength;
protected SeekBar sbPosition;
- protected Button butPlaybackSpeed;
protected ImageButton butRev;
protected TextView txtvRev;
protected ImageButton butPlay;
@@ -129,8 +125,8 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
}
@Override
- public void postStatusMsg(int msg) {
- MediaplayerActivity.this.postStatusMsg(msg);
+ public void postStatusMsg(int msg, boolean showToast) {
+ MediaplayerActivity.this.postStatusMsg(msg, showToast);
}
@Override
@@ -208,7 +204,6 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
Log.d(TAG, "onCreate()");
StorageUtils.checkStorageAvailability(this);
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
orientation = getResources().getConfiguration().orientation;
getWindow().setFormat(PixelFormat.TRANSPARENT);
@@ -286,6 +281,7 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
+ requestCastButton(MenuItem.SHOW_AS_ACTION_ALWAYS);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.mediaplayer, menu);
return true;
@@ -589,7 +585,7 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
*/
protected abstract void onAwaitingVideoSurface();
- protected abstract void postStatusMsg(int resId);
+ protected abstract void postStatusMsg(int resId, boolean showToast);
protected abstract void clearStatusMsg();
@@ -644,40 +640,12 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
}
}
- private void updatePlaybackSpeedButton() {
- if(butPlaybackSpeed == null) {
- return;
- }
- if (controller == null) {
- butPlaybackSpeed.setVisibility(View.GONE);
- return;
- }
- updatePlaybackSpeedButtonText();
- ViewCompat.setAlpha(butPlaybackSpeed, controller.canSetPlaybackSpeed() ? 1.0f : 0.5f);
- butPlaybackSpeed.setVisibility(View.VISIBLE);
+ protected void updatePlaybackSpeedButton() {
+ // Only meaningful on AudioplayerActivity, where it is overridden.
}
- private void updatePlaybackSpeedButtonText() {
- if(butPlaybackSpeed == null) {
- return;
- }
- if (controller == null) {
- butPlaybackSpeed.setVisibility(View.GONE);
- return;
- }
- float speed = 1.0f;
- if(controller.canSetPlaybackSpeed()) {
- try {
- // we can only retrieve the playback speed from the controller/playback service
- // once mediaplayer has been initialized
- speed = Float.parseFloat(UserPreferences.getPlaybackSpeed());
- } catch (NumberFormatException e) {
- Log.e(TAG, Log.getStackTraceString(e));
- UserPreferences.setPlaybackSpeed(String.valueOf(speed));
- }
- }
- String speedStr = String.format("%.2fx", speed);
- butPlaybackSpeed.setText(speedStr);
+ protected void updatePlaybackSpeedButtonText() {
+ // Only meaningful on AudioplayerActivity, where it is overridden.
}
@@ -690,28 +658,29 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false);
Log.d("timeleft", showTimeLeft ? "true" : "false");
txtvLength = (TextView) findViewById(R.id.txtvLength);
- txtvLength.setOnClickListener(v -> {
- showTimeLeft = !showTimeLeft;
- Playable media = controller.getMedia();
- if (media == null) {
- return;
- }
+ if (txtvLength != null) {
+ txtvLength.setOnClickListener(v -> {
+ showTimeLeft = !showTimeLeft;
+ Playable media = controller.getMedia();
+ if (media == null) {
+ return;
+ }
- String length;
- if (showTimeLeft) {
- length = "-" + Converter.getDurationStringLong(media.getDuration() - media.getPosition());
- } else {
- length = Converter.getDurationStringLong(media.getDuration());
- }
- txtvLength.setText(length);
+ String length;
+ if (showTimeLeft) {
+ length = "-" + Converter.getDurationStringLong(media.getDuration() - media.getPosition());
+ } else {
+ length = Converter.getDurationStringLong(media.getDuration());
+ }
+ txtvLength.setText(length);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(PREF_SHOW_TIME_LEFT, showTimeLeft);
- editor.apply();
- Log.d("timeleft on click", showTimeLeft ? "true" : "false");
- });
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(PREF_SHOW_TIME_LEFT, showTimeLeft);
+ editor.apply();
+ Log.d("timeleft on click", showTimeLeft ? "true" : "false");
+ });
+ }
- butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed);
butRev = (ImageButton) findViewById(R.id.butRev);
txtvRev = (TextView) findViewById(R.id.txtvRev);
if (txtvRev != null) {
@@ -731,47 +700,6 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
// BUTTON SETUP
- if(butPlaybackSpeed != null) {
- butPlaybackSpeed.setOnClickListener(v -> {
- if (controller == null) {
- return;
- }
- if (controller.canSetPlaybackSpeed()) {
- String[] availableSpeeds = UserPreferences.getPlaybackSpeedArray();
- String currentSpeed = UserPreferences.getPlaybackSpeed();
-
- // Provide initial value in case the speed list has changed
- // out from under us
- // and our current speed isn't in the new list
- String newSpeed;
- if (availableSpeeds.length > 0) {
- newSpeed = availableSpeeds[0];
- } else {
- newSpeed = "1.00";
- }
-
- for (int i = 0; i < availableSpeeds.length; i++) {
- if (availableSpeeds[i].equals(currentSpeed)) {
- if (i == availableSpeeds.length - 1) {
- newSpeed = availableSpeeds[0];
- } else {
- newSpeed = availableSpeeds[i + 1];
- }
- break;
- }
- }
- UserPreferences.setPlaybackSpeed(newSpeed);
- controller.setPlaybackSpeed(Float.parseFloat(newSpeed));
- } else {
- VariableSpeedDialog.showGetPluginDialog(this);
- }
- });
- butPlaybackSpeed.setOnLongClickListener(v -> {
- VariableSpeedDialog.showDialog(this);
- return true;
- });
- }
-
if (butRev != null) {
butRev.setOnClickListener(v -> onRewind());
butRev.setOnLongClickListener(new View.OnLongClickListener() {
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
new file mode 100644
index 000000000..e966b8cce
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
@@ -0,0 +1,620 @@
+package de.danoeh.antennapod.activity;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.design.widget.AppBarLayout;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentStatePagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v7.app.ActionBarDrawerToggle;
+import android.support.v7.widget.Toolbar;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextMenu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import com.viewpagerindicator.CirclePageIndicator;
+
+import java.util.List;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.adapter.ChaptersListAdapter;
+import de.danoeh.antennapod.adapter.NavListAdapter;
+import de.danoeh.antennapod.core.asynctask.FeedRemover;
+import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
+import de.danoeh.antennapod.core.feed.EventDistributor;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.service.playback.PlaybackService;
+import de.danoeh.antennapod.core.service.playback.PlayerStatus;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.core.util.playback.Playable;
+import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import de.danoeh.antennapod.fragment.AddFeedFragment;
+import de.danoeh.antennapod.fragment.ChaptersFragment;
+import de.danoeh.antennapod.fragment.CoverFragment;
+import de.danoeh.antennapod.fragment.DownloadsFragment;
+import de.danoeh.antennapod.fragment.EpisodesFragment;
+import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
+import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
+import de.danoeh.antennapod.fragment.QueueFragment;
+import de.danoeh.antennapod.fragment.SubscriptionFragment;
+import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
+import de.danoeh.antennapod.preferences.PreferenceController;
+import rx.Observable;
+import rx.Subscription;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.schedulers.Schedulers;
+
+/**
+ * Activity for playing files that do not require a video surface.
+ */
+public abstract class MediaplayerInfoActivity extends MediaplayerActivity implements NavDrawerActivity {
+
+ private static final int POS_COVER = 0;
+ private static final int POS_DESCR = 1;
+ private static final int POS_CHAPTERS = 2;
+ private static final int NUM_CONTENT_FRAGMENTS = 3;
+
+ final String TAG = "MediaplayerInfoActivity";
+ private static final String PREFS = "AudioPlayerActivityPreferences";
+ private static final String PREF_KEY_SELECTED_FRAGMENT_POSITION = "selectedFragmentPosition";
+
+ public static final String[] NAV_DRAWER_TAGS = {
+ QueueFragment.TAG,
+ EpisodesFragment.TAG,
+ SubscriptionFragment.TAG,
+ DownloadsFragment.TAG,
+ PlaybackHistoryFragment.TAG,
+ AddFeedFragment.TAG,
+ NavListAdapter.SUBSCRIPTION_LIST_TAG
+ };
+
+ protected Button butPlaybackSpeed;
+ protected ImageButton butCastDisconnect;
+ private DrawerLayout drawerLayout;
+ private NavListAdapter navAdapter;
+ private ListView navList;
+ private View navDrawer;
+ private ActionBarDrawerToggle drawerToggle;
+ private int mPosition = -1;
+
+ private Playable media;
+ private ViewPager pager;
+ private MediaplayerInfoPagerAdapter pagerAdapter;
+
+ private Subscription subscription;
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ Log.d(TAG, "onStop()");
+ if(pagerAdapter != null) {
+ pagerAdapter.setController(null);
+ }
+ if(subscription != null) {
+ subscription.unsubscribe();
+ }
+ EventDistributor.getInstance().unregister(contentUpdate);
+ saveCurrentFragment();
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.d(TAG, "onDestroy()");
+ super.onDestroy();
+ // don't risk creating memory leaks
+ drawerLayout = null;
+ navAdapter = null;
+ navList = null;
+ navDrawer = null;
+ drawerToggle = null;
+ pager = null;
+ pagerAdapter = null;
+ }
+
+ @Override
+ protected void chooseTheme() {
+ setTheme(UserPreferences.getNoTitleTheme());
+ }
+
+ protected void saveCurrentFragment() {
+ if(pager == null) {
+ return;
+ }
+ Log.d(TAG, "Saving preferences");
+ SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
+ prefs.edit()
+ .putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, pager.getCurrentItem())
+ .commit();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if(drawerToggle != null) {
+ drawerToggle.onConfigurationChanged(newConfig);
+ }
+ }
+
+ private void loadLastFragment() {
+ Log.d(TAG, "Restoring instance state");
+ SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
+ int lastPosition = prefs.getInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, -1);
+ pager.setCurrentItem(lastPosition);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if(pagerAdapter != null && controller != null && controller.getMedia() != media) {
+ media = controller.getMedia();
+ pagerAdapter.onMediaChanged(media);
+ pagerAdapter.setController(controller);
+ }
+
+ EventDistributor.getInstance().register(contentUpdate);
+ loadData();
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
+ }
+
+ @Override
+ protected void onAwaitingVideoSurface() {
+ Log.d(TAG, "onAwaitingVideoSurface was called in audio player -> switching to video player");
+ startActivity(new Intent(this, VideoplayerActivity.class));
+ }
+
+ @Override
+ protected void postStatusMsg(int resId, boolean showToast) {
+ if (resId == R.string.player_preparing_msg
+ || resId == R.string.player_seeking_msg
+ || resId == R.string.player_buffering_msg) {
+ // TODO Show progress bar here
+ }
+ if (showToast) {
+ Toast.makeText(this, resId, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ protected void clearStatusMsg() {
+ // TODO Hide progress bar here
+ }
+
+
+ @Override
+ protected void setupGUI() {
+ super.setupGUI();
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setTitle("");
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ findViewById(R.id.shadow).setVisibility(View.GONE);
+ AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appBar);
+ float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources().getDisplayMetrics());
+ appBarLayout.setElevation(px);
+ }
+ drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+ navList = (ListView) findViewById(R.id.nav_list);
+ navDrawer = findViewById(R.id.nav_layout);
+
+ drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close);
+ drawerToggle.setDrawerIndicatorEnabled(false);
+ drawerLayout.setDrawerListener(drawerToggle);
+
+ navAdapter = new NavListAdapter(itemAccess, this);
+ navList.setAdapter(navAdapter);
+ navList.setOnItemClickListener((parent, view, position, id) -> {
+ int viewType = parent.getAdapter().getItemViewType(position);
+ if (viewType != NavListAdapter.VIEW_TYPE_SECTION_DIVIDER) {
+ Intent intent = new Intent(MediaplayerInfoActivity.this, MainActivity.class);
+ intent.putExtra(MainActivity.EXTRA_NAV_TYPE, viewType);
+ intent.putExtra(MainActivity.EXTRA_NAV_INDEX, position);
+ startActivity(intent);
+ }
+ drawerLayout.closeDrawer(navDrawer);
+ });
+ navList.setOnItemLongClickListener((parent, view, position, id) -> {
+ if (position < navAdapter.getTags().size()) {
+ showDrawerPreferencesDialog();
+ return true;
+ } else {
+ mPosition = position;
+ return false;
+ }
+ });
+ registerForContextMenu(navList);
+ drawerToggle.syncState();
+
+ findViewById(R.id.nav_settings).setOnClickListener(v -> {
+ drawerLayout.closeDrawer(navDrawer);
+ startActivity(new Intent(MediaplayerInfoActivity.this, PreferenceController.getPreferenceActivity()));
+ });
+
+ butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed);
+ butCastDisconnect = (ImageButton) findViewById(R.id.butCastDisconnect);
+
+ pager = (ViewPager) findViewById(R.id.pager);
+ pagerAdapter = new MediaplayerInfoPagerAdapter(getSupportFragmentManager(), media);
+ pagerAdapter.setController(controller);
+ pager.setAdapter(pagerAdapter);
+ CirclePageIndicator pageIndicator = (CirclePageIndicator) findViewById(R.id.page_indicator);
+ pageIndicator.setViewPager(pager);
+ loadLastFragment();
+ pager.onSaveInstanceState();
+ }
+
+ @Override
+ protected void onPositionObserverUpdate() {
+ super.onPositionObserverUpdate();
+ notifyMediaPositionChanged();
+ }
+
+ @Override
+ protected boolean loadMediaInfo() {
+ if (!super.loadMediaInfo()) {
+ return false;
+ }
+ if(controller.getMedia() != media) {
+ media = controller.getMedia();
+ pagerAdapter.onMediaChanged(media);
+ }
+ return true;
+ }
+
+ public void notifyMediaPositionChanged() {
+ if(pagerAdapter == null) {
+ return;
+ }
+ ChaptersFragment chaptersFragment = pagerAdapter.getChaptersFragment();
+ if(chaptersFragment != null) {
+ ChaptersListAdapter adapter = (ChaptersListAdapter) chaptersFragment.getListAdapter();
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+ }
+ }
+
+ @Override
+ protected void onReloadNotification(int notificationCode) {
+ if (notificationCode == PlaybackService.EXTRA_CODE_VIDEO) {
+ Log.d(TAG, "ReloadNotification received, switching to Videoplayer now");
+ finish();
+ startActivity(new Intent(this, VideoplayerActivity.class));
+
+ }
+ }
+
+ @Override
+ protected void onBufferStart() {
+ postStatusMsg(R.string.player_buffering_msg, false);
+ }
+
+ @Override
+ protected void onBufferEnd() {
+ clearStatusMsg();
+ }
+
+ public PlaybackController getPlaybackController() {
+ return controller;
+ }
+
+ @Override
+ public boolean isDrawerOpen() {
+ return drawerLayout != null && navDrawer != null && drawerLayout.isDrawerOpen(navDrawer);
+ }
+
+ @Override
+ protected int getContentViewResourceId() {
+ return R.layout.mediaplayerinfo_activity;
+ }
+
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ return drawerToggle != null && drawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ if(v.getId() != R.id.nav_list) {
+ return;
+ }
+ AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
+ int position = adapterInfo.position;
+ if(position < navAdapter.getSubscriptionOffset()) {
+ return;
+ }
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.nav_feed_context, menu);
+ Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
+ menu.setHeaderTitle(feed.getTitle());
+ // episodes are not loaded, so we cannot check if the podcast has new or unplayed ones!
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final int position = mPosition;
+ mPosition = -1; // reset
+ if(position < 0) {
+ return false;
+ }
+ Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
+ switch(item.getItemId()) {
+ case R.id.mark_all_seen_item:
+ DBWriter.markFeedSeen(feed.getId());
+ return true;
+ case R.id.mark_all_read_item:
+ DBWriter.markFeedRead(feed.getId());
+ return true;
+ case R.id.remove_item:
+ final FeedRemover remover = new FeedRemover(this, feed) {
+ @Override
+ protected void onPostExecute(Void result) {
+ super.onPostExecute(result);
+ }
+ };
+ ConfirmationDialog conDialog = new ConfirmationDialog(this,
+ R.string.remove_feed_label,
+ R.string.feed_delete_confirmation_msg) {
+ @Override
+ public void onConfirmButtonPressed(
+ DialogInterface dialog) {
+ dialog.dismiss();
+ if (controller != null) {
+ Playable playable = controller.getMedia();
+ if (playable != null && playable instanceof FeedMedia) {
+ FeedMedia media = (FeedMedia) playable;
+ if (media.getItem().getFeed().getId() == feed.getId()) {
+ Log.d(TAG, "Currently playing episode is about to be deleted, skipping");
+ remover.skipOnCompletion = true;
+ if(controller.getStatus() == PlayerStatus.PLAYING) {
+ sendBroadcast(new Intent(
+ PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE));
+ }
+ }
+ }
+ }
+ remover.executeAsync();
+ }
+ };
+ conDialog.createNewDialog().show();
+ return true;
+ default:
+ return super.onContextItemSelected(item);
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ if(isDrawerOpen()) {
+ drawerLayout.closeDrawer(navDrawer);
+ } else if (pager == null || pager.getCurrentItem() == 0) {
+ // If the user is currently looking at the first step, allow the system to handle the
+ // Back button. This calls finish() on this activity and pops the back stack.
+ super.onBackPressed();
+ } else {
+ // Otherwise, select the previous step.
+ pager.setCurrentItem(pager.getCurrentItem() - 1);
+ }
+ }
+
+ public void showDrawerPreferencesDialog() {
+ final List<String> hiddenDrawerItems = UserPreferences.getHiddenDrawerItems();
+ String[] navLabels = new String[NAV_DRAWER_TAGS.length];
+ final boolean[] checked = new boolean[NAV_DRAWER_TAGS.length];
+ for (int i = 0; i < NAV_DRAWER_TAGS.length; i++) {
+ String tag = NAV_DRAWER_TAGS[i];
+ navLabels[i] = navAdapter.getLabel(tag);
+ if (!hiddenDrawerItems.contains(tag)) {
+ checked[i] = true;
+ }
+ }
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.drawer_preferences);
+ builder.setMultiChoiceItems(navLabels, checked, (dialog, which, isChecked) -> {
+ if (isChecked) {
+ hiddenDrawerItems.remove(NAV_DRAWER_TAGS[which]);
+ } else {
+ hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]);
+ }
+ });
+ builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
+ UserPreferences.setHiddenDrawerItems(hiddenDrawerItems);
+ });
+ builder.setNegativeButton(R.string.cancel_label, null);
+ builder.create().show();
+ }
+
+ private DBReader.NavDrawerData navDrawerData;
+
+ private void loadData() {
+ subscription = Observable.fromCallable(DBReader::getNavDrawerData)
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(result -> {
+ navDrawerData = result;
+ if (navAdapter != null) {
+ navAdapter.notifyDataSetChanged();
+ }
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ });
+ }
+
+
+
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+
+ @Override
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((EventDistributor.FEED_LIST_UPDATE & arg) != 0) {
+ Log.d(TAG, "Received contentUpdate Intent.");
+ loadData();
+ }
+ }
+ };
+
+ private final NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() {
+ @Override
+ public int getCount() {
+ if (navDrawerData != null) {
+ return navDrawerData.feeds.size();
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public Feed getItem(int position) {
+ if (navDrawerData != null && 0 <= position && position < navDrawerData.feeds.size()) {
+ return navDrawerData.feeds.get(position);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public int getSelectedItemIndex() {
+ return -1;
+ }
+
+ @Override
+ public int getQueueSize() {
+ return (navDrawerData != null) ? navDrawerData.queueSize : 0;
+ }
+
+ @Override
+ public int getNumberOfNewItems() {
+ return (navDrawerData != null) ? navDrawerData.numNewItems : 0;
+ }
+
+ @Override
+ public int getNumberOfDownloadedItems() {
+ return (navDrawerData != null) ? navDrawerData.numDownloadedItems : 0;
+ }
+
+ @Override
+ public int getReclaimableItems() {
+ return (navDrawerData != null) ? navDrawerData.reclaimableSpace : 0;
+ }
+
+ @Override
+ public int getFeedCounter(long feedId) {
+ return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0;
+ }
+
+ @Override
+ public int getFeedCounterSum() {
+ if(navDrawerData == null) {
+ return 0;
+ }
+ int sum = 0;
+ for(int counter : navDrawerData.feedCounters.values()) {
+ sum += counter;
+ }
+ return sum;
+ }
+ };
+
+ public interface MediaplayerInfoContentFragment {
+ void onMediaChanged(Playable media);
+ }
+
+ private static class MediaplayerInfoPagerAdapter extends FragmentStatePagerAdapter {
+
+ private static final String TAG = "MPInfoPagerAdapter";
+
+ private Playable media;
+ private PlaybackController controller;
+
+ public MediaplayerInfoPagerAdapter(FragmentManager fm, Playable media) {
+ super(fm);
+ this.media = media;
+ }
+
+ private CoverFragment coverFragment;
+ private ItemDescriptionFragment itemDescriptionFragment;
+ private ChaptersFragment chaptersFragment;
+
+ public void onMediaChanged(Playable media) {
+ Log.d(TAG, "media changing to " + media.getEpisodeTitle());
+ this.media = media;
+ if(coverFragment != null) {
+ coverFragment.onMediaChanged(media);
+ }
+ if(itemDescriptionFragment != null) {
+ itemDescriptionFragment.onMediaChanged(media);
+ }
+ if(chaptersFragment != null) {
+ chaptersFragment.onMediaChanged(media);
+ }
+ }
+
+ public void setController(PlaybackController controller) {
+ this.controller = controller;
+ if(chaptersFragment != null) {
+ chaptersFragment.setController(controller);
+ }
+ }
+
+ @Nullable
+ public ChaptersFragment getChaptersFragment() {
+ return chaptersFragment;
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ Log.d(TAG, "getItem(" + position + ")");
+ switch (position) {
+ case POS_COVER:
+ if(coverFragment == null) {
+ coverFragment = CoverFragment.newInstance(media);
+ }
+ return coverFragment;
+ case POS_DESCR:
+ if(itemDescriptionFragment == null) {
+ itemDescriptionFragment = ItemDescriptionFragment.newInstance(media, true, true);
+ }
+ return itemDescriptionFragment;
+ case POS_CHAPTERS:
+ if(chaptersFragment == null) {
+ chaptersFragment = ChaptersFragment.newInstance(media);
+ chaptersFragment.setController(controller);
+ }
+ return chaptersFragment;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public int getCount() {
+ return NUM_CONTENT_FRAGMENTS;
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
index 42c9edd99..a52382dea 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
@@ -83,6 +83,12 @@ public class VideoplayerActivity extends MediaplayerActivity {
launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY,
true);
startService(launchIntent);
+ } else if (PlaybackService.isCasting()) {
+ Intent intent = PlaybackService.getPlayerActivityIntent(this);
+ if (!intent.getComponent().getClassName().equals(VideoplayerActivity.class.getName())) {
+ finish();
+ startActivity(intent);
+ }
}
}
@@ -159,7 +165,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
}
@Override
- protected void postStatusMsg(int resId) {
+ protected void postStatusMsg(int resId, boolean showToast) {
if (resId == R.string.player_preparing_msg) {
progressIndicator.setVisibility(View.VISIBLE);
} else {
@@ -257,6 +263,10 @@ public class VideoplayerActivity extends MediaplayerActivity {
Log.d(TAG, "ReloadNotification received, switching to Audioplayer now");
finish();
startActivity(new Intent(this, AudioplayerActivity.class));
+ } else if (notificationCode == PlaybackService.EXTRA_CODE_CAST) {
+ Log.d(TAG, "ReloadNotification received, switching to Castplayer now");
+ finish();
+ startActivity(new Intent(this, CastplayerActivity.class));
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java
index 997befe99..1ab60ef61 100644
--- a/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java
+++ b/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java
@@ -5,6 +5,7 @@ import android.content.Intent;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.AudioplayerActivity;
+import de.danoeh.antennapod.activity.CastplayerActivity;
import de.danoeh.antennapod.activity.VideoplayerActivity;
import de.danoeh.antennapod.core.PlaybackServiceCallbacks;
import de.danoeh.antennapod.core.feed.MediaType;
@@ -12,7 +13,10 @@ import de.danoeh.antennapod.core.feed.MediaType;
public class PlaybackServiceCallbacksImpl implements PlaybackServiceCallbacks {
@Override
- public Intent getPlayerActivityIntent(Context context, MediaType mediaType) {
+ public Intent getPlayerActivityIntent(Context context, MediaType mediaType, boolean remotePlayback) {
+ if (remotePlayback) {
+ return new Intent(context, CastplayerActivity.class);
+ }
if (mediaType == MediaType.VIDEO) {
return new Intent(context, VideoplayerActivity.class);
} else {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
index aea911f79..77e66f3b0 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
@@ -7,14 +7,14 @@ import android.view.View;
import android.widget.ListView;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment;
+import de.danoeh.antennapod.activity.MediaplayerInfoActivity.MediaplayerInfoContentFragment;
import de.danoeh.antennapod.adapter.ChaptersListAdapter;
import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
-public class ChaptersFragment extends ListFragment implements AudioplayerContentFragment {
+public class ChaptersFragment extends ListFragment implements MediaplayerInfoContentFragment {
private static final String TAG = "ChaptersFragment";
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
index d3b97f9df..943ddeec7 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
@@ -12,14 +12,14 @@ import android.widget.TextView;
import com.bumptech.glide.Glide;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment;
+import de.danoeh.antennapod.activity.MediaplayerInfoActivity.MediaplayerInfoContentFragment;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.util.playback.Playable;
/**
* Displays the cover and the title of a FeedItem.
*/
-public class CoverFragment extends Fragment implements AudioplayerContentFragment {
+public class CoverFragment extends Fragment implements MediaplayerInfoContentFragment {
private static final String TAG = "CoverFragment";
private static final String ARG_PLAYABLE = "arg.playable";
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
index ca60e7bf2..758f8095d 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -172,7 +172,7 @@ public class ExternalPlayerFragment extends Fragment {
.into(imgvCover);
fragmentLayout.setVisibility(View.VISIBLE);
- if (controller.isPlayingVideo()) {
+ if (controller.isPlayingVideoLocally()) {
butPlay.setVisibility(View.GONE);
} else {
butPlay.setVisibility(View.VISIBLE);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
index 5b301333e..55d28cadb 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -27,8 +27,8 @@ import android.webkit.WebViewClient;
import android.widget.Toast;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.AudioplayerActivity;
-import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment;
+import de.danoeh.antennapod.activity.MediaplayerInfoActivity;
+import de.danoeh.antennapod.activity.MediaplayerInfoActivity.MediaplayerInfoContentFragment;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
@@ -47,7 +47,7 @@ import rx.schedulers.Schedulers;
/**
* Displays the description of a Playable object in a Webview.
*/
-public class ItemDescriptionFragment extends Fragment implements AudioplayerContentFragment {
+public class ItemDescriptionFragment extends Fragment implements MediaplayerInfoContentFragment {
private static final String TAG = "ItemDescriptionFragment";
@@ -371,8 +371,8 @@ public class ItemDescriptionFragment extends Fragment implements AudioplayerCont
private void onTimecodeLinkSelected(String link) {
int time = Timeline.getTimecodeLinkTime(link);
- if (getActivity() != null && getActivity() instanceof AudioplayerActivity) {
- PlaybackController pc = ((AudioplayerActivity) getActivity()).getPlaybackController();
+ if (getActivity() != null && getActivity() instanceof MediaplayerInfoActivity) {
+ PlaybackController pc = ((MediaplayerInfoActivity) getActivity()).getPlaybackController();
if (pc != null) {
pc.seekTo(time);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
index 9740c9af9..e721af47d 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -39,6 +39,7 @@ import org.apache.commons.lang3.ArrayUtils;
import java.util.List;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.CastEnabledActivity;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.core.event.DownloadEvent;
@@ -311,6 +312,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
if(!isAdded() || item == null) {
return;
}
+ ((CastEnabledActivity) getActivity()).requestCastButton(MenuItem.SHOW_AS_ACTION_ALWAYS);
inflater.inflate(R.menu.feeditem_options, menu);
popupMenu = menu;
if (item.hasMedia()) {
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
index 3c1332e33..6c03dc7ae 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
@@ -34,6 +34,8 @@ import android.widget.Toast;
import android.widget.ListView;
import com.afollestad.materialdialogs.MaterialDialog;
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.GoogleApiAvailability;
import org.apache.commons.lang3.ArrayUtils;
@@ -410,6 +412,22 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
ui.getActivity().startActivity(Intent.createChooser(emailIntent, intentTitle));
return true;
});
+ //checks whether Google Play Services is installed on the device (condition necessary for Cast support)
+ ui.findPreference(UserPreferences.PREF_CAST_ENABLED).setOnPreferenceChangeListener((preference, o) -> {
+ if (o instanceof Boolean && ((Boolean) o)) {
+ final int googlePlayServicesCheck = GoogleApiAvailability.getInstance()
+ .isGooglePlayServicesAvailable(ui.getActivity());
+ if (googlePlayServicesCheck == ConnectionResult.SUCCESS) {
+ return true;
+ } else {
+ GoogleApiAvailability.getInstance()
+ .getErrorDialog(ui.getActivity(), googlePlayServicesCheck, 0)
+ .show();
+ return false;
+ }
+ }
+ return true;
+ });
buildEpisodeCleanupPreference();
buildSmartMarkAsPlayedPreference();
buildAutodownloadSelectedNetworsPreference();
diff --git a/app/src/main/res/layout/external_player_fragment.xml b/app/src/main/res/layout/external_player_fragment.xml
index e6fd21241..fb7abde55 100644
--- a/app/src/main/res/layout/external_player_fragment.xml
+++ b/app/src/main/res/layout/external_player_fragment.xml
@@ -37,6 +37,18 @@
android:indeterminate="false"
tools:progress="100"/>
+ <ImageButton
+ android:id="@+id/butPlay"
+ android:layout_width="52dp"
+ android:layout_height="52dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
+ android:layout_below="@id/episodeProgress"
+ android:layout_centerVertical="true"
+ android:contentDescription="@string/pause_label"
+ android:background="?attr/selectableItemBackground"
+ tools:src="@drawable/ic_play_arrow_white_36dp"/>
+
<TextView
android:id="@+id/txtvTitle"
android:layout_width="wrap_content"
@@ -72,18 +84,6 @@
android:maxLines="1"
tools:text="Episode author that is too long and will cause the text to wrap"/>
- <ImageButton
- android:id="@+id/butPlay"
- android:layout_width="52dp"
- android:layout_height="52dp"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"
- android:layout_below="@id/episodeProgress"
- android:layout_centerVertical="true"
- android:contentDescription="@string/pause_label"
- android:background="?attr/selectableItemBackground"
- tools:src="@drawable/ic_play_arrow_white_36dp"/>
-
</RelativeLayout>
</LinearLayout>
diff --git a/app/src/main/res/layout/audioplayer_activity.xml b/app/src/main/res/layout/mediaplayerinfo_activity.xml
index fb4f995a2..0f68b503e 100644
--- a/app/src/main/res/layout/audioplayer_activity.xml
+++ b/app/src/main/res/layout/mediaplayerinfo_activity.xml
@@ -152,6 +152,21 @@
android:src="?attr/av_fast_forward"
android:textSize="@dimen/text_size_medium"
android:textAllCaps="false"
+ tools:visibility="gone"
+ tools:background="@android:color/holo_green_dark" />
+
+ <ImageButton
+ android:id="@+id/butCastDisconnect"
+ android:layout_width="@dimen/audioplayer_playercontrols_length"
+ android:layout_height="@dimen/audioplayer_playercontrols_length"
+ android:layout_toLeftOf="@id/butRev"
+ android:background="?attr/selectableItemBackground"
+ android:contentDescription="@string/cast_disconnect_label"
+ android:src="?attr/ic_cast_disconnect"
+ android:scaleType="fitCenter"
+ android:visibility="gone"
+ tools:visibility="visible"
+ tools:src="@drawable/ic_cast_disconnect_white_36dp"
tools:background="@android:color/holo_green_dark" />
<ImageButton
diff --git a/app/src/main/res/menu/cast_enabled.xml b/app/src/main/res/menu/cast_enabled.xml
new file mode 100644
index 000000000..d6e85c311
--- /dev/null
+++ b/app/src/main/res/menu/cast_enabled.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/media_route_menu_item"
+ android:title="@string/cast_media_route_menu_title"
+ custom:actionProviderClass="de.danoeh.antennapod.core.cast.SwitchableMediaRouteActionProvider"
+ custom:showAsAction="ifRoom"/>
+</menu> \ No newline at end of file
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index ecdcd3517..57829e3e1 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -293,5 +293,14 @@
android:key="prefAbout"
android:title="@string/about_pref"/>
</PreferenceCategory>
+
+ <PreferenceCategory android:title="@string/experimental_pref">
+ <de.danoeh.antennapod.preferences.SwitchCompatPreference
+ android:defaultValue="false"
+ android:enabled="true"
+ android:key="prefCast"
+ android:summary="@string/pref_cast_message"
+ android:title="@string/pref_cast_title"/>
+ </PreferenceCategory>
</PreferenceScreen>