diff options
Diffstat (limited to 'app/src')
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> |