summaryrefslogtreecommitdiff
path: root/app/src/main/java/de/danoeh/antennapod
diff options
context:
space:
mode:
authordaniel oeh <daniel.oeh@gmail.com>2014-10-11 17:43:07 +0200
committerdaniel oeh <daniel.oeh@gmail.com>2014-10-11 17:43:07 +0200
commit658559699f5cd482bb19ade298db43a65d750664 (patch)
treedb9ab70a4aef41678a2436cd5ab25cb4baea8699 /app/src/main/java/de/danoeh/antennapod
parent21b5b835e3a9c83410120d38a63e51be2981a38b (diff)
downloadAntennaPod-658559699f5cd482bb19ade298db43a65d750664.zip
Moved core classes into subproject
Diffstat (limited to 'app/src/main/java/de/danoeh/antennapod')
-rw-r--r--app/src/main/java/de/danoeh/antennapod/PodcastApp.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java118
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java (renamed from app/src/main/java/de/danoeh/antennapod/core/asynctask/OpmlFeedQueuer.java)4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java (renamed from app/src/main/java/de/danoeh/antennapod/core/asynctask/OpmlImportWorker.java)6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/ApplicationCallbacksImpl.java23
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java49
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/FlattrCallbacksImpl.java53
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/GpodnetCallbacksImpl.java22
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java21
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/StorageCallbacksImpl.java107
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/ClientConfig.java21
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/DownloadServiceCallbacks.java43
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/FlattrCallbacks.java24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/GpodnetCallbacks.java26
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/PlaybackServiceCallbacks.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/StorageCallbacks.java27
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/asynctask/DownloadObserver.java177
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/asynctask/FeedRemover.java74
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java238
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrStatusFetcher.java47
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrTokenFetcher.java95
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/asynctask/OpmlExportWorker.java114
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoImageResource.java37
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java152
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java211
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java64
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/dialog/DownloadRequestErrorDialogCreator.java30
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java55
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java140
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/feed/Feed.java445
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java66
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/feed/FeedFile.java105
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/feed/FeedImage.java71
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java332
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java408
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java89
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/feed/ID3Chapter.java36
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/feed/MediaType.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/feed/SearchResult.java34
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java25
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/feed/VorbisCommentChapter.java109
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java718
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetServiceAuthenticationException.java21
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetServiceBadStatusCodeException.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetServiceException.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java72
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java65
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java41
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java46
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java56
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/opml/OpmlElement.java46
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/opml/OpmlReader.java87
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/opml/OpmlSymbols.java21
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/opml/OpmlWriter.java65
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java246
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java146
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java577
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/receiver/AlarmUpdateReceiver.java33
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/receiver/ConnectivityActionReceiver.java46
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java46
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java32
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java245
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/service/download/APRedirectHandler.java54
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java96
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java209
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java1230
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java181
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/service/download/Downloader.java69
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/service/download/DownloaderCallback.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java246
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java1080
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java979
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java384
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/service/playback/PlayerStatus.java14
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java908
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java895
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java974
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequestException.java25
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java366
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/storage/FeedItemStatistics.java70
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java57
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java1391
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/handler/FeedHandler.java34
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/handler/FeedHandlerResult.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java98
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/handler/SyndHandler.java126
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/handler/TypeGetter.java111
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java38
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSContent.java25
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java51
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java68
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java141
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java42
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/Namespace.java21
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/SyndElement.java22
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java46
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java194
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndDateUtils.java153
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndTypeUtils.java42
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java261
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/Converter.java103
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/DownloadError.java52
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/DuckType.java117
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/EpisodeFilter.java49
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/FeedtitleComparator.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java36
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/InvalidFeedException.java21
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java120
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java69
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/QueueAccess.java93
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java34
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/ShownotesProvider.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java66
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/ThemeUtils.java22
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/URIUtil.java35
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java51
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/UndoBarController.java137
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/comparator/ChapterStartTimeComparator.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/comparator/DownloadStatusComparator.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/comparator/FeedItemPubdateComparator.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/comparator/PlaybackCompletionDateComparator.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/comparator/SearchResultValueComparator.java14
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/exception/MediaFileNotFoundException.java23
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrServiceCreator.java25
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrStatus.java68
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrThing.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrUtils.java305
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/flattr/SimpleFlattrThing.java30
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/gui/FeedItemUndoToken.java55
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java118
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java250
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3ReaderException.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/FrameHeader.java17
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/Header.java29
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/TagHeader.java26
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java34
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java235
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java69
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/playback/MediaPlayerError.java23
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java207
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java784
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java161
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java67
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java78
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java81
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java101
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentHeader.java26
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java194
-rw-r--r--app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReaderException.java24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/FeedItemDialog.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/TimeDialog.java (renamed from app/src/main/java/de/danoeh/antennapod/core/dialog/TimeDialog.java)4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java (renamed from app/src/main/java/de/danoeh/antennapod/core/util/menuhandler/FeedItemMenuHandler.java)4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java (renamed from app/src/main/java/de/danoeh/antennapod/core/util/menuhandler/FeedMenuHandler.java)4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java (renamed from app/src/main/java/de/danoeh/antennapod/core/util/menuhandler/MenuItemUtils.java)4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/NavDrawerActivity.java (renamed from app/src/main/java/de/danoeh/antennapod/core/util/menuhandler/NavDrawerActivity.java)2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java (renamed from app/src/main/java/de/danoeh/antennapod/core/receiver/PlayerWidget.java)15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java (renamed from app/src/main/java/de/danoeh/antennapod/core/service/playback/PlayerWidgetService.java)8
172 files changed, 464 insertions, 20922 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
index 25aa9fb68..12213d6f9 100644
--- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
+++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
@@ -12,7 +12,6 @@ import de.danoeh.antennapod.spa.SPAUtil;
public class PodcastApp extends Application {
private static final String TAG = "PodcastApp";
- public static final String EXPORT_DIR = "export/";
private static float LOGICAL_DENSITY;
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 5622bc987..f9001adad 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -43,8 +43,8 @@ import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.util.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.core.util.menuhandler.NavDrawerActivity;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
index 80484df37..3000cfaeb 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
@@ -21,7 +21,7 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.util.LangUtils;
-import de.danoeh.antennapod.core.util.menuhandler.FeedMenuHandler;
+import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
/**
* Displays information about a feed.
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 2c660019c..7029fd32c 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -31,7 +31,7 @@ import de.danoeh.antennapod.fragment.*;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.StorageUtils;
-import de.danoeh.antennapod.core.util.menuhandler.NavDrawerActivity;
+import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
import java.util.List;
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 249a3c5c3..14cb2727f 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -22,7 +22,7 @@ import com.doomonafireball.betterpickers.hmspicker.HmsPickerBuilder;
import com.doomonafireball.betterpickers.hmspicker.HmsPickerDialogFragment;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.dialog.TimeDialog;
+import de.danoeh.antennapod.dialog.TimeDialog;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
index 2e66978fd..d974e0e1b 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
@@ -4,8 +4,8 @@ import android.content.Intent;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.asynctask.OpmlFeedQueuer;
-import de.danoeh.antennapod.core.asynctask.OpmlImportWorker;
+import de.danoeh.antennapod.asynctask.OpmlFeedQueuer;
+import de.danoeh.antennapod.asynctask.OpmlImportWorker;
import de.danoeh.antennapod.core.opml.OpmlElement;
import java.io.Reader;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
index 65efcc230..484550a6a 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -22,7 +22,7 @@ import android.widget.Toast;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.asynctask.FlattrClickWorker;
-import de.danoeh.antennapod.core.asynctask.OpmlExportWorker;
+import de.danoeh.antennapod.asynctask.OpmlExportWorker;
import de.danoeh.antennapod.dialog.AuthenticationDialog;
import de.danoeh.antennapod.dialog.AutoFlattrPreferenceDialog;
import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog;
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java
new file mode 100644
index 000000000..6bba956a6
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java
@@ -0,0 +1,118 @@
+package de.danoeh.antennapod.asynctask;
+
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.AsyncTask;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+
+import de.danoeh.antennapod.core.R;
+import de.danoeh.antennapod.core.opml.OpmlWriter;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.util.LangUtils;
+
+/**
+ * Writes an OPML file into the export directory in the background.
+ */
+public class OpmlExportWorker extends AsyncTask<Void, Void, Void> {
+ private static final String TAG = "OpmlExportWorker";
+ private static final String DEFAULT_OUTPUT_NAME = "antennapod-feeds.opml";
+ public static final String EXPORT_DIR = "export/";
+
+ private Context context;
+ private File output;
+
+ private ProgressDialog progDialog;
+ private Exception exception;
+
+ public OpmlExportWorker(Context context, File output) {
+ this.context = context;
+ this.output = output;
+ }
+
+ public OpmlExportWorker(Context context) {
+ this.context = context;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ OpmlWriter opmlWriter = new OpmlWriter();
+ if (output == null) {
+ output = new File(
+ UserPreferences.getDataFolder(context, EXPORT_DIR),
+ DEFAULT_OUTPUT_NAME);
+ if (output.exists()) {
+ Log.w(TAG, "Overwriting previously exported file.");
+ output.delete();
+ }
+ }
+ OutputStreamWriter writer = null;
+ try {
+ writer = new OutputStreamWriter(new FileOutputStream(output), LangUtils.UTF_8);
+ opmlWriter.writeDocument(DBReader.getFeedList(context), writer);
+ } catch (IOException e) {
+ e.printStackTrace();
+ exception = e;
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch (IOException ioe) {
+ exception = ioe;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ progDialog.dismiss();
+ AlertDialog.Builder alert = new AlertDialog.Builder(context)
+ .setNeutralButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+ dialog.dismiss();
+ }
+ });
+ if (exception != null) {
+ alert.setTitle(R.string.export_error_label);
+ alert.setMessage(exception.getMessage());
+ } else {
+ alert.setTitle(R.string.opml_export_success_title);
+ alert.setMessage(context
+ .getString(R.string.opml_export_success_sum)
+ + output.toString());
+ }
+ alert.create().show();
+ }
+
+ @Override
+ protected void onPreExecute() {
+ progDialog = new ProgressDialog(context);
+ progDialog.setMessage(context.getString(R.string.exporting_label));
+ progDialog.setIndeterminate(true);
+ progDialog.show();
+ }
+
+ @SuppressLint("NewApi")
+ public void executeAsync() {
+ if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
+ executeOnExecutor(THREAD_POOL_EXECUTOR);
+ } else {
+ execute();
+ }
+ }
+
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/asynctask/OpmlFeedQueuer.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java
index 13144faa9..cb9197b8e 100644
--- a/app/src/main/java/de/danoeh/antennapod/core/asynctask/OpmlFeedQueuer.java
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java
@@ -1,10 +1,10 @@
-package de.danoeh.antennapod.core.asynctask;
+package de.danoeh.antennapod.asynctask;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
-import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.activity.OpmlImportHolder;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.opml.OpmlElement;
diff --git a/app/src/main/java/de/danoeh/antennapod/core/asynctask/OpmlImportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
index a4308be9b..cfe0703ca 100644
--- a/app/src/main/java/de/danoeh/antennapod/core/asynctask/OpmlImportWorker.java
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
@@ -1,4 +1,4 @@
-package de.danoeh.antennapod.core.asynctask;
+package de.danoeh.antennapod.asynctask;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
@@ -8,8 +8,8 @@ import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.AsyncTask;
import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.BuildConfig;
+import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.opml.OpmlElement;
import de.danoeh.antennapod.core.opml.OpmlReader;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/app/src/main/java/de/danoeh/antennapod/config/ApplicationCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/ApplicationCallbacksImpl.java
new file mode 100644
index 000000000..fdbb2139d
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/config/ApplicationCallbacksImpl.java
@@ -0,0 +1,23 @@
+package de.danoeh.antennapod.config;
+
+
+import android.app.Application;
+import android.content.Context;
+import android.content.Intent;
+
+import de.danoeh.antennapod.PodcastApp;
+import de.danoeh.antennapod.activity.StorageErrorActivity;
+import de.danoeh.antennapod.core.ApplicationCallbacks;
+
+public class ApplicationCallbacksImpl implements ApplicationCallbacks {
+
+ @Override
+ public Application getApplicationInstance() {
+ return PodcastApp.getInstance();
+ }
+
+ @Override
+ public Intent getStorageErrorActivity(Context context) {
+ return new Intent(context, StorageErrorActivity.class);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
new file mode 100644
index 000000000..5dc3416c6
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
@@ -0,0 +1,19 @@
+package de.danoeh.antennapod.config;
+
+import de.danoeh.antennapod.core.ClientConfig;
+
+/**
+ * Configures the ClientConfig class of the core package.
+ */
+public class ClientConfigurator {
+
+ static {
+ ClientConfig.USER_AGENT = "AntennaPod/0.9.9.3";
+ ClientConfig.applicationCallbacks = new ApplicationCallbacksImpl();
+ ClientConfig.downloadServiceCallbacks = new DownloadServiceCallbacksImpl();
+ ClientConfig.gpodnetCallbacks = new GpodnetCallbacksImpl();
+ ClientConfig.playbackServiceCallbacks = new PlaybackServiceCallbacksImpl();
+ ClientConfig.storageCallbacks = new StorageCallbacksImpl();
+ ClientConfig.flattrCallbacks = new FlattrCallbacksImpl();
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java
new file mode 100644
index 000000000..0f180e9c5
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java
@@ -0,0 +1,49 @@
+package de.danoeh.antennapod.config;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import de.danoeh.antennapod.activity.DownloadAuthenticationActivity;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.adapter.NavListAdapter;
+import de.danoeh.antennapod.core.DownloadServiceCallbacks;
+import de.danoeh.antennapod.core.service.download.DownloadRequest;
+import de.danoeh.antennapod.fragment.DownloadsFragment;
+
+
+public class DownloadServiceCallbacksImpl implements DownloadServiceCallbacks {
+
+ @Override
+ public PendingIntent getNotificationContentIntent(Context context) {
+ Intent intent = new Intent(context, MainActivity.class);
+ intent.putExtra(MainActivity.EXTRA_NAV_TYPE, NavListAdapter.VIEW_TYPE_NAV);
+ intent.putExtra(MainActivity.EXTRA_NAV_INDEX, MainActivity.POS_DOWNLOADS);
+ Bundle args = new Bundle();
+ args.putInt(DownloadsFragment.ARG_SELECTED_TAB, DownloadsFragment.POS_RUNNING);
+ intent.putExtra(MainActivity.EXTRA_FRAGMENT_ARGS, args);
+
+ return PendingIntent.getActivity(context, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ @Override
+ public PendingIntent getAuthentificationNotificationContentIntent(Context context, DownloadRequest request) {
+ final Intent activityIntent = new Intent(context.getApplicationContext(), DownloadAuthenticationActivity.class);
+ activityIntent.putExtra(DownloadAuthenticationActivity.ARG_DOWNLOAD_REQUEST, request);
+ activityIntent.putExtra(DownloadAuthenticationActivity.ARG_SEND_TO_DOWNLOAD_REQUESTER_BOOL, true);
+ return PendingIntent.getActivity(context.getApplicationContext(), 0, activityIntent, PendingIntent.FLAG_ONE_SHOT);
+ }
+
+ @Override
+ public PendingIntent getReportNotificationContentIntent(Context context) {
+ Intent intent = new Intent(context, MainActivity.class);
+ intent.putExtra(MainActivity.EXTRA_NAV_TYPE, NavListAdapter.VIEW_TYPE_NAV);
+ intent.putExtra(MainActivity.EXTRA_NAV_INDEX, MainActivity.POS_DOWNLOADS);
+ Bundle args = new Bundle();
+ args.putInt(DownloadsFragment.ARG_SELECTED_TAB, DownloadsFragment.POS_LOG);
+ intent.putExtra(MainActivity.EXTRA_FRAGMENT_ARGS, args);
+ return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/FlattrCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/FlattrCallbacksImpl.java
new file mode 100644
index 000000000..3817db6de
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/config/FlattrCallbacksImpl.java
@@ -0,0 +1,53 @@
+package de.danoeh.antennapod.config;
+
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import org.shredzone.flattr4j.oauth.AccessToken;
+
+import de.danoeh.antennapod.BuildConfig;
+import de.danoeh.antennapod.activity.FlattrAuthActivity;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.core.FlattrCallbacks;
+
+public class FlattrCallbacksImpl implements FlattrCallbacks {
+ private static final String TAG = "FlattrCallbacksImpl";
+
+ @Override
+ public boolean flattrEnabled() {
+ return true;
+ }
+
+ @Override
+ public Intent getFlattrAuthenticationActivityIntent(Context context) {
+ return new Intent(context, FlattrAuthActivity.class);
+ }
+
+ @Override
+ public PendingIntent getFlattrFailedNotificationContentIntent(Context context) {
+ return PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0);
+ }
+
+ @Override
+ public String getFlattrAppKey() {
+ return BuildConfig.FLATTR_APP_KEY;
+ }
+
+ @Override
+ public String getFlattrAppSecret() {
+ return BuildConfig.FLATTR_APP_SECRET;
+ }
+
+ @Override
+ public void handleFlattrAuthenticationSuccess(AccessToken token) {
+ FlattrAuthActivity instance = FlattrAuthActivity.getInstance();
+ if (instance != null) {
+ instance.handleAuthenticationSuccess();
+ } else {
+ Log.e(TAG, "FlattrAuthActivity instance was null");
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/GpodnetCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/GpodnetCallbacksImpl.java
new file mode 100644
index 000000000..5f8da6894
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/config/GpodnetCallbacksImpl.java
@@ -0,0 +1,22 @@
+package de.danoeh.antennapod.config;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.core.GpodnetCallbacks;
+
+
+public class GpodnetCallbacksImpl implements GpodnetCallbacks {
+ @Override
+ public boolean gpodnetEnabled() {
+ return true;
+ }
+
+ @Override
+ public PendingIntent getGpodnetSyncServiceErrorNotificationPendingIntent(Context context) {
+ return PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java
new file mode 100644
index 000000000..d1e3a8379
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java
@@ -0,0 +1,21 @@
+package de.danoeh.antennapod.config;
+
+import android.content.Context;
+import android.content.Intent;
+
+import de.danoeh.antennapod.activity.AudioplayerActivity;
+import de.danoeh.antennapod.activity.VideoplayerActivity;
+import de.danoeh.antennapod.core.PlaybackServiceCallbacks;
+import de.danoeh.antennapod.core.feed.MediaType;
+
+
+public class PlaybackServiceCallbacksImpl implements PlaybackServiceCallbacks {
+ @Override
+ public Intent getPlayerActivityIntent(Context context, MediaType mediaType) {
+ if (mediaType == MediaType.VIDEO) {
+ return new Intent(context, VideoplayerActivity.class);
+ } else {
+ return new Intent(context, AudioplayerActivity.class);
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/StorageCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/StorageCallbacksImpl.java
new file mode 100644
index 000000000..ec133aed1
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/config/StorageCallbacksImpl.java
@@ -0,0 +1,107 @@
+package de.danoeh.antennapod.config;
+
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.util.Log;
+
+import de.danoeh.antennapod.core.StorageCallbacks;
+import de.danoeh.antennapod.core.storage.PodDBAdapter;
+
+public class StorageCallbacksImpl implements StorageCallbacks {
+
+ @Override
+ public int getDatabaseVersion() {
+ return 12;
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.w("DBAdapter", "Upgrading from version " + oldVersion + " to "
+ + newVersion + ".");
+ if (oldVersion <= 1) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN "
+ + PodDBAdapter.KEY_TYPE + " TEXT");
+ }
+ if (oldVersion <= 2) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS
+ + " ADD COLUMN " + PodDBAdapter.KEY_LINK + " TEXT");
+ }
+ if (oldVersion <= 3) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
+ + " ADD COLUMN " + PodDBAdapter.KEY_ITEM_IDENTIFIER + " TEXT");
+ }
+ if (oldVersion <= 4) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN "
+ + PodDBAdapter.KEY_FEED_IDENTIFIER + " TEXT");
+ }
+ if (oldVersion <= 5) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_DOWNLOAD_LOG
+ + " ADD COLUMN " + PodDBAdapter.KEY_REASON_DETAILED + " TEXT");
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_DOWNLOAD_LOG
+ + " ADD COLUMN " + PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE + " TEXT");
+ }
+ if (oldVersion <= 6) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS
+ + " ADD COLUMN " + PodDBAdapter.KEY_CHAPTER_TYPE + " INTEGER");
+ }
+ if (oldVersion <= 7) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
+ + " ADD COLUMN " + PodDBAdapter.KEY_PLAYBACK_COMPLETION_DATE
+ + " INTEGER");
+ }
+ if (oldVersion <= 8) {
+ final int KEY_ID_POSITION = 0;
+ final int KEY_MEDIA_POSITION = 1;
+
+ // Add feeditem column to feedmedia table
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
+ + " ADD COLUMN " + PodDBAdapter.KEY_FEEDITEM
+ + " INTEGER");
+ Cursor feeditemCursor = db.query(PodDBAdapter.TABLE_NAME_FEED_ITEMS,
+ new String[]{PodDBAdapter.KEY_ID, PodDBAdapter.KEY_MEDIA}, "? > 0",
+ new String[]{PodDBAdapter.KEY_MEDIA}, null, null, null);
+ if (feeditemCursor.moveToFirst()) {
+ db.beginTransaction();
+ ContentValues contentValues = new ContentValues();
+ do {
+ long mediaId = feeditemCursor.getLong(KEY_MEDIA_POSITION);
+ contentValues.put(PodDBAdapter.KEY_FEEDITEM, feeditemCursor.getLong(KEY_ID_POSITION));
+ db.update(PodDBAdapter.TABLE_NAME_FEED_MEDIA, contentValues, PodDBAdapter.KEY_ID + "=?", new String[]{String.valueOf(mediaId)});
+ contentValues.clear();
+ } while (feeditemCursor.moveToNext());
+ db.setTransactionSuccessful();
+ db.endTransaction();
+ }
+ feeditemCursor.close();
+ }
+ if (oldVersion <= 9) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ + " ADD COLUMN " + PodDBAdapter.KEY_AUTO_DOWNLOAD
+ + " INTEGER DEFAULT 1");
+ }
+ if (oldVersion <= 10) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ + " ADD COLUMN " + PodDBAdapter.KEY_FLATTR_STATUS
+ + " INTEGER");
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
+ + " ADD COLUMN " + PodDBAdapter.KEY_FLATTR_STATUS
+ + " INTEGER");
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
+ + " ADD COLUMN " + PodDBAdapter.KEY_PLAYED_DURATION
+ + " INTEGER");
+ }
+ if (oldVersion <= 11) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ + " ADD COLUMN " + PodDBAdapter.KEY_USERNAME
+ + " TEXT");
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ + " ADD COLUMN " + PodDBAdapter.KEY_PASSWORD
+ + " TEXT");
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
+ + " ADD COLUMN " + PodDBAdapter.KEY_IMAGE
+ + " INTEGER");
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/ClientConfig.java b/app/src/main/java/de/danoeh/antennapod/core/ClientConfig.java
deleted file mode 100644
index bf28c17ea..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/ClientConfig.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package de.danoeh.antennapod.core;
-
-/**
- * Stores callbacks for core classes like Services, DB classes etc. and other configuration variables.
- * Apps using the core module of AntennaPod should register implementations of all interfaces here.
- */
-public class ClientConfig {
-
- /**
- * Should be used when setting User-Agent header for HTTP-requests.
- */
- public static String USER_AGENT;
-
- public static DownloadServiceCallbacks downloadServiceCallbacks;
-
- public static PlaybackServiceCallbacks playbackServiceCallbacks;
-
- public static GpodnetCallbacks gpodnetCallbacks;
-
- public static StorageCallbacks storageCallbacks;
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/DownloadServiceCallbacks.java b/app/src/main/java/de/danoeh/antennapod/core/DownloadServiceCallbacks.java
deleted file mode 100644
index 9e4ed8e2b..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/DownloadServiceCallbacks.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package de.danoeh.antennapod.core;
-
-import android.app.PendingIntent;
-
-import de.danoeh.antennapod.core.service.download.DownloadRequest;
-
-/**
- * Callbacks for the DownloadService of the core module
- */
-public interface DownloadServiceCallbacks {
-
- /**
- * Returns a PendingIntent for a notification the main notification of the DownloadService.
- * <p/>
- * The PendingIntent takes the users to a screen where they can observe all currently running
- * downloads.
- *
- * @return A non-null PendingIntent for the notification.
- */
- public PendingIntent getNotificationContentIntent();
-
- /**
- * Returns a PendingIntent for a notification that tells the user to enter a username
- * or a password for a requested download.
- * <p/>
- * The PendingIntent takes users to an Activity that lets the user enter their username
- * and password to retry the download.
- *
- * @return A non-null PendingIntent for the notification.
- */
- public PendingIntent getAuthentificationNotificationContentIntent(DownloadRequest request);
-
- /**
- * Returns a PendingIntent for notification that notifies the user about the completion of downloads
- * along with information about failed and successful downloads.
- * <p/>
- * The PendingIntent takes users to an activity where they can look at all successful and failed downloads.
- *
- * @return A non-null PendingIntent for the notification.
- */
- public PendingIntent getReportNotificationContentIntent();
-}
-
diff --git a/app/src/main/java/de/danoeh/antennapod/core/FlattrCallbacks.java b/app/src/main/java/de/danoeh/antennapod/core/FlattrCallbacks.java
deleted file mode 100644
index 2dde4d8f3..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/FlattrCallbacks.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package de.danoeh.antennapod.core;
-
-import android.content.Intent;
-
-/**
- * Callbacks for the flattr integration of the app.
- */
-public interface FlattrCallbacks {
-
- /**
- * Returns if true if the flattr integration should be activated,
- * false otherwise.
- */
- public boolean flattrEnabled();
-
- /**
- * Returns an intent that starts the activity that is responsible for
- * letting users log into their flattr account.
- *
- * @return The intent that starts the authentication activity or null
- * if flattr integration is disabled (i.e. flattrEnabled() == false).
- */
- public Intent getFlattrAuthenticationActivityIntent();
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/GpodnetCallbacks.java b/app/src/main/java/de/danoeh/antennapod/core/GpodnetCallbacks.java
deleted file mode 100644
index e937bf35c..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/GpodnetCallbacks.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package de.danoeh.antennapod.core;
-
-import android.app.PendingIntent;
-
-/**
- * Callbacks related to the gpodder.net integration of the core module
- */
-public interface GpodnetCallbacks {
-
-
- /**
- * Returns if true if the gpodder.net integration should be activated,
- * false otherwise.
- */
- public boolean gpodnetEnabled();
-
- /**
- * Returns a PendingIntent for the error notification of the GpodnetSyncService.
- * <p/>
- * What the PendingIntent does may be implementation-specific.
- *
- * @return A PendingIntent for the notification or null if gpodder.net integration
- * has been disabled (i.e. gpodnetEnabled() == false).
- */
- public PendingIntent getGpodnetSyncServiceErrorNotificationPendingIntent();
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/PlaybackServiceCallbacks.java b/app/src/main/java/de/danoeh/antennapod/core/PlaybackServiceCallbacks.java
deleted file mode 100644
index a74c441c4..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/PlaybackServiceCallbacks.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package de.danoeh.antennapod.core;
-
-import android.content.Intent;
-
-import de.danoeh.antennapod.core.feed.MediaType;
-
-/**
- * Callbacks for the PlaybackService of the core module
- */
-public interface PlaybackServiceCallbacks {
-
- /**
- * Returns an intent which starts an audio- or videoplayer, depending on the
- * type of media that is being played.
- *
- * @param mediaType The type of media that is being played.
- * @return A non-null activity intent.
- */
- public Intent getPlayerActivityIntent(MediaType mediaType);
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/StorageCallbacks.java b/app/src/main/java/de/danoeh/antennapod/core/StorageCallbacks.java
deleted file mode 100644
index 5d1a0fffc..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/StorageCallbacks.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package de.danoeh.antennapod.core;
-
-import android.database.sqlite.SQLiteDatabase;
-
-/**
- * Callbacks for the classes in the storage package of the core module.
- */
-public interface StorageCallbacks {
-
- /**
- * Returns the current version of the database.
- *
- * @return The non-negative version number of the database.
- */
- public int getDatabaseVersion();
-
- /**
- * Upgrades the given database from an old version to a newer version.
- *
- * @param db The database that is supposed to be upgraded.
- * @param oldVersion The old version of the database.
- * @param newVersion The version that the database is supposed to be upgraded to.
- */
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);
-
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/asynctask/DownloadObserver.java b/app/src/main/java/de/danoeh/antennapod/core/asynctask/DownloadObserver.java
deleted file mode 100644
index 8b3635af8..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/asynctask/DownloadObserver.java
+++ /dev/null
@@ -1,177 +0,0 @@
-package de.danoeh.antennapod.core.asynctask;
-
-import android.app.Activity;
-import android.content.*;
-import android.os.Handler;
-import android.os.IBinder;
-import android.util.Log;
-
-import org.apache.commons.lang3.Validate;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.service.download.DownloadService;
-import de.danoeh.antennapod.core.service.download.Downloader;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Provides access to the DownloadService's list of items that are currently being downloaded.
- * The DownloadObserver object should be created in the activity's onCreate() method. resume() and pause()
- * should be called in the activity's onResume() and onPause() methods
- */
-public class DownloadObserver {
- private static final String TAG = "DownloadObserver";
-
- /**
- * Time period between update notifications.
- */
- public static final int WAITING_INTERVAL_MS = 3000;
-
- private volatile Activity activity;
- private final Handler handler;
- private final Callback callback;
-
- private DownloadService downloadService = null;
- private AtomicBoolean mIsBound = new AtomicBoolean(false);
-
- private Thread refresherThread;
- private AtomicBoolean refresherThreadRunning = new AtomicBoolean(false);
-
-
- /**
- * Creates a new download observer.
- *
- * @param activity Used for registering receivers
- * @param handler All callback methods are executed on this handler. The handler MUST run on the GUI thread.
- * @param callback Callback methods for posting content updates
- * @throws java.lang.IllegalArgumentException if one of the arguments is null.
- */
- public DownloadObserver(Activity activity, Handler handler, Callback callback) {
- Validate.notNull(activity);
- Validate.notNull(handler);
- Validate.notNull(callback);
-
- this.activity = activity;
- this.handler = handler;
- this.callback = callback;
- }
-
- public void onResume() {
- if (BuildConfig.DEBUG) Log.d(TAG, "DownloadObserver resumed");
- activity.registerReceiver(contentChangedReceiver, new IntentFilter(DownloadService.ACTION_DOWNLOADS_CONTENT_CHANGED));
- connectToDownloadService();
- }
-
- public void onPause() {
- if (BuildConfig.DEBUG) Log.d(TAG, "DownloadObserver paused");
- try {
- activity.unregisterReceiver(contentChangedReceiver);
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- }
- try {
- activity.unbindService(mConnection);
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- }
- stopRefresher();
- }
-
- private BroadcastReceiver contentChangedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- // reconnect to DownloadService if connection has been closed
- if (downloadService == null) {
- connectToDownloadService();
- }
- callback.onContentChanged();
- startRefresher();
- }
- };
-
- public interface Callback {
- void onContentChanged();
-
- void onDownloadDataAvailable(List<Downloader> downloaderList);
- }
-
- private void connectToDownloadService() {
- activity.bindService(new Intent(activity, DownloadService.class), mConnection, 0);
- }
-
- private ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceDisconnected(ComponentName className) {
- downloadService = null;
- mIsBound.set(false);
- stopRefresher();
- Log.i(TAG, "Closed connection with DownloadService.");
- }
-
- public void onServiceConnected(ComponentName name, IBinder service) {
- downloadService = ((DownloadService.LocalBinder) service)
- .getService();
- mIsBound.set(true);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Connection to service established");
- List<Downloader> downloaderList = downloadService.getDownloads();
- if (downloaderList != null && !downloaderList.isEmpty()) {
- callback.onDownloadDataAvailable(downloaderList);
- startRefresher();
- }
- }
- };
-
- private void stopRefresher() {
- if (refresherThread != null) {
- refresherThread.interrupt();
- }
- }
-
- private void startRefresher() {
- if (refresherThread == null || refresherThread.isInterrupted()) {
- refresherThread = new Thread(new RefresherThread());
- refresherThread.start();
- }
- }
-
- private class RefresherThread implements Runnable {
-
- public void run() {
- refresherThreadRunning.set(true);
- while (!Thread.interrupted()) {
- try {
- Thread.sleep(WAITING_INTERVAL_MS);
- } catch (InterruptedException e) {
- Log.d(TAG, "Refresher thread was interrupted");
- }
- if (mIsBound.get()) {
- postUpdate();
- }
- }
- refresherThreadRunning.set(false);
- }
-
- private void postUpdate() {
- handler.post(new Runnable() {
- @Override
- public void run() {
- callback.onContentChanged();
- if (downloadService != null) {
- List<Downloader> downloaderList = downloadService.getDownloads();
- if (downloaderList == null || downloaderList.isEmpty()) {
- Thread.currentThread().interrupt();
- }
- }
- }
- });
- }
- }
-
- public void setActivity(Activity activity) {
- Validate.notNull(activity);
- this.activity = activity;
- }
-
-}
-
diff --git a/app/src/main/java/de/danoeh/antennapod/core/asynctask/FeedRemover.java b/app/src/main/java/de/danoeh/antennapod/core/asynctask/FeedRemover.java
deleted file mode 100644
index 2201dfbe7..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/asynctask/FeedRemover.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package de.danoeh.antennapod.core.asynctask;
-
-import android.annotation.SuppressLint;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
-import android.os.AsyncTask;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.storage.DBWriter;
-
-import java.util.concurrent.ExecutionException;
-
-/** Removes a feed in the background. */
-public class FeedRemover extends AsyncTask<Void, Void, Void> {
- Context context;
- ProgressDialog dialog;
- Feed feed;
-
- public FeedRemover(Context context, Feed feed) {
- super();
- this.context = context;
- this.feed = feed;
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- try {
- DBWriter.deleteFeed(context, feed.getId()).get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- @Override
- protected void onCancelled() {
- dialog.dismiss();
- }
-
- @Override
- protected void onPostExecute(Void result) {
- dialog.dismiss();
- }
-
- @Override
- protected void onPreExecute() {
- dialog = new ProgressDialog(context);
- dialog.setMessage(context.getString(R.string.feed_remover_msg));
- dialog.setOnCancelListener(new OnCancelListener() {
-
- @Override
- public void onCancel(DialogInterface dialog) {
- cancel(true);
-
- }
-
- });
- dialog.show();
- }
-
- @SuppressLint("NewApi")
- public void executeAsync() {
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- execute();
- }
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java b/app/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java
deleted file mode 100644
index 44ad91981..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java
+++ /dev/null
@@ -1,238 +0,0 @@
-package de.danoeh.antennapod.core.asynctask;
-
-import android.annotation.TargetApi;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.os.AsyncTask;
-import android.support.v4.app.NotificationCompat;
-import android.util.Log;
-import android.widget.Toast;
-
-import org.apache.commons.lang3.Validate;
-import org.shredzone.flattr4j.exception.FlattrException;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.FlattrAuthActivity;
-import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.util.NetworkUtils;
-import de.danoeh.antennapod.core.util.flattr.FlattrThing;
-import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
-
-/**
- * Performs a click action in a background thread.
- * <p/>
- * When started, the flattr click worker will try to flattr every item that is in the flattr queue. If no network
- * connection is available it will shut down immediately. The FlattrClickWorker can also be given one additional
- * FlattrThing which will be flattrd immediately.
- * <p/>
- * The FlattrClickWorker will display a toast notification for every item that has been flattrd. If the FlattrClickWorker failed
- * to flattr something, a notification will be displayed.
- */
-public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorker.ExitCode> {
- protected static final String TAG = "FlattrClickWorker";
-
- private static final int NOTIFICATION_ID = 4;
-
- private final Context context;
-
- public static enum ExitCode {EXIT_NORMAL, NO_TOKEN, NO_NETWORK, NO_THINGS}
-
- private volatile int countFailed = 0;
- private volatile int countSuccess = 0;
-
- private volatile FlattrThing extraFlattrThing;
-
- /**
- * Only relevant if just one thing is flattrd
- */
- private volatile FlattrException exception;
-
- /**
- * Creates a new FlattrClickWorker which will only flattr all things in the queue.
- * <p/>
- * The FlattrClickWorker has to be started by calling executeAsync().
- *
- * @param context A context for accessing the database and posting notifications. Must not be null.
- */
- public FlattrClickWorker(Context context) {
- Validate.notNull(context);
- this.context = context.getApplicationContext();
- }
-
- /**
- * Creates a new FlattrClickWorker which will flattr all things in the queue and one additional
- * FlattrThing.
- * <p/>
- * The FlattrClickWorker has to be started by calling executeAsync().
- *
- * @param context A context for accessing the database and posting notifications. Must not be null.
- * @param extraFlattrThing The additional thing to flattr
- */
- public FlattrClickWorker(Context context, FlattrThing extraFlattrThing) {
- this(context);
- this.extraFlattrThing = extraFlattrThing;
- }
-
-
- @Override
- protected ExitCode doInBackground(Void... params) {
-
- if (!FlattrUtils.hasToken()) {
- return ExitCode.NO_TOKEN;
- }
-
- if (!NetworkUtils.networkAvailable(context)) {
- return ExitCode.NO_NETWORK;
- }
-
- final List<FlattrThing> flattrQueue = DBReader.getFlattrQueue(context);
- if (extraFlattrThing != null) {
- flattrQueue.add(extraFlattrThing);
- } else if (flattrQueue.size() == 1) {
- // if only one item is flattrd, the report can specifically mentioned that this item has failed
- extraFlattrThing = flattrQueue.get(0);
- }
-
- if (flattrQueue.isEmpty()) {
- return ExitCode.NO_THINGS;
- }
-
- List<Future> dbFutures = new LinkedList<Future>();
- for (FlattrThing thing : flattrQueue) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Processing " + thing.getTitle());
-
- try {
- thing.getFlattrStatus().setUnflattred(); // pop from queue to prevent unflattrable things from getting stuck in flattr queue infinitely
- FlattrUtils.clickUrl(context, thing.getPaymentLink());
- thing.getFlattrStatus().setFlattred();
- publishProgress(R.string.flattr_click_success);
- countSuccess++;
-
- } catch (FlattrException e) {
- e.printStackTrace();
- countFailed++;
- if (countFailed == 1) {
- exception = e;
- }
- }
-
- Future<?> f = DBWriter.setFlattredStatus(context, thing, false);
- if (f != null) {
- dbFutures.add(f);
- }
- }
-
- for (Future f : dbFutures) {
- try {
- f.get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
-
- return ExitCode.EXIT_NORMAL;
- }
-
- @Override
- protected void onPostExecute(ExitCode exitCode) {
- super.onPostExecute(exitCode);
- switch (exitCode) {
- case EXIT_NORMAL:
- if (countFailed > 0) {
- postFlattrFailedNotification();
- }
- break;
- case NO_NETWORK:
- postToastNotification(R.string.flattr_click_enqueued);
- break;
- case NO_TOKEN:
- postNoTokenNotification();
- break;
- case NO_THINGS: // nothing to notify here
- break;
- }
- }
-
- @Override
- protected void onProgressUpdate(Integer... values) {
- super.onProgressUpdate(values);
- postToastNotification(values[0]);
- }
-
- private void postToastNotification(int msg) {
- Toast.makeText(context, context.getString(msg), Toast.LENGTH_LONG).show();
- }
-
- private void postNoTokenNotification() {
- PendingIntent contentIntent = PendingIntent.getActivity(context, 0, new Intent(context, FlattrAuthActivity.class), 0);
-
- Notification notification = new NotificationCompat.Builder(context)
- .setStyle(new NotificationCompat.BigTextStyle().bigText(context.getString(R.string.no_flattr_token_notification_msg)))
- .setContentIntent(contentIntent)
- .setContentTitle(context.getString(R.string.no_flattr_token_title))
- .setTicker(context.getString(R.string.no_flattr_token_title))
- .setSmallIcon(R.drawable.stat_notify_sync_error)
- .setOngoing(false)
- .setAutoCancel(true)
- .build();
- ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, notification);
- }
-
- private void postFlattrFailedNotification() {
- if (countFailed == 0) {
- return;
- }
-
- PendingIntent contentIntent = PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0);
- String title;
- String subtext;
-
- if (countFailed == 1) {
- title = context.getString(R.string.flattrd_failed_label);
- String exceptionMsg = (exception.getMessage() != null) ? exception.getMessage() : "";
- subtext = context.getString(R.string.flattr_click_failure, extraFlattrThing.getTitle())
- + "\n" + exceptionMsg;
- } else {
- title = context.getString(R.string.flattrd_label);
- subtext = context.getString(R.string.flattr_click_success_count, countSuccess) + "\n"
- + context.getString(R.string.flattr_click_failure_count, countFailed);
- }
-
- Notification notification = new NotificationCompat.Builder(context)
- .setStyle(new NotificationCompat.BigTextStyle().bigText(subtext))
- .setContentIntent(contentIntent)
- .setContentTitle(title)
- .setTicker(title)
- .setSmallIcon(R.drawable.stat_notify_sync_error)
- .setOngoing(false)
- .setAutoCancel(true)
- .build();
- ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, notification);
- }
-
-
- /**
- * Starts the FlattrClickWorker as an AsyncTask.
- */
- @TargetApi(11)
- public void executeAsync() {
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- execute();
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrStatusFetcher.java b/app/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrStatusFetcher.java
deleted file mode 100644
index ddc4370e6..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrStatusFetcher.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package de.danoeh.antennapod.core.asynctask;
-
-import android.content.Context;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
-import org.shredzone.flattr4j.exception.FlattrException;
-import org.shredzone.flattr4j.model.Flattr;
-
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-
-/**
- * Fetch list of flattred things and flattr status in database in a background thread.
- */
-
-public class FlattrStatusFetcher extends Thread {
- protected static final String TAG = "FlattrStatusFetcher";
- protected Context context;
-
- public FlattrStatusFetcher(Context context) {
- super();
- this.context = context;
- }
-
- @Override
- public void run() {
- if (BuildConfig.DEBUG) Log.d(TAG, "Starting background work: Retrieving Flattr status");
-
- Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
-
- try {
- List<Flattr> flattredThings = FlattrUtils.retrieveFlattredThings();
- DBWriter.setFlattredStatus(context, flattredThings).get();
- } catch (FlattrException e) {
- e.printStackTrace();
- Log.d(TAG, "flattrQueue exception retrieving list with flattred items " + e.getMessage());
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
-
- if (BuildConfig.DEBUG) Log.d(TAG, "Finished background work: Retrieved Flattr status");
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrTokenFetcher.java b/app/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrTokenFetcher.java
deleted file mode 100644
index 6f8319c7d..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrTokenFetcher.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package de.danoeh.antennapod.core.asynctask;
-
-
-import android.annotation.SuppressLint;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.FlattrAuthActivity;
-import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
-import org.shredzone.flattr4j.exception.FlattrException;
-import org.shredzone.flattr4j.oauth.AccessToken;
-import org.shredzone.flattr4j.oauth.AndroidAuthenticator;
-
-/** Fetches the access token in the background in order to avoid networkOnMainThread exception. */
-
-public class FlattrTokenFetcher extends AsyncTask<Void, Void, AccessToken> {
- private static final String TAG = "FlattrTokenFetcher";
- Context context;
- AndroidAuthenticator auth;
- AccessToken token;
- Uri uri;
- ProgressDialog dialog;
- FlattrException exception;
-
- public FlattrTokenFetcher(Context context, AndroidAuthenticator auth, Uri uri) {
- super();
- this.context = context;
- this.auth = auth;
- this.uri = uri;
- }
-
- @Override
- protected void onPostExecute(AccessToken result) {
- if (result != null) {
- FlattrUtils.storeToken(result);
- }
- dialog.dismiss();
- if (exception == null) {
- FlattrAuthActivity instance = FlattrAuthActivity.getInstance();
- if (instance != null) {
- instance.handleAuthenticationSuccess();
- } else {
- Log.e(TAG, "FlattrAuthActivity instance was null");
- }
- } else {
- FlattrUtils.showErrorDialog(context, exception.getMessage());
- }
- }
-
-
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- dialog = new ProgressDialog(context);
- dialog.setMessage(context.getString(R.string.processing_label));
- dialog.setIndeterminate(true);
- dialog.setCancelable(false);
- dialog.show();
- }
-
-
-
- @Override
- protected AccessToken doInBackground(Void... params) {
- try {
- token = auth.fetchAccessToken(uri);
- } catch (FlattrException e) {
- e.printStackTrace();
- exception = e;
- return null;
- }
- if (token != null) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Successfully got token");
- return token;
- } else {
- Log.w(TAG, "Flattr token was null");
- return null;
- }
- }
-
- @SuppressLint("NewApi")
- public void executeAsync() {
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- execute();
- }
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/asynctask/OpmlExportWorker.java b/app/src/main/java/de/danoeh/antennapod/core/asynctask/OpmlExportWorker.java
deleted file mode 100644
index 9f887bda6..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/asynctask/OpmlExportWorker.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package de.danoeh.antennapod.core.asynctask;
-
-import android.annotation.SuppressLint;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.os.AsyncTask;
-import android.util.Log;
-import de.danoeh.antennapod.PodcastApp;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.opml.OpmlWriter;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.util.LangUtils;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-
-/** Writes an OPML file into the export directory in the background. */
-public class OpmlExportWorker extends AsyncTask<Void, Void, Void> {
- private static final String TAG = "OpmlExportWorker";
- private static final String DEFAULT_OUTPUT_NAME = "antennapod-feeds.opml";
- private Context context;
- private File output;
-
- private ProgressDialog progDialog;
- private Exception exception;
-
- public OpmlExportWorker(Context context, File output) {
- this.context = context;
- this.output = output;
- }
-
- public OpmlExportWorker(Context context) {
- this.context = context;
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- OpmlWriter opmlWriter = new OpmlWriter();
- if (output == null) {
- output = new File(
- UserPreferences.getDataFolder(context, PodcastApp.EXPORT_DIR),
- DEFAULT_OUTPUT_NAME);
- if (output.exists()) {
- Log.w(TAG, "Overwriting previously exported file.");
- output.delete();
- }
- }
- OutputStreamWriter writer = null;
- try {
- writer = new OutputStreamWriter(new FileOutputStream(output), LangUtils.UTF_8);
- opmlWriter.writeDocument(DBReader.getFeedList(context), writer);
- } catch (IOException e) {
- e.printStackTrace();
- exception = e;
- } finally {
- if (writer != null) {
- try {
- writer.close();
- } catch (IOException ioe) {
- exception = ioe;
- }
- }
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- progDialog.dismiss();
- AlertDialog.Builder alert = new AlertDialog.Builder(context)
- .setNeutralButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- dialog.dismiss();
- }
- });
- if (exception != null) {
- alert.setTitle(R.string.export_error_label);
- alert.setMessage(exception.getMessage());
- } else {
- alert.setTitle(R.string.opml_export_success_title);
- alert.setMessage(context
- .getString(R.string.opml_export_success_sum)
- + output.toString());
- }
- alert.create().show();
- }
-
- @Override
- protected void onPreExecute() {
- progDialog = new ProgressDialog(context);
- progDialog.setMessage(context.getString(R.string.exporting_label));
- progDialog.setIndeterminate(true);
- progDialog.show();
- }
-
- @SuppressLint("NewApi")
- public void executeAsync() {
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- executeOnExecutor(THREAD_POOL_EXECUTOR);
- } else {
- execute();
- }
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoImageResource.java b/app/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoImageResource.java
deleted file mode 100644
index c0d8049db..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoImageResource.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package de.danoeh.antennapod.core.asynctask;
-
-import android.net.Uri;
-
-/**
- * Classes that implement this interface provide access to an image resource that can
- * be loaded by the Picasso library.
- */
-public interface PicassoImageResource {
-
- /**
- * This scheme should be used by PicassoImageResources to
- * indicate that the image Uri points to a file that is not an image
- * (e.g. a media file). This workaround is needed so that the Picasso library
- * loads these Uri with a Downloader instead of trying to load it directly.
- * <p/>
- * For example implementations, see FeedMedia or ExternalMedia.
- */
- public static final String SCHEME_MEDIA = "media";
-
-
- /**
- * Parameter key for an encoded fallback Uri. This Uri MUST point to a local image file
- */
- public static final String PARAM_FALLBACK = "fallback";
-
- /**
- * Returns a Uri to the image or null if no image is available.
- * <p/>
- * The Uri can either be an HTTP-URL, a URL pointing to a local image file or
- * a non-image file (see SCHEME_MEDIA for more details).
- * <p/>
- * The Uri can also have an optional fallback-URL if loading the default URL
- * failed (see PARAM_FALLBACK).
- */
- public Uri getImageUri();
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java b/app/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java
deleted file mode 100644
index 6ace92800..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java
+++ /dev/null
@@ -1,152 +0,0 @@
-package de.danoeh.antennapod.core.asynctask;
-
-import android.content.Context;
-import android.media.MediaMetadataRetriever;
-import android.net.Uri;
-import android.util.Log;
-import android.webkit.MimeTypeMap;
-
-import com.squareup.picasso.Cache;
-import com.squareup.picasso.Downloader;
-import com.squareup.picasso.LruCache;
-import com.squareup.picasso.OkHttpDownloader;
-import com.squareup.picasso.Picasso;
-
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.Validate;
-
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-/**
- * Provides access to Picasso instances.
- */
-public class PicassoProvider {
- private static final String TAG = "PicassoProvider";
-
- private static final boolean DEBUG = false;
-
- private static ExecutorService executorService;
- private static Cache memoryCache;
-
- private static Picasso defaultPicassoInstance;
- private static Picasso mediaMetadataPicassoInstance;
-
- private static synchronized ExecutorService getExecutorService() {
- if (executorService == null) {
- executorService = Executors.newFixedThreadPool(3);
- }
- return executorService;
- }
-
- private static synchronized Cache getMemoryCache(Context context) {
- if (memoryCache == null) {
- memoryCache = new LruCache(context);
- }
- return memoryCache;
- }
-
- /**
- * Returns a Picasso instance that uses an OkHttpDownloader. This instance can only load images
- * from image files.
- * <p/>
- * This instance should be used as long as no images from media files are loaded.
- */
- public static synchronized Picasso getDefaultPicassoInstance(Context context) {
- Validate.notNull(context);
- if (defaultPicassoInstance == null) {
- defaultPicassoInstance = new Picasso.Builder(context)
- .indicatorsEnabled(DEBUG)
- .loggingEnabled(DEBUG)
- .downloader(new OkHttpDownloader(context))
- .executor(getExecutorService())
- .memoryCache(getMemoryCache(context))
- .listener(new Picasso.Listener() {
- @Override
- public void onImageLoadFailed(Picasso picasso, Uri uri, Exception e) {
- Log.e(TAG, "Failed to load Uri:" + uri.toString());
- e.printStackTrace();
- }
- })
- .build();
- }
- return defaultPicassoInstance;
- }
-
- /**
- * Returns a Picasso instance that uses a MediaMetadataRetriever if the given Uri is a media file
- * and a default OkHttpDownloader otherwise.
- */
- public static synchronized Picasso getMediaMetadataPicassoInstance(Context context) {
- Validate.notNull(context);
- if (mediaMetadataPicassoInstance == null) {
- mediaMetadataPicassoInstance = new Picasso.Builder(context)
- .indicatorsEnabled(DEBUG)
- .loggingEnabled(DEBUG)
- .downloader(new MediaMetadataDownloader(context))
- .executor(getExecutorService())
- .memoryCache(getMemoryCache(context))
- .listener(new Picasso.Listener() {
- @Override
- public void onImageLoadFailed(Picasso picasso, Uri uri, Exception e) {
- Log.e(TAG, "Failed to load Uri:" + uri.toString());
- e.printStackTrace();
- }
- })
- .build();
- }
- return mediaMetadataPicassoInstance;
- }
-
- private static class MediaMetadataDownloader implements Downloader {
-
- private static final String TAG = "MediaMetadataDownloader";
-
- private final OkHttpDownloader okHttpDownloader;
-
- public MediaMetadataDownloader(Context context) {
- Validate.notNull(context);
- okHttpDownloader = new OkHttpDownloader(context);
- }
-
- @Override
- public Response load(Uri uri, boolean b) throws IOException {
- if (StringUtils.equals(uri.getScheme(), PicassoImageResource.SCHEME_MEDIA)) {
- String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(FilenameUtils.getExtension(uri.getLastPathSegment()));
- if (StringUtils.startsWith(type, "image")) {
- File imageFile = new File(uri.toString());
- return new Response(new BufferedInputStream(new FileInputStream(imageFile)), true, imageFile.length());
- } else {
- MediaMetadataRetriever mmr = new MediaMetadataRetriever();
- mmr.setDataSource(uri.getPath());
- byte[] data = mmr.getEmbeddedPicture();
- mmr.release();
-
- if (data != null) {
- return new Response(new ByteArrayInputStream(data), true, data.length);
- } else {
-
- // check for fallback Uri
- String fallbackParam = uri.getQueryParameter(PicassoImageResource.PARAM_FALLBACK);
-
- if (fallbackParam != null) {
- String fallback = Uri.decode(Uri.parse(fallbackParam).getPath());
- if (fallback != null) {
- File imageFile = new File(fallback);
- return new Response(new BufferedInputStream(new FileInputStream(imageFile)), true, imageFile.length());
- }
- }
- return null;
- }
- }
- }
- return okHttpDownloader.load(uri, b);
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java b/app/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java
deleted file mode 100644
index 72b5066b3..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java
+++ /dev/null
@@ -1,211 +0,0 @@
-package de.danoeh.antennapod.core.backup;
-
-import android.app.backup.BackupAgentHelper;
-import android.app.backup.BackupDataInputStream;
-import android.app.backup.BackupDataOutput;
-import android.app.backup.BackupHelper;
-import android.content.Context;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import de.danoeh.antennapod.BuildConfig;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.io.Writer;
-import java.math.BigInteger;
-import java.security.DigestInputStream;
-import java.security.DigestOutputStream;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.opml.OpmlElement;
-import de.danoeh.antennapod.core.opml.OpmlReader;
-import de.danoeh.antennapod.core.opml.OpmlWriter;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DownloadRequestException;
-import de.danoeh.antennapod.core.storage.DownloadRequester;
-import de.danoeh.antennapod.core.util.LangUtils;
-
-public class OpmlBackupAgent extends BackupAgentHelper {
- private static final String OPML_BACKUP_KEY = "opml";
-
- @Override
- public void onCreate() {
- addHelper(OPML_BACKUP_KEY, new OpmlBackupHelper(this));
- }
-
- private static final void LOGD(String tag, String msg) {
- if (BuildConfig.DEBUG && Log.isLoggable(tag, Log.DEBUG)) {
- Log.d(tag, msg);
- }
- }
-
- private static final void LOGD(String tag, String msg, Throwable tr) {
- if (BuildConfig.DEBUG && Log.isLoggable(tag, Log.DEBUG)) {
- Log.d(tag, msg, tr);
- }
- }
-
- /** Class for backing up and restoring the OPML file. */
- private static class OpmlBackupHelper implements BackupHelper {
- private static final String TAG = "OpmlBackupHelper";
-
- private static final String OPML_ENTITY_KEY = "antennapod-feeds.opml";
-
- private final Context mContext;
-
- /** Checksum of restored OPML file */
- private byte[] mChecksum;
-
- public OpmlBackupHelper(Context context) {
- mContext = context;
- }
-
- @Override
- public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) {
- Log.d(TAG, "Performing backup");
- ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
- MessageDigest digester = null;
- Writer writer;
-
- try {
- digester = MessageDigest.getInstance("MD5");
- writer = new OutputStreamWriter(new DigestOutputStream(byteStream, digester),
- LangUtils.UTF_8);
- } catch (NoSuchAlgorithmException e) {
- writer = new OutputStreamWriter(byteStream, LangUtils.UTF_8);
- }
-
- try {
- // Write OPML
- new OpmlWriter().writeDocument(DBReader.getFeedList(mContext), writer);
-
- // Compare checksum of new and old file to see if we need to perform a backup at all
- if (digester != null) {
- byte[] newChecksum = digester.digest();
- LOGD(TAG, "New checksum: " + new BigInteger(1, newChecksum).toString(16));
-
- // Get the old checksum
- if (oldState != null) {
- FileInputStream inState = new FileInputStream(oldState.getFileDescriptor());
- int len = inState.read();
-
- if (len != -1) {
- byte[] oldChecksum = new byte[len];
- inState.read(oldChecksum);
- LOGD(TAG, "Old checksum: " + new BigInteger(1, oldChecksum).toString(16));
-
- if (Arrays.equals(oldChecksum, newChecksum)) {
- LOGD(TAG, "Checksums are the same; won't backup");
- return;
- }
- }
- }
-
- writeNewStateDescription(newState, newChecksum);
- }
-
- LOGD(TAG, "Backing up OPML");
- byte[] bytes = byteStream.toByteArray();
- data.writeEntityHeader(OPML_ENTITY_KEY, bytes.length);
- data.writeEntityData(bytes, bytes.length);
- } catch (IOException e) {
- Log.e(TAG, "Error during backup", e);
- } finally {
- if (writer != null) {
- try {
- writer.close();
- } catch (IOException e) {
- }
- }
- }
- }
-
- @Override
- public void restoreEntity(BackupDataInputStream data) {
- LOGD(TAG, "Backup restore");
-
- if (!OPML_ENTITY_KEY.equals(data.getKey())) {
- LOGD(TAG, "Unknown entity key: " + data.getKey());
- return;
- }
-
- MessageDigest digester = null;
- Reader reader;
-
- try {
- digester = MessageDigest.getInstance("MD5");
- reader = new InputStreamReader(new DigestInputStream(data, digester),
- LangUtils.UTF_8);
- } catch (NoSuchAlgorithmException e) {
- reader = new InputStreamReader(data, LangUtils.UTF_8);
- }
-
- try {
- ArrayList<OpmlElement> opmlElements = new OpmlReader().readDocument(reader);
- mChecksum = digester == null ? null : digester.digest();
- DownloadRequester downloader = DownloadRequester.getInstance();
- Date lastUpdated = new Date();
-
- for (OpmlElement opmlElem : opmlElements) {
- Feed feed = new Feed(opmlElem.getXmlUrl(), lastUpdated, opmlElem.getText());
-
- try {
- downloader.downloadFeed(mContext, feed);
- } catch (DownloadRequestException e) {
- LOGD(TAG, "Error while restoring/downloading feed", e);
- }
- }
- } catch (XmlPullParserException e) {
- Log.e(TAG, "Error while parsing the OPML file", e);
- } catch (IOException e) {
- Log.e(TAG, "Failed to restore OPML backup", e);
- } finally {
- if (reader != null) {
- try {
- reader.close();
- } catch (IOException e) {
- }
- }
- }
- }
-
- @Override
- public void writeNewStateDescription(ParcelFileDescriptor newState) {
- writeNewStateDescription(newState, mChecksum);
- }
-
- /**
- * Writes the new state description, which is the checksum of the OPML file.
- *
- * @param newState
- * @param checksum
- */
- private void writeNewStateDescription(ParcelFileDescriptor newState, byte[] checksum) {
- if (checksum == null) {
- return;
- }
-
- try {
- FileOutputStream outState = new FileOutputStream(newState.getFileDescriptor());
- outState.write(checksum.length);
- outState.write(checksum);
- outState.flush();
- outState.close();
- } catch (IOException e) {
- Log.e(TAG, "Failed to write new state description", e);
- }
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java b/app/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java
deleted file mode 100644
index e51d70708..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package de.danoeh.antennapod.core.dialog;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-
-/**
- * Creates an AlertDialog which asks the user to confirm something. Other
- * classes can handle events like confirmation or cancellation.
- */
-public abstract class ConfirmationDialog {
- private static final String TAG = "ConfirmationDialog";
-
- Context context;
- int titleId;
- int messageId;
-
- public ConfirmationDialog(Context context, int titleId, int messageId) {
- this.context = context;
- this.titleId = titleId;
- this.messageId = messageId;
- }
-
- public void onCancelButtonPressed(DialogInterface dialog) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Dialog was cancelled");
- dialog.dismiss();
- }
-
- public abstract void onConfirmButtonPressed(DialogInterface dialog);
-
- public final AlertDialog createNewDialog() {
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(titleId);
- builder.setMessage(messageId);
- builder.setPositiveButton(R.string.confirm_label,
- new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- onConfirmButtonPressed(dialog);
- }
- });
- builder.setNegativeButton(R.string.cancel_label,
- new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- onCancelButtonPressed(dialog);
- }
- });
- builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
-
- @Override
- public void onCancel(DialogInterface dialog) {
- onCancelButtonPressed(dialog);
- }
- });
- return builder.create();
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/dialog/DownloadRequestErrorDialogCreator.java b/app/src/main/java/de/danoeh/antennapod/core/dialog/DownloadRequestErrorDialogCreator.java
deleted file mode 100644
index a1c3a4c6a..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/dialog/DownloadRequestErrorDialogCreator.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package de.danoeh.antennapod.core.dialog;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import de.danoeh.antennapod.R;
-
-/** Creates Alert Dialogs if a DownloadRequestException has happened. */
-public class DownloadRequestErrorDialogCreator {
- private DownloadRequestErrorDialogCreator() {
- }
-
- public static void newRequestErrorDialog(Context context,
- String errorMessage) {
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setNeutralButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- }
- })
- .setTitle(R.string.download_error_request_error)
- .setMessage(
- context.getString(R.string.download_request_error_dialog_message_prefix)
- + errorMessage);
- builder.create().show();
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java b/app/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java
deleted file mode 100644
index ce3352ed6..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package de.danoeh.antennapod.core.feed;
-
-public abstract class Chapter extends FeedComponent {
-
- /** Defines starting point in milliseconds. */
- protected long start;
- protected String title;
- protected String link;
-
- public Chapter() {
- }
-
- public Chapter(long start) {
- super();
- this.start = start;
- }
-
- public Chapter(long start, String title, FeedItem item, String link) {
- super();
- this.start = start;
- this.title = title;
- this.link = link;
- }
-
- public abstract int getChapterType();
-
- public long getStart() {
- return start;
- }
-
- public String getTitle() {
- return title;
- }
-
- public String getLink() {
- return link;
- }
-
- public void setStart(long start) {
- this.start = start;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public void setLink(String link) {
- this.link = link;
- }
-
- @Override
- public String getHumanReadableIdentifier() {
- return title;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java b/app/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java
deleted file mode 100644
index 65c55a361..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java
+++ /dev/null
@@ -1,140 +0,0 @@
-package de.danoeh.antennapod.core.feed;
-
-import android.os.Handler;
-import android.util.Log;
-
-import org.apache.commons.lang3.Validate;
-
-import de.danoeh.antennapod.BuildConfig;
-
-import java.util.AbstractQueue;
-import java.util.Observable;
-import java.util.Observer;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-/**
- * Notifies its observers about changes in the feed database. Observers can
- * register by retrieving an instance of this class and registering an
- * EventListener. When new events arrive, the EventDistributor will process the
- * event queue in a handler that runs on the main thread. The observers will only
- * be notified once if the event queue contains multiple elements.
- *
- * Events can be sent with the send* methods.
- */
-public class EventDistributor extends Observable {
- private static final String TAG = "EventDistributor";
-
- public static final int FEED_LIST_UPDATE = 1;
- public static final int UNREAD_ITEMS_UPDATE = 2;
- public static final int QUEUE_UPDATE = 4;
- public static final int DOWNLOADLOG_UPDATE = 8;
- public static final int PLAYBACK_HISTORY_UPDATE = 16;
- public static final int DOWNLOAD_QUEUED = 32;
- public static final int DOWNLOAD_HANDLED = 64;
-
- private Handler handler;
- private AbstractQueue<Integer> events;
-
- private static EventDistributor instance;
-
- private EventDistributor() {
- this.handler = new Handler();
- events = new ConcurrentLinkedQueue<Integer>();
- }
-
- public static synchronized EventDistributor getInstance() {
- if (instance == null) {
- instance = new EventDistributor();
- }
- return instance;
- }
-
- public void register(EventListener el) {
- addObserver(el);
- }
-
- public void unregister(EventListener el) {
- deleteObserver(el);
- }
-
- public void addEvent(Integer i) {
- events.offer(i);
- handler.post(new Runnable() {
-
- @Override
- public void run() {
- processEventQueue();
- }
- });
- }
-
- private void processEventQueue() {
- Integer result = 0;
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Processing event queue. Number of events: "
- + events.size());
- for (Integer current = events.poll(); current != null; current = events
- .poll()) {
- result |= current;
- }
- if (result != 0) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Notifying observers. Data: " + result);
- setChanged();
- notifyObservers(result);
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Event queue didn't contain any new events. Observers will not be notified.");
- }
- }
-
- @Override
- public void addObserver(Observer observer) {
- super.addObserver(observer);
- Validate.isInstanceOf(EventListener.class, observer);
- }
-
- public void sendDownloadQueuedBroadcast() {
- addEvent(DOWNLOAD_QUEUED);
- }
-
- public void sendUnreadItemsUpdateBroadcast() {
- addEvent(UNREAD_ITEMS_UPDATE);
- }
-
- public void sendQueueUpdateBroadcast() {
- addEvent(QUEUE_UPDATE);
- }
-
- public void sendFeedUpdateBroadcast() {
- addEvent(FEED_LIST_UPDATE);
- }
-
- public void sendPlaybackHistoryUpdateBroadcast() {
- addEvent(PLAYBACK_HISTORY_UPDATE);
- }
-
- public void sendDownloadLogUpdateBroadcast() {
- addEvent(DOWNLOADLOG_UPDATE);
- }
-
- public void sendDownloadHandledBroadcast() {
- addEvent(DOWNLOAD_HANDLED);
- }
-
- public static abstract class EventListener implements Observer {
-
- @Override
- public void update(Observable observable, Object data) {
- if (observable instanceof EventDistributor
- && data instanceof Integer) {
- update((EventDistributor) observable, (Integer) data);
- }
- }
-
- public abstract void update(EventDistributor eventDistributor,
- Integer arg);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/feed/Feed.java b/app/src/main/java/de/danoeh/antennapod/core/feed/Feed.java
deleted file mode 100644
index 3f83ab8b6..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/feed/Feed.java
+++ /dev/null
@@ -1,445 +0,0 @@
-package de.danoeh.antennapod.core.feed;
-
-import android.content.Context;
-import android.net.Uri;
-
-import de.danoeh.antennapod.core.asynctask.PicassoImageResource;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.util.EpisodeFilter;
-import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
-import de.danoeh.antennapod.core.util.flattr.FlattrThing;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-/**
- * Data Object for a whole feed
- *
- * @author daniel
- */
-public class Feed extends FeedFile implements FlattrThing, PicassoImageResource {
- public static final int FEEDFILETYPE_FEED = 0;
- public static final String TYPE_RSS2 = "rss";
- public static final String TYPE_RSS091 = "rss";
- public static final String TYPE_ATOM1 = "atom";
-
- private String title;
- /**
- * Contains 'id'-element in Atom feed.
- */
- private String feedIdentifier;
- /**
- * Link to the website.
- */
- private String link;
- private String description;
- private String language;
- /**
- * Name of the author
- */
- private String author;
- private FeedImage image;
- private List<FeedItem> items;
- /**
- * Date of last refresh.
- */
- private Date lastUpdate;
- private FlattrStatus flattrStatus;
- private String paymentLink;
- /**
- * Feed type, for example RSS 2 or Atom
- */
- private String type;
-
- /**
- * Feed preferences
- */
- private FeedPreferences preferences;
-
- /**
- * This constructor is used for restoring a feed from the database.
- */
- public Feed(long id, Date lastUpdate, String title, String link, String description, String paymentLink,
- String author, String language, String type, String feedIdentifier, FeedImage image, String fileUrl,
- String downloadUrl, boolean downloaded, FlattrStatus status) {
- super(fileUrl, downloadUrl, downloaded);
- this.id = id;
- this.title = title;
- if (lastUpdate != null) {
- this.lastUpdate = (Date) lastUpdate.clone();
- } else {
- this.lastUpdate = null;
- }
- this.link = link;
- this.description = description;
- this.paymentLink = paymentLink;
- this.author = author;
- this.language = language;
- this.type = type;
- this.feedIdentifier = feedIdentifier;
- this.image = image;
- this.flattrStatus = status;
-
- items = new ArrayList<FeedItem>();
- }
-
- /**
- * This constructor is used for test purposes and uses a default flattr status object.
- */
- public Feed(long id, Date lastUpdate, String title, String link, String description, String paymentLink,
- String author, String language, String type, String feedIdentifier, FeedImage image, String fileUrl,
- String downloadUrl, boolean downloaded) {
- this(id, lastUpdate, title, link, description, paymentLink, author, language, type, feedIdentifier, image,
- fileUrl, downloadUrl, downloaded, new FlattrStatus());
- }
-
- /**
- * This constructor can be used when parsing feed data. Only the 'lastUpdate' and 'items' field are initialized.
- */
- public Feed() {
- super();
- items = new ArrayList<FeedItem>();
- lastUpdate = new Date();
- this.flattrStatus = new FlattrStatus();
- }
-
- /**
- * This constructor is used for requesting a feed download (it must not be used for anything else!). It should NOT be
- * used if the title of the feed is already known.
- */
- public Feed(String url, Date lastUpdate) {
- super(null, url, false);
- this.lastUpdate = (lastUpdate != null) ? (Date) lastUpdate.clone() : null;
- this.flattrStatus = new FlattrStatus();
- }
-
- /**
- * This constructor is used for requesting a feed download (it must not be used for anything else!). It should be
- * used if the title of the feed is already known.
- */
- public Feed(String url, Date lastUpdate, String title) {
- this(url, lastUpdate);
- this.title = title;
- this.flattrStatus = new FlattrStatus();
- }
-
- /**
- * This constructor is used for requesting a feed download (it must not be used for anything else!). It should be
- * used if the title of the feed is already known.
- */
- public Feed(String url, Date lastUpdate, String title, String username, String password) {
- this(url, lastUpdate, title);
- preferences = new FeedPreferences(0, true, username, password);
- }
-
- /**
- * Returns the number of FeedItems where 'read' is false. If the 'display
- * only episodes' - preference is set to true, this method will only count
- * items with episodes.
- */
- public int getNumOfNewItems() {
- int count = 0;
- for (FeedItem item : items) {
- if (item.getState() == FeedItem.State.NEW) {
- if (!UserPreferences.isDisplayOnlyEpisodes()
- || item.getMedia() != null) {
- count++;
- }
- }
- }
- return count;
- }
-
- /**
- * Returns the number of FeedItems where the media started to play but
- * wasn't finished yet.
- */
- public int getNumOfStartedItems() {
- int count = 0;
-
- for (FeedItem item : items) {
- FeedItem.State state = item.getState();
- if (state == FeedItem.State.IN_PROGRESS
- || state == FeedItem.State.PLAYING) {
- count++;
- }
- }
- return count;
- }
-
- /**
- * Returns true if at least one item in the itemlist is unread.
- *
- * @param enableEpisodeFilter true if this method should only count items with episodes if
- * the 'display only episodes' - preference is set to true by the
- * user.
- */
- public boolean hasNewItems(boolean enableEpisodeFilter) {
- for (FeedItem item : items) {
- if (item.getState() == FeedItem.State.NEW) {
- if (!(enableEpisodeFilter && UserPreferences
- .isDisplayOnlyEpisodes()) || item.getMedia() != null) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Returns the number of FeedItems.
- *
- * @param enableEpisodeFilter true if this method should only count items with episodes if
- * the 'display only episodes' - preference is set to true by the
- * user.
- */
- public int getNumOfItems(boolean enableEpisodeFilter) {
- if (enableEpisodeFilter && UserPreferences.isDisplayOnlyEpisodes()) {
- return EpisodeFilter.countItemsWithEpisodes(items);
- } else {
- return items.size();
- }
- }
-
- /**
- * Returns the item at the specified index.
- *
- * @param enableEpisodeFilter true if this method should ignore items without episdodes if
- * the episodes filter has been enabled by the user.
- */
- public FeedItem getItemAtIndex(boolean enableEpisodeFilter, int position) {
- if (enableEpisodeFilter && UserPreferences.isDisplayOnlyEpisodes()) {
- return EpisodeFilter.accessEpisodeByIndex(items, position);
- } else {
- return items.get(position);
- }
- }
-
- /**
- * Returns the value that uniquely identifies this Feed. If the
- * feedIdentifier attribute is not null, it will be returned. Else it will
- * try to return the title. If the title is not given, it will use the link
- * of the feed.
- */
- public String getIdentifyingValue() {
- if (feedIdentifier != null && !feedIdentifier.isEmpty()) {
- return feedIdentifier;
- } else if (download_url != null && !download_url.isEmpty()) {
- return download_url;
- } else if (title != null && !title.isEmpty()) {
- return title;
- } else {
- return link;
- }
- }
-
- @Override
- public String getHumanReadableIdentifier() {
- if (title != null) {
- return title;
- } else {
- return download_url;
- }
- }
-
- public void updateFromOther(Feed other) {
- super.updateFromOther(other);
- if (other.title != null) {
- title = other.title;
- }
- if (other.feedIdentifier != null) {
- feedIdentifier = other.feedIdentifier;
- }
- if (other.link != null) {
- link = other.link;
- }
- if (other.description != null) {
- description = other.description;
- }
- if (other.language != null) {
- language = other.language;
- }
- if (other.author != null) {
- author = other.author;
- }
- if (other.paymentLink != null) {
- paymentLink = other.paymentLink;
- }
- if (other.flattrStatus != null) {
- flattrStatus = other.flattrStatus;
- }
- }
-
- public boolean compareWithOther(Feed other) {
- if (super.compareWithOther(other)) {
- return true;
- }
- if (!title.equals(other.title)) {
- return true;
- }
- if (other.feedIdentifier != null) {
- if (feedIdentifier == null
- || !feedIdentifier.equals(other.feedIdentifier)) {
- return true;
- }
- }
- if (other.link != null) {
- if (link == null || !link.equals(other.link)) {
- return true;
- }
- }
- if (other.description != null) {
- if (description == null || !description.equals(other.description)) {
- return true;
- }
- }
- if (other.language != null) {
- if (language == null || !language.equals(other.language)) {
- return true;
- }
- }
- if (other.author != null) {
- if (author == null || !author.equals(other.author)) {
- return true;
- }
- }
- if (other.paymentLink != null) {
- if (paymentLink == null || !paymentLink.equals(other.paymentLink)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public int getTypeAsInt() {
- return FEEDFILETYPE_FEED;
- }
-
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public String getLink() {
- return link;
- }
-
- public void setLink(String link) {
- this.link = link;
- }
-
- public String getDescription() {
- return description;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-
- public FeedImage getImage() {
- return image;
- }
-
- public void setImage(FeedImage image) {
- this.image = image;
- }
-
- public List<FeedItem> getItems() {
- return items;
- }
-
- public void setItems(List<FeedItem> list) {
- this.items = list;
- }
-
- public Date getLastUpdate() {
- return (lastUpdate != null) ? (Date) lastUpdate.clone() : null;
- }
-
- public void setLastUpdate(Date lastUpdate) {
- this.lastUpdate = (lastUpdate != null) ? (Date) lastUpdate.clone() : null;
- }
-
- public String getFeedIdentifier() {
- return feedIdentifier;
- }
-
- public void setFeedIdentifier(String feedIdentifier) {
- this.feedIdentifier = feedIdentifier;
- }
-
- public void setFlattrStatus(FlattrStatus status) {
- this.flattrStatus = status;
- }
-
- public FlattrStatus getFlattrStatus() {
- return flattrStatus;
- }
-
- public String getPaymentLink() {
- return paymentLink;
- }
-
- public void setPaymentLink(String paymentLink) {
- this.paymentLink = paymentLink;
- }
-
- public String getLanguage() {
- return language;
- }
-
- public void setLanguage(String language) {
- this.language = language;
- }
-
- public String getAuthor() {
- return author;
- }
-
- public void setAuthor(String author) {
- this.author = author;
- }
-
- public String getType() {
- return type;
- }
-
- public void setType(String type) {
- this.type = type;
- }
-
- public void setPreferences(FeedPreferences preferences) {
- this.preferences = preferences;
- }
-
- public FeedPreferences getPreferences() {
- return preferences;
- }
-
- public void savePreferences(Context context) {
- DBWriter.setFeedPreferences(context, preferences);
- }
-
- @Override
- public void setId(long id) {
- super.setId(id);
- if (preferences != null) {
- preferences.setFeedID(id);
- }
- }
-
- @Override
- public Uri getImageUri() {
- if (image != null) {
- return image.getImageUri();
- } else {
- return null;
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java b/app/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java
deleted file mode 100644
index 05115c1ea..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package de.danoeh.antennapod.core.feed;
-
-/**
- * Represents every possible component of a feed
- *
- * @author daniel
- */
-public abstract class FeedComponent {
-
- protected long id;
-
- public FeedComponent() {
- super();
- }
-
- public long getId() {
- return id;
- }
-
- public void setId(long id) {
- this.id = id;
- }
-
- /**
- * Update this FeedComponent's attributes with the attributes from another
- * FeedComponent. This method should only update attributes which where read from
- * the feed.
- */
- public void updateFromOther(FeedComponent other) {
- }
-
- /**
- * Compare's this FeedComponent's attribute values with another FeedComponent's
- * attribute values. This method will only compare attributes which were
- * read from the feed.
- *
- * @return true if attribute values are different, false otherwise
- */
- public boolean compareWithOther(FeedComponent other) {
- return false;
- }
-
-
- /**
- * Should return a non-null, human-readable String so that the item can be
- * identified by the user. Can be title, download-url, etc.
- */
- public abstract String getHumanReadableIdentifier();
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- FeedComponent that = (FeedComponent) o;
-
- if (id != that.id) return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- return (int) (id ^ (id >>> 32));
- }
-} \ No newline at end of file
diff --git a/app/src/main/java/de/danoeh/antennapod/core/feed/FeedFile.java b/app/src/main/java/de/danoeh/antennapod/core/feed/FeedFile.java
deleted file mode 100644
index 3dc58654b..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/feed/FeedFile.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package de.danoeh.antennapod.core.feed;
-
-import java.io.File;
-
-/**
- * Represents a component of a Feed that has to be downloaded
- */
-public abstract class FeedFile extends FeedComponent {
-
- protected String file_url;
- protected String download_url;
- protected boolean downloaded;
-
- /**
- * Creates a new FeedFile object.
- *
- * @param file_url The location of the FeedFile. If this is null, the downloaded-attribute
- * will automatically be set to false.
- * @param download_url The location where the FeedFile can be downloaded.
- * @param downloaded true if the FeedFile has been downloaded, false otherwise. This parameter
- * will automatically be interpreted as false if the file_url is null.
- */
- public FeedFile(String file_url, String download_url, boolean downloaded) {
- super();
- this.file_url = file_url;
- this.download_url = download_url;
- this.downloaded = (file_url != null) && downloaded;
- }
-
- public FeedFile() {
- this(null, null, false);
- }
-
- public abstract int getTypeAsInt();
-
- /**
- * Update this FeedFile's attributes with the attributes from another
- * FeedFile. This method should only update attributes which where read from
- * the feed.
- */
- public void updateFromOther(FeedFile other) {
- super.updateFromOther(other);
- this.download_url = other.download_url;
- }
-
- /**
- * Compare's this FeedFile's attribute values with another FeedFile's
- * attribute values. This method will only compare attributes which were
- * read from the feed.
- *
- * @return true if attribute values are different, false otherwise
- */
- public boolean compareWithOther(FeedFile other) {
- if (super.compareWithOther(other)) {
- return true;
- }
- if (!download_url.equals(other.download_url)) {
- return true;
- }
- return false;
- }
-
- /**
- * Returns true if the file exists at file_url.
- */
- public boolean fileExists() {
- if (file_url == null) {
- return false;
- } else {
- File f = new File(file_url);
- return f.exists();
- }
- }
-
- public String getFile_url() {
- return file_url;
- }
-
- /**
- * Changes the file_url of this FeedFile. Setting this value to
- * null will also set the downloaded-attribute to false.
- */
- public void setFile_url(String file_url) {
- this.file_url = file_url;
- if (file_url == null) {
- downloaded = false;
- }
- }
-
- public String getDownload_url() {
- return download_url;
- }
-
- public void setDownload_url(String download_url) {
- this.download_url = download_url;
- }
-
- public boolean isDownloaded() {
- return downloaded;
- }
-
- public void setDownloaded(boolean downloaded) {
- this.downloaded = downloaded;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/feed/FeedImage.java b/app/src/main/java/de/danoeh/antennapod/core/feed/FeedImage.java
deleted file mode 100644
index 51605691d..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/feed/FeedImage.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package de.danoeh.antennapod.core.feed;
-
-import android.net.Uri;
-
-import de.danoeh.antennapod.core.asynctask.PicassoImageResource;
-
-import java.io.File;
-
-
-public class FeedImage extends FeedFile implements PicassoImageResource {
- public static final int FEEDFILETYPE_FEEDIMAGE = 1;
-
- protected String title;
- protected FeedComponent owner;
-
- public FeedImage(String download_url, String title) {
- super(null, download_url, false);
- this.download_url = download_url;
- this.title = title;
- }
-
- public FeedImage(long id, String title, String file_url,
- String download_url, boolean downloaded) {
- super(file_url, download_url, downloaded);
- this.id = id;
- this.title = title;
- }
-
- @Override
- public String getHumanReadableIdentifier() {
- if (owner != null && owner.getHumanReadableIdentifier() != null) {
- return owner.getHumanReadableIdentifier();
- } else {
- return download_url;
- }
- }
-
- @Override
- public int getTypeAsInt() {
- return FEEDFILETYPE_FEEDIMAGE;
- }
-
- public FeedImage() {
- super();
- }
-
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public FeedComponent getOwner() {
- return owner;
- }
-
- public void setOwner(FeedComponent owner) {
- this.owner = owner;
- }
-
- @Override
- public Uri getImageUri() {
- if (file_url != null && downloaded) {
- return Uri.fromFile(new File(file_url));
- } else {
- return null;
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java b/app/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
deleted file mode 100644
index 55143b13b..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
+++ /dev/null
@@ -1,332 +0,0 @@
-package de.danoeh.antennapod.core.feed;
-
-import android.net.Uri;
-
-import de.danoeh.antennapod.PodcastApp;
-import de.danoeh.antennapod.core.asynctask.PicassoImageResource;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.util.ShownotesProvider;
-import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
-import de.danoeh.antennapod.core.util.flattr.FlattrThing;
-
-import java.util.Date;
-import java.util.List;
-import java.util.concurrent.Callable;
-
-/**
- * Data Object for a XML message
- *
- * @author daniel
- */
-public class FeedItem extends FeedComponent implements ShownotesProvider, FlattrThing, PicassoImageResource {
-
- /**
- * The id/guid that can be found in the rss/atom feed. Might not be set.
- */
- private String itemIdentifier;
- private String title;
- /**
- * The description of a feeditem.
- */
- private String description;
- /**
- * The content of the content-encoded tag of a feeditem.
- */
- private String contentEncoded;
-
- private String link;
- private Date pubDate;
- private FeedMedia media;
-
- private Feed feed;
- private long feedId;
-
- private boolean read;
- private String paymentLink;
- private FlattrStatus flattrStatus;
- private List<Chapter> chapters;
- private FeedImage image;
-
- public FeedItem() {
- this.read = true;
- this.flattrStatus = new FlattrStatus();
- }
-
- /**
- * This constructor should be used for creating test objects.
- */
- public FeedItem(long id, String title, String itemIdentifier, String link, Date pubDate, boolean read, Feed feed) {
- this.id = id;
- this.title = title;
- this.itemIdentifier = itemIdentifier;
- this.link = link;
- this.pubDate = (pubDate != null) ? (Date) pubDate.clone() : null;
- this.read = read;
- this.feed = feed;
- this.flattrStatus = new FlattrStatus();
- }
-
- public void updateFromOther(FeedItem other) {
- super.updateFromOther(other);
- if (other.title != null) {
- title = other.title;
- }
- if (other.getDescription() != null) {
- description = other.getDescription();
- }
- if (other.getContentEncoded() != null) {
- contentEncoded = other.contentEncoded;
- }
- if (other.link != null) {
- link = other.link;
- }
- if (other.pubDate != null && other.pubDate != pubDate) {
- pubDate = other.pubDate;
- }
- if (other.media != null) {
- if (media == null) {
- setMedia(other.media);
- } else if (media.compareWithOther(other)) {
- media.updateFromOther(other);
- }
- }
- if (other.paymentLink != null) {
- paymentLink = other.paymentLink;
- }
- if (other.chapters != null) {
- if (chapters == null) {
- chapters = other.chapters;
- }
- }
- if (image == null) {
- image = other.image;
- }
- }
-
- /**
- * Returns the value that uniquely identifies this FeedItem. If the
- * itemIdentifier attribute is not null, it will be returned. Else it will
- * try to return the title. If the title is not given, it will use the link
- * of the entry.
- */
- public String getIdentifyingValue() {
- if (itemIdentifier != null && !itemIdentifier.isEmpty()) {
- return itemIdentifier;
- } else if (title != null && !title.isEmpty()) {
- return title;
- } else {
- return link;
- }
- }
-
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public String getDescription() {
- return description;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-
- public String getLink() {
- return link;
- }
-
- public void setLink(String link) {
- this.link = link;
- }
-
- public Date getPubDate() {
- if (pubDate != null) {
- return (Date) pubDate.clone();
- } else {
- return null;
- }
- }
-
- public void setPubDate(Date pubDate) {
- if (pubDate != null) {
- this.pubDate = (Date) pubDate.clone();
- } else {
- this.pubDate = null;
- }
- }
-
- public FeedMedia getMedia() {
- return media;
- }
-
- /**
- * Sets the media object of this FeedItem. If the given
- * FeedMedia object is not null, it's 'item'-attribute value
- * will also be set to this item.
- */
- public void setMedia(FeedMedia media) {
- this.media = media;
- if (media != null && media.getItem() != this) {
- media.setItem(this);
- }
- }
-
- public Feed getFeed() {
- return feed;
- }
-
- public void setFeed(Feed feed) {
- this.feed = feed;
- }
-
- public boolean isRead() {
- return read || isInProgress();
- }
-
- public void setRead(boolean read) {
- this.read = read;
- }
-
- private boolean isInProgress() {
- return (media != null && media.isInProgress());
- }
-
- public String getContentEncoded() {
- return contentEncoded;
- }
-
- public void setContentEncoded(String contentEncoded) {
- this.contentEncoded = contentEncoded;
- }
-
- public void setFlattrStatus(FlattrStatus status) {
- this.flattrStatus = status;
- }
-
- public FlattrStatus getFlattrStatus() {
- return flattrStatus;
- }
-
- public String getPaymentLink() {
- return paymentLink;
- }
-
- public void setPaymentLink(String paymentLink) {
- this.paymentLink = paymentLink;
- }
-
- public List<Chapter> getChapters() {
- return chapters;
- }
-
- public void setChapters(List<Chapter> chapters) {
- this.chapters = chapters;
- }
-
- public String getItemIdentifier() {
- return itemIdentifier;
- }
-
- public void setItemIdentifier(String itemIdentifier) {
- this.itemIdentifier = itemIdentifier;
- }
-
- public boolean hasMedia() {
- return media != null;
- }
-
- private boolean isPlaying() {
- if (media != null) {
- return media.isPlaying();
- }
- return false;
- }
-
- @Override
- public Callable<String> loadShownotes() {
- return new Callable<String>() {
- @Override
- public String call() throws Exception {
-
- if (contentEncoded == null || description == null) {
- DBReader.loadExtraInformationOfFeedItem(PodcastApp.getInstance(), FeedItem.this);
-
- }
- return (contentEncoded != null) ? contentEncoded : description;
- }
- };
- }
-
- @Override
- public Uri getImageUri() {
- if (hasMedia()) {
- return media.getImageUri();
- } else if (feed != null) {
- return feed.getImageUri();
- } else {
- return null;
- }
- }
-
- public enum State {
- NEW, IN_PROGRESS, READ, PLAYING
- }
-
- public State getState() {
- if (hasMedia()) {
- if (isPlaying()) {
- return State.PLAYING;
- }
- if (isInProgress()) {
- return State.IN_PROGRESS;
- }
- }
- return (isRead() ? State.READ : State.NEW);
- }
-
- public long getFeedId() {
- return feedId;
- }
-
- public void setFeedId(long feedId) {
- this.feedId = feedId;
- }
-
- /**
- * Returns the image of this item or the image of the feed if this item does
- * not have its own image.
- */
- public FeedImage getImage() {
- return (hasItemImage()) ? image : feed.getImage();
- }
-
- public void setImage(FeedImage image) {
- this.image = image;
- if (image != null) {
- image.setOwner(this);
- }
- }
-
- /**
- * Returns true if this FeedItem has its own image, false otherwise.
- */
- public boolean hasItemImage() {
- return image != null;
- }
-
- /**
- * Returns true if this FeedItem has its own image and the image has been downloaded.
- */
- public boolean hasItemImageDownloaded() {
- return image != null && image.isDownloaded();
- }
-
- @Override
- public String getHumanReadableIdentifier() {
- return title;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java b/app/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
deleted file mode 100644
index ab87e822d..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
+++ /dev/null
@@ -1,408 +0,0 @@
-package de.danoeh.antennapod.core.feed;
-
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Date;
-import java.util.List;
-import java.util.concurrent.Callable;
-
-import de.danoeh.antennapod.PodcastApp;
-import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.util.ChapterUtils;
-import de.danoeh.antennapod.core.util.playback.Playable;
-
-public class FeedMedia extends FeedFile implements Playable {
- private static final String TAG = "FeedMedia";
-
- public static final int FEEDFILETYPE_FEEDMEDIA = 2;
- public static final int PLAYABLE_TYPE_FEEDMEDIA = 1;
-
- public static final String PREF_MEDIA_ID = "FeedMedia.PrefMediaId";
- public static final String PREF_FEED_ID = "FeedMedia.PrefFeedId";
-
- private int duration;
- private int position; // Current position in file
- private int played_duration; // How many ms of this file have been played (for autoflattring)
- private long size; // File size in Byte
- private String mime_type;
- private volatile FeedItem item;
- private Date playbackCompletionDate;
-
- /* Used for loading item when restoring from parcel. */
- private long itemID;
-
- public FeedMedia(FeedItem i, String download_url, long size,
- String mime_type) {
- super(null, download_url, false);
- this.item = i;
- this.size = size;
- this.mime_type = mime_type;
- }
-
- public FeedMedia(long id, FeedItem item, int duration, int position,
- long size, String mime_type, String file_url, String download_url,
- boolean downloaded, Date playbackCompletionDate, int played_duration) {
- super(file_url, download_url, downloaded);
- this.id = id;
- this.item = item;
- this.duration = duration;
- this.position = position;
- this.played_duration = played_duration;
- this.size = size;
- this.mime_type = mime_type;
- this.playbackCompletionDate = playbackCompletionDate == null
- ? null : (Date) playbackCompletionDate.clone();
- }
-
- public FeedMedia(long id, FeedItem item) {
- super();
- this.id = id;
- this.item = item;
- }
-
- @Override
- public String getHumanReadableIdentifier() {
- if (item != null && item.getTitle() != null) {
- return item.getTitle();
- } else {
- return download_url;
- }
- }
-
- /**
- * Uses mimetype to determine the type of media.
- */
- public MediaType getMediaType() {
- if (mime_type == null || mime_type.isEmpty()) {
- return MediaType.UNKNOWN;
- } else {
- if (mime_type.startsWith("audio")) {
- return MediaType.AUDIO;
- } else if (mime_type.startsWith("video")) {
- return MediaType.VIDEO;
- } else if (mime_type.equals("application/ogg")) {
- return MediaType.AUDIO;
- }
- }
- return MediaType.UNKNOWN;
- }
-
- public void updateFromOther(FeedMedia other) {
- super.updateFromOther(other);
- if (other.size > 0) {
- size = other.size;
- }
- if (other.mime_type != null) {
- mime_type = other.mime_type;
- }
- }
-
- public boolean compareWithOther(FeedMedia other) {
- if (super.compareWithOther(other)) {
- return true;
- }
- if (other.mime_type != null) {
- if (mime_type == null || !mime_type.equals(other.mime_type)) {
- return true;
- }
- }
- if (other.size > 0 && other.size != size) {
- return true;
- }
- return false;
- }
-
- /**
- * Reads playback preferences to determine whether this FeedMedia object is
- * currently being played.
- */
- public boolean isPlaying() {
- return PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA
- && PlaybackPreferences.getCurrentlyPlayingFeedMediaId() == id;
- }
-
- @Override
- public int getTypeAsInt() {
- return FEEDFILETYPE_FEEDMEDIA;
- }
-
- public int getDuration() {
- return duration;
- }
-
- public void setDuration(int duration) {
- this.duration = duration;
- }
-
- public int getPlayedDuration() {
- return played_duration;
- }
-
- public void setPlayedDuration(int played_duration) {
- this.played_duration = played_duration;
- }
-
- public int getPosition() {
- return position;
- }
-
- public void setPosition(int position) {
- this.position = position;
- }
-
- public long getSize() {
- return size;
- }
-
- public void setSize(long size) {
- this.size = size;
- }
-
- public String getMime_type() {
- return mime_type;
- }
-
- public void setMime_type(String mime_type) {
- this.mime_type = mime_type;
- }
-
- public FeedItem getItem() {
- return item;
- }
-
- /**
- * Sets the item object of this FeedMedia. If the given
- * FeedItem object is not null, it's 'media'-attribute value
- * will also be set to this media object.
- */
- public void setItem(FeedItem item) {
- this.item = item;
- if (item != null && item.getMedia() != this) {
- item.setMedia(this);
- }
- }
-
- public Date getPlaybackCompletionDate() {
- return playbackCompletionDate == null
- ? null : (Date) playbackCompletionDate.clone();
- }
-
- public void setPlaybackCompletionDate(Date playbackCompletionDate) {
- this.playbackCompletionDate = playbackCompletionDate == null
- ? null : (Date) playbackCompletionDate.clone();
- }
-
- public boolean isInProgress() {
- return (this.position > 0);
- }
-
- public FeedImage getImage() {
- if (item != null) {
- return (item.hasItemImageDownloaded()) ? item.getImage() : item.getFeed().getImage();
- }
- return null;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeLong(id);
- dest.writeLong(item.getId());
-
- dest.writeInt(duration);
- dest.writeInt(position);
- dest.writeLong(size);
- dest.writeString(mime_type);
- dest.writeString(file_url);
- dest.writeString(download_url);
- dest.writeByte((byte) ((downloaded) ? 1 : 0));
- dest.writeLong((playbackCompletionDate != null) ? playbackCompletionDate.getTime() : 0);
- dest.writeInt(played_duration);
- }
-
- @Override
- public void writeToPreferences(Editor prefEditor) {
- prefEditor.putLong(PREF_FEED_ID, item.getFeed().getId());
- prefEditor.putLong(PREF_MEDIA_ID, id);
- }
-
- @Override
- public void loadMetadata() throws PlayableException {
- if (item == null && itemID != 0) {
- item = DBReader.getFeedItem(PodcastApp.getInstance(), itemID);
- }
- }
-
- @Override
- public void loadChapterMarks() {
- if (getChapters() == null && !localFileAvailable()) {
- ChapterUtils.loadChaptersFromStreamUrl(this);
- if (getChapters() != null && item != null) {
- DBWriter.setFeedItem(PodcastApp.getInstance(),
- item);
- }
- }
-
- }
-
- @Override
- public String getEpisodeTitle() {
- if (item == null) {
- return null;
- }
- if (getItem().getTitle() != null) {
- return getItem().getTitle();
- } else {
- return getItem().getIdentifyingValue();
- }
- }
-
- @Override
- public List<Chapter> getChapters() {
- if (item == null) {
- return null;
- }
- return getItem().getChapters();
- }
-
- @Override
- public String getWebsiteLink() {
- if (item == null) {
- return null;
- }
- return getItem().getLink();
- }
-
- @Override
- public String getFeedTitle() {
- if (item == null) {
- return null;
- }
- return getItem().getFeed().getTitle();
- }
-
- @Override
- public Object getIdentifier() {
- return id;
- }
-
- @Override
- public String getLocalMediaUrl() {
- return file_url;
- }
-
- @Override
- public String getStreamUrl() {
- return download_url;
- }
-
- @Override
- public String getPaymentLink() {
- if (item == null) {
- return null;
- }
- return getItem().getPaymentLink();
- }
-
- @Override
- public boolean localFileAvailable() {
- return isDownloaded() && file_url != null;
- }
-
- @Override
- public boolean streamAvailable() {
- return download_url != null;
- }
-
- @Override
- public void saveCurrentPosition(SharedPreferences pref, int newPosition) {
- setPosition(newPosition);
- DBWriter.setFeedMediaPlaybackInformation(PodcastApp.getInstance(), this);
- }
-
- @Override
- public void onPlaybackStart() {
- }
-
- @Override
- public void onPlaybackCompleted() {
-
- }
-
- @Override
- public int getPlayableType() {
- return PLAYABLE_TYPE_FEEDMEDIA;
- }
-
- @Override
- public void setChapters(List<Chapter> chapters) {
- getItem().setChapters(chapters);
- }
-
- @Override
- public Callable<String> loadShownotes() {
- return new Callable<String>() {
- @Override
- public String call() throws Exception {
- if (item == null) {
- item = DBReader.getFeedItem(PodcastApp.getInstance(), itemID);
- }
- if (item.getContentEncoded() == null || item.getDescription() == null) {
- DBReader.loadExtraInformationOfFeedItem(PodcastApp.getInstance(), item);
-
- }
- return (item.getContentEncoded() != null) ? item.getContentEncoded() : item.getDescription();
- }
- };
- }
-
- public static final Parcelable.Creator<FeedMedia> CREATOR = new Parcelable.Creator<FeedMedia>() {
- public FeedMedia createFromParcel(Parcel in) {
- final long id = in.readLong();
- final long itemID = in.readLong();
- FeedMedia result = new FeedMedia(id, null, in.readInt(), in.readInt(), in.readLong(), in.readString(), in.readString(),
- in.readString(), in.readByte() != 0, new Date(in.readLong()), in.readInt());
- result.itemID = itemID;
- return result;
- }
-
- public FeedMedia[] newArray(int size) {
- return new FeedMedia[size];
- }
- };
-
- @Override
- public Uri getImageUri() {
- final Uri feedImgUri = getFeedImageUri();
-
- if (localFileAvailable()) {
- Uri.Builder builder = new Uri.Builder();
- builder.scheme(SCHEME_MEDIA)
- .encodedPath(getLocalMediaUrl());
- if (feedImgUri != null) {
- builder.appendQueryParameter(PARAM_FALLBACK, feedImgUri.toString());
- }
- return builder.build();
- } else {
- return feedImgUri;
- }
- }
-
- private Uri getFeedImageUri() {
- if (item != null && item.getFeed() != null) {
- return item.getFeed().getImageUri();
- } else {
- return null;
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java b/app/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java
deleted file mode 100644
index 2f0304182..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package de.danoeh.antennapod.core.feed;
-
-import android.content.Context;
-import de.danoeh.antennapod.core.storage.DBWriter;
-import org.apache.commons.lang3.StringUtils;
-
-/**
- * Contains preferences for a single feed.
- */
-public class FeedPreferences {
-
- private long feedID;
- private boolean autoDownload;
- private String username;
- private String password;
-
- public FeedPreferences(long feedID, boolean autoDownload, String username, String password) {
- this.feedID = feedID;
- this.autoDownload = autoDownload;
- this.username = username;
- this.password = password;
- }
-
-
- /**
- * Compare another FeedPreferences with this one. The feedID and autoDownload attribute are excluded from the
- * comparison.
- *
- * @return True if the two objects are different.
- */
- public boolean compareWithOther(FeedPreferences other) {
- if (other == null)
- return true;
- if (!StringUtils.equals(username, other.username)) {
- return true;
- }
- if (!StringUtils.equals(password, other.password)) {
- return true;
- }
- return false;
- }
-
- /**
- * Update this FeedPreferences object from another one. The feedID and autoDownload attributes are excluded
- * from the update.
- */
- public void updateFromOther(FeedPreferences other) {
- if (other == null)
- return;
- this.username = other.username;
- this.password = other.password;
- }
-
- public long getFeedID() {
- return feedID;
- }
-
- public void setFeedID(long feedID) {
- this.feedID = feedID;
- }
-
- public boolean getAutoDownload() {
- return autoDownload;
- }
-
- public void setAutoDownload(boolean autoDownload) {
- this.autoDownload = autoDownload;
- }
-
- public void save(Context context) {
- DBWriter.setFeedPreferences(context, this);
- }
-
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/feed/ID3Chapter.java b/app/src/main/java/de/danoeh/antennapod/core/feed/ID3Chapter.java
deleted file mode 100644
index f0ff03a93..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/feed/ID3Chapter.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package de.danoeh.antennapod.core.feed;
-
-public class ID3Chapter extends Chapter {
- public static final int CHAPTERTYPE_ID3CHAPTER = 2;
-
- /**
- * Identifies the chapter in its ID3 tag. This attribute does not have to be
- * store in the DB and is only used for parsing.
- */
- private String id3ID;
-
- public ID3Chapter(String id3ID, long start) {
- super(start);
- this.id3ID = id3ID;
- }
-
- public ID3Chapter(long start, String title, FeedItem item, String link) {
- super(start, title, item, link);
- }
-
- @Override
- public String toString() {
- return "ID3Chapter [id3ID=" + id3ID + ", title=" + title + ", start="
- + start + ", url=" + link + "]";
- }
-
- @Override
- public int getChapterType() {
- return CHAPTERTYPE_ID3CHAPTER;
- }
-
- public String getId3ID() {
- return id3ID;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/feed/MediaType.java b/app/src/main/java/de/danoeh/antennapod/core/feed/MediaType.java
deleted file mode 100644
index 7b3cb829d..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/feed/MediaType.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package de.danoeh.antennapod.core.feed;
-
-public enum MediaType {
- AUDIO, VIDEO, UNKNOWN
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/feed/SearchResult.java b/app/src/main/java/de/danoeh/antennapod/core/feed/SearchResult.java
deleted file mode 100644
index 9aa8d3170..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/feed/SearchResult.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package de.danoeh.antennapod.core.feed;
-
-public class SearchResult {
- private FeedComponent component;
- /** Additional information (e.g. where it was found) */
- private String subtitle;
- /** Higher value means more importance */
- private int value;
-
- public SearchResult(FeedComponent component, int value, String subtitle) {
- super();
- this.component = component;
- this.value = value;
- this.subtitle = subtitle;
- }
-
- public FeedComponent getComponent() {
- return component;
- }
-
- public String getSubtitle() {
- return subtitle;
- }
-
- public void setSubtitle(String subtitle) {
- this.subtitle = subtitle;
- }
-
- public int getValue() {
- return value;
- }
-
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java b/app/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java
deleted file mode 100644
index 2dadd3ec8..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package de.danoeh.antennapod.core.feed;
-
-public class SimpleChapter extends Chapter {
- public static final int CHAPTERTYPE_SIMPLECHAPTER = 0;
-
- public SimpleChapter(long start, String title, FeedItem item, String link) {
- super(start, title, item, link);
- }
-
- @Override
- public int getChapterType() {
- return CHAPTERTYPE_SIMPLECHAPTER;
- }
-
- public void updateFromOther(SimpleChapter other) {
- super.updateFromOther(other);
- start = other.start;
- if (other.title != null) {
- title = other.title;
- }
- if (other.link != null) {
- link = other.link;
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/feed/VorbisCommentChapter.java b/app/src/main/java/de/danoeh/antennapod/core/feed/VorbisCommentChapter.java
deleted file mode 100644
index 5b54a2d59..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/feed/VorbisCommentChapter.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package de.danoeh.antennapod.core.feed;
-
-import de.danoeh.antennapod.core.util.vorbiscommentreader.VorbisCommentReaderException;
-
-import java.util.concurrent.TimeUnit;
-
-public class VorbisCommentChapter extends Chapter {
- public static final int CHAPTERTYPE_VORBISCOMMENT_CHAPTER = 3;
-
- private static final int CHAPTERXXX_LENGTH = "chapterxxx".length();
-
- private int vorbisCommentId;
-
- public VorbisCommentChapter(int vorbisCommentId) {
- this.vorbisCommentId = vorbisCommentId;
- }
-
- public VorbisCommentChapter(long start, String title, FeedItem item,
- String link) {
- super(start, title, item, link);
- }
-
- @Override
- public String toString() {
- return "VorbisCommentChapter [id=" + id + ", title=" + title
- + ", link=" + link + ", start=" + start + "]";
- }
-
- public static long getStartTimeFromValue(String value)
- throws VorbisCommentReaderException {
- String[] parts = value.split(":");
- if (parts.length >= 3) {
- try {
- long hours = TimeUnit.MILLISECONDS.convert(
- Long.parseLong(parts[0]), TimeUnit.HOURS);
- long minutes = TimeUnit.MILLISECONDS.convert(
- Long.parseLong(parts[1]), TimeUnit.MINUTES);
- if (parts[2].contains("-->")) {
- parts[2] = parts[2].substring(0, parts[2].indexOf("-->"));
- }
- long seconds = TimeUnit.MILLISECONDS.convert(
- ((long) Float.parseFloat(parts[2])), TimeUnit.SECONDS);
- return hours + minutes + seconds;
- } catch (NumberFormatException e) {
- throw new VorbisCommentReaderException(e);
- }
- } else {
- throw new VorbisCommentReaderException("Invalid time string");
- }
- }
-
- /**
- * Return the id of a vorbiscomment chapter from a string like CHAPTERxxx*
- *
- * @return the id of the chapter key or -1 if the id couldn't be read.
- * @throws VorbisCommentReaderException
- * */
- public static int getIDFromKey(String key)
- throws VorbisCommentReaderException {
- if (key.length() >= CHAPTERXXX_LENGTH) { // >= CHAPTERxxx
- try {
- String strId = key.substring(8, 10);
- return Integer.parseInt(strId);
- } catch (NumberFormatException e) {
- throw new VorbisCommentReaderException(e);
- }
- }
- throw new VorbisCommentReaderException("key is too short (" + key + ")");
- }
-
- /**
- * Get the string that comes after 'CHAPTERxxx', for example 'name' or
- * 'url'.
- */
- public static String getAttributeTypeFromKey(String key) {
- if (key.length() > CHAPTERXXX_LENGTH) {
- return key.substring(CHAPTERXXX_LENGTH, key.length());
- }
- return null;
- }
-
- @Override
- public int getChapterType() {
- return CHAPTERTYPE_VORBISCOMMENT_CHAPTER;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public void setLink(String link) {
- this.link = link;
- }
-
- public void setStart(long start) {
- this.start = start;
- }
-
- public int getVorbisCommentId() {
- return vorbisCommentId;
- }
-
- public void setVorbisCommentId(int vorbisCommentId) {
- this.vorbisCommentId = vorbisCommentId;
- }
-
-
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java b/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
deleted file mode 100644
index 117cbf96b..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
+++ /dev/null
@@ -1,718 +0,0 @@
-package de.danoeh.antennapod.core.gpoddernet;
-
-import org.apache.commons.lang3.Validate;
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.auth.AuthenticationException;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpPut;
-import org.apache.http.client.methods.HttpRequestBase;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.auth.BasicScheme;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-
-import de.danoeh.antennapod.core.gpoddernet.model.GpodnetDevice;
-import de.danoeh.antennapod.core.gpoddernet.model.GpodnetPodcast;
-import de.danoeh.antennapod.core.gpoddernet.model.GpodnetSubscriptionChange;
-import de.danoeh.antennapod.core.gpoddernet.model.GpodnetTag;
-import de.danoeh.antennapod.core.gpoddernet.model.GpodnetUploadChangesResponse;
-import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
-import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
-
-/**
- * Communicates with the gpodder.net service.
- */
-public class GpodnetService {
-
- private static final String BASE_SCHEME = "https";
-
- public static final String DEFAULT_BASE_HOST = "gpodder.net";
- private final String BASE_HOST;
-
- private final HttpClient httpClient;
-
- public GpodnetService() {
- httpClient = AntennapodHttpClient.getHttpClient();
- BASE_HOST = GpodnetPreferences.getHostname();
- }
-
- /**
- * Returns the [count] most used tags.
- */
- public List<GpodnetTag> getTopTags(int count)
- throws GpodnetServiceException {
- URI uri;
- try {
- uri = new URI(BASE_SCHEME, BASE_HOST, String.format(
- "/api/2/tags/%d.json", count), null);
- } catch (URISyntaxException e1) {
- e1.printStackTrace();
- throw new IllegalStateException(e1);
- }
-
- HttpGet request = new HttpGet(uri);
- String response = executeRequest(request);
- try {
- JSONArray jsonTagList = new JSONArray(response);
- List<GpodnetTag> tagList = new ArrayList<GpodnetTag>(
- jsonTagList.length());
- for (int i = 0; i < jsonTagList.length(); i++) {
- JSONObject jObj = jsonTagList.getJSONObject(i);
- String name = jObj.getString("tag");
- int usage = jObj.getInt("usage");
- tagList.add(new GpodnetTag(name, usage));
- }
- return tagList;
- } catch (JSONException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- }
- }
-
- /**
- * Returns the [count] most subscribed podcasts for the given tag.
- *
- * @throws IllegalArgumentException if tag is null
- */
- public List<GpodnetPodcast> getPodcastsForTag(GpodnetTag tag, int count)
- throws GpodnetServiceException {
- Validate.notNull(tag);
-
- try {
- URI uri = new URI(BASE_SCHEME, BASE_HOST, String.format(
- "/api/2/tag/%s/%d.json", tag.getName(), count), null);
- HttpGet request = new HttpGet(uri);
- String response = executeRequest(request);
-
- JSONArray jsonArray = new JSONArray(response);
- return readPodcastListFromJSONArray(jsonArray);
-
- } catch (JSONException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- } catch (URISyntaxException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
-
- }
- }
-
- /**
- * Returns the toplist of podcast.
- *
- * @param count of elements that should be returned. Must be in range 1..100.
- * @throws IllegalArgumentException if count is out of range.
- */
- public List<GpodnetPodcast> getPodcastToplist(int count)
- throws GpodnetServiceException {
- Validate.isTrue(count >= 1 && count <= 100, "Count must be in range 1..100");
-
- try {
- URI uri = new URI(BASE_SCHEME, BASE_HOST, String.format(
- "/toplist/%d.json", count), null);
- HttpGet request = new HttpGet(uri);
- String response = executeRequest(request);
-
- JSONArray jsonArray = new JSONArray(response);
- return readPodcastListFromJSONArray(jsonArray);
-
- } catch (JSONException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- } catch (URISyntaxException e) {
- e.printStackTrace();
- throw new IllegalStateException(e);
-
- }
- }
-
- /**
- * Returns a list of suggested podcasts for the user that is currently
- * logged in.
- * <p/>
- * This method requires authentication.
- *
- * @param count The
- * number of elements that should be returned. Must be in range
- * 1..100.
- * @throws IllegalArgumentException if count is out of range.
- * @throws GpodnetServiceAuthenticationException If there is an authentication error.
- */
- public List<GpodnetPodcast> getSuggestions(int count) throws GpodnetServiceException {
- Validate.isTrue(count >= 1 && count <= 100, "Count must be in range 1..100");
-
- try {
- URI uri = new URI(BASE_SCHEME, BASE_HOST, String.format(
- "/suggestions/%d.json", count), null);
- HttpGet request = new HttpGet(uri);
- String response = executeRequest(request);
-
- JSONArray jsonArray = new JSONArray(response);
- return readPodcastListFromJSONArray(jsonArray);
- } catch (URISyntaxException e) {
- e.printStackTrace();
- throw new IllegalStateException(e);
- } catch (JSONException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- }
- }
-
- /**
- * Searches the podcast directory for a given string.
- *
- * @param query The search query
- * @param scaledLogoSize The size of the logos that are returned by the search query.
- * Must be in range 1..256. If the value is out of range, the
- * default value defined by the gpodder.net API will be used.
- */
- public List<GpodnetPodcast> searchPodcasts(String query, int scaledLogoSize)
- throws GpodnetServiceException {
- String parameters = (scaledLogoSize > 0 && scaledLogoSize <= 256) ? String
- .format("q=%s&scale_logo=%d", query, scaledLogoSize) : String
- .format("q=%s", query);
- try {
- URI uri = new URI(BASE_SCHEME, null, BASE_HOST, -1, "/search.json",
- parameters, null);
- System.out.println(uri.toASCIIString());
- HttpGet request = new HttpGet(uri);
- String response = executeRequest(request);
-
- JSONArray jsonArray = new JSONArray(response);
- return readPodcastListFromJSONArray(jsonArray);
-
- } catch (JSONException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- } catch (URISyntaxException e) {
- e.printStackTrace();
- throw new IllegalStateException(e);
-
- }
- }
-
- /**
- * Returns all devices of a given user.
- * <p/>
- * This method requires authentication.
- *
- * @param username The username. Must be the same user as the one which is
- * currently logged in.
- * @throws IllegalArgumentException If username is null.
- * @throws GpodnetServiceAuthenticationException If there is an authentication error.
- */
- public List<GpodnetDevice> getDevices(String username)
- throws GpodnetServiceException {
- Validate.notNull(username);
-
- try {
- URI uri = new URI(BASE_SCHEME, BASE_HOST, String.format(
- "/api/2/devices/%s.json", username), null);
- HttpGet request = new HttpGet(uri);
- String response = executeRequest(request);
- JSONArray devicesArray = new JSONArray(response);
- List<GpodnetDevice> result = readDeviceListFromJSONArray(devicesArray);
-
- return result;
- } catch (URISyntaxException e) {
- e.printStackTrace();
- throw new IllegalStateException(e);
- } catch (JSONException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- }
- }
-
- /**
- * Configures the device of a given user.
- * <p/>
- * This method requires authentication.
- *
- * @param username The username. Must be the same user as the one which is
- * currently logged in.
- * @param deviceId The ID of the device that should be configured.
- * @throws IllegalArgumentException If username or deviceId is null.
- * @throws GpodnetServiceAuthenticationException If there is an authentication error.
- */
- public void configureDevice(String username, String deviceId,
- String caption, GpodnetDevice.DeviceType type)
- throws GpodnetServiceException {
- Validate.notNull(username);
- Validate.notNull(deviceId);
-
- try {
- URI uri = new URI(BASE_SCHEME, BASE_HOST, String.format(
- "/api/2/devices/%s/%s.json", username, deviceId), null);
- HttpPost request = new HttpPost(uri);
- if (caption != null || type != null) {
- JSONObject jsonContent = new JSONObject();
- if (caption != null) {
- jsonContent.put("caption", caption);
- }
- if (type != null) {
- jsonContent.put("type", type.toString());
- }
- StringEntity strEntity = new StringEntity(
- jsonContent.toString(), "UTF-8");
- strEntity.setContentType("application/json");
- request.setEntity(strEntity);
- }
- executeRequest(request);
- } catch (URISyntaxException e) {
- e.printStackTrace();
- throw new IllegalArgumentException(e);
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- throw new IllegalStateException(e);
- } catch (JSONException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- }
- }
-
- /**
- * Returns the subscriptions of a specific device.
- * <p/>
- * This method requires authentication.
- *
- * @param username The username. Must be the same user as the one which is
- * currently logged in.
- * @param deviceId The ID of the device whose subscriptions should be returned.
- * @return A list of subscriptions in OPML format.
- * @throws IllegalArgumentException If username or deviceId is null.
- * @throws GpodnetServiceAuthenticationException If there is an authentication error.
- */
- public String getSubscriptionsOfDevice(String username, String deviceId)
- throws GpodnetServiceException {
- Validate.notNull(username);
- Validate.notNull(deviceId);
-
- try {
- URI uri = new URI(BASE_SCHEME, BASE_HOST, String.format(
- "/subscriptions/%s/%s.opml", username, deviceId), null);
- HttpGet request = new HttpGet(uri);
- String response = executeRequest(request);
- return response;
- } catch (URISyntaxException e) {
- e.printStackTrace();
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Returns all subscriptions of a specific user.
- * <p/>
- * This method requires authentication.
- *
- * @param username The username. Must be the same user as the one which is
- * currently logged in.
- * @return A list of subscriptions in OPML format.
- * @throws IllegalArgumentException If username is null.
- * @throws GpodnetServiceAuthenticationException If there is an authentication error.
- */
- public String getSubscriptionsOfUser(String username)
- throws GpodnetServiceException {
- Validate.notNull(username);
-
- try {
- URI uri = new URI(BASE_SCHEME, BASE_HOST, String.format(
- "/subscriptions/%s.opml", username), null);
- HttpGet request = new HttpGet(uri);
- String response = executeRequest(request);
- return response;
- } catch (URISyntaxException e) {
- e.printStackTrace();
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Uploads the subscriptions of a specific device.
- * <p/>
- * This method requires authentication.
- *
- * @param username The username. Must be the same user as the one which is
- * currently logged in.
- * @param deviceId The ID of the device whose subscriptions should be updated.
- * @param subscriptions A list of feed URLs containing all subscriptions of the
- * device.
- * @throws IllegalArgumentException If username, deviceId or subscriptions is null.
- * @throws GpodnetServiceAuthenticationException If there is an authentication error.
- */
- public void uploadSubscriptions(String username, String deviceId,
- List<String> subscriptions) throws GpodnetServiceException {
- if (username == null || deviceId == null || subscriptions == null) {
- throw new IllegalArgumentException(
- "Username, device ID and subscriptions must not be null");
- }
- try {
- URI uri = new URI(BASE_SCHEME, BASE_HOST, String.format(
- "/subscriptions/%s/%s.txt", username, deviceId), null);
- HttpPut request = new HttpPut(uri);
- StringBuilder builder = new StringBuilder();
- for (String s : subscriptions) {
- builder.append(s);
- builder.append("\n");
- }
- StringEntity entity = new StringEntity(builder.toString(), "UTF-8");
- request.setEntity(entity);
-
- executeRequest(request);
- } catch (URISyntaxException e) {
- e.printStackTrace();
- throw new IllegalStateException(e);
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- throw new IllegalStateException(e);
- }
- }
-
- /**
- * Updates the subscription list of a specific device.
- * <p/>
- * This method requires authentication.
- *
- * @param username The username. Must be the same user as the one which is
- * currently logged in.
- * @param deviceId The ID of the device whose subscriptions should be updated.
- * @param added Collection of feed URLs of added feeds. This Collection MUST NOT contain any duplicates
- * @param removed Collection of feed URLs of removed feeds. This Collection MUST NOT contain any duplicates
- * @return a GpodnetUploadChangesResponse. See {@link de.danoeh.antennapod.core.gpoddernet.model.GpodnetUploadChangesResponse}
- * for details.
- * @throws java.lang.IllegalArgumentException if username, deviceId, added or removed is null.
- * @throws de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException if added or removed contain duplicates or if there
- * is an authentication error.
- */
- public GpodnetUploadChangesResponse uploadChanges(String username, String deviceId, Collection<String> added,
- Collection<String> removed) throws GpodnetServiceException {
- Validate.notNull(username);
- Validate.notNull(deviceId);
- Validate.notNull(added);
- Validate.notNull(removed);
-
- try {
- URI uri = new URI(BASE_SCHEME, BASE_HOST, String.format(
- "/api/2/subscriptions/%s/%s.json", username, deviceId), null);
-
- final JSONObject requestObject = new JSONObject();
- requestObject.put("add", new JSONArray(added));
- requestObject.put("remove", new JSONArray(removed));
-
- HttpPost request = new HttpPost(uri);
- StringEntity entity = new StringEntity(requestObject.toString(), "UTF-8");
- request.setEntity(entity);
-
- final String response = executeRequest(request);
- return GpodnetUploadChangesResponse.fromJSONObject(response);
- } catch (URISyntaxException e) {
- e.printStackTrace();
- throw new IllegalStateException(e);
- } catch (JSONException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- throw new IllegalStateException(e);
- }
-
- }
-
- /**
- * Returns all subscription changes of a specific device.
- * <p/>
- * This method requires authentication.
- *
- * @param username The username. Must be the same user as the one which is
- * currently logged in.
- * @param deviceId The ID of the device whose subscription changes should be
- * downloaded.
- * @param timestamp A timestamp that can be used to receive all changes since a
- * specific point in time.
- * @throws IllegalArgumentException If username or deviceId is null.
- * @throws GpodnetServiceAuthenticationException If there is an authentication error.
- */
- public GpodnetSubscriptionChange getSubscriptionChanges(String username,
- String deviceId, long timestamp) throws GpodnetServiceException {
- Validate.notNull(username);
- Validate.notNull(deviceId);
-
- String params = String.format("since=%d", timestamp);
- String path = String.format("/api/2/subscriptions/%s/%s.json",
- username, deviceId);
- try {
- URI uri = new URI(BASE_SCHEME, null, BASE_HOST, -1, path, params,
- null);
- HttpGet request = new HttpGet(uri);
-
- String response = executeRequest(request);
- JSONObject changes = new JSONObject(response);
- return readSubscriptionChangesFromJSONObject(changes);
- } catch (URISyntaxException e) {
- e.printStackTrace();
- throw new IllegalStateException(e);
- } catch (JSONException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- }
-
- }
-
- /**
- * Logs in a specific user. This method must be called if any of the methods
- * that require authentication is used.
- *
- * @throws IllegalArgumentException If username or password is null.
- */
- public void authenticate(String username, String password)
- throws GpodnetServiceException {
- Validate.notNull(username);
- Validate.notNull(password);
-
- URI uri;
- try {
- uri = new URI(BASE_SCHEME, BASE_HOST, String.format(
- "/api/2/auth/%s/login.json", username), null);
- } catch (URISyntaxException e) {
- e.printStackTrace();
- throw new GpodnetServiceException();
- }
- HttpPost request = new HttpPost(uri);
- executeRequestWithAuthentication(request, username, password);
- }
-
- /**
- * Shuts down the GpodnetService's HTTP client. The service will be shut down in a separate thread to avoid
- * NetworkOnMainThreadExceptions.
- */
- public void shutdown() {
- new Thread() {
- @Override
- public void run() {
- AntennapodHttpClient.cleanup();
- }
- }.start();
- }
-
- private String executeRequest(HttpRequestBase request)
- throws GpodnetServiceException {
- Validate.notNull(request);
-
- String responseString = null;
- HttpResponse response = null;
- try {
- response = httpClient.execute(request);
- checkStatusCode(response);
- responseString = getStringFromEntity(response.getEntity());
- } catch (ClientProtocolException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- } catch (IOException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- } finally {
- if (response != null) {
- try {
- response.getEntity().consumeContent();
- } catch (IOException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- }
- }
-
- }
- return responseString;
- }
-
- private String executeRequestWithAuthentication(HttpRequestBase request,
- String username, String password) throws GpodnetServiceException {
- if (request == null || username == null || password == null) {
- throw new IllegalArgumentException(
- "request and credentials must not be null");
- }
- String result = null;
- HttpResponse response = null;
- try {
- Header auth = new BasicScheme().authenticate(
- new UsernamePasswordCredentials(username, password),
- request);
- request.addHeader(auth);
- response = httpClient.execute(request);
- checkStatusCode(response);
- result = getStringFromEntity(response.getEntity());
- } catch (ClientProtocolException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- } catch (IOException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- } catch (AuthenticationException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- } finally {
- if (response != null) {
- try {
- response.getEntity().consumeContent();
- } catch (IOException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- }
- }
- }
- return result;
- }
-
- private String getStringFromEntity(HttpEntity entity)
- throws GpodnetServiceException {
- Validate.notNull(entity);
-
- ByteArrayOutputStream outputStream;
- int contentLength = (int) entity.getContentLength();
- if (contentLength > 0) {
- outputStream = new ByteArrayOutputStream(contentLength);
- } else {
- outputStream = new ByteArrayOutputStream();
- }
- try {
- byte[] buffer = new byte[8 * 1024];
- InputStream in = entity.getContent();
- int count;
- while ((count = in.read(buffer)) > 0) {
- outputStream.write(buffer, 0, count);
- }
- } catch (IOException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- }
- // System.out.println(outputStream.toString());
- return outputStream.toString();
- }
-
- private void checkStatusCode(HttpResponse response)
- throws GpodnetServiceException {
- Validate.notNull(response);
- int responseCode = response.getStatusLine().getStatusCode();
- if (responseCode != HttpStatus.SC_OK) {
- if (responseCode == HttpStatus.SC_UNAUTHORIZED) {
- throw new GpodnetServiceAuthenticationException("Wrong username or password");
- } else {
- throw new GpodnetServiceBadStatusCodeException(
- "Bad response code: " + responseCode, responseCode);
- }
- }
- }
-
- private List<GpodnetPodcast> readPodcastListFromJSONArray(JSONArray array)
- throws JSONException {
- Validate.notNull(array);
-
- List<GpodnetPodcast> result = new ArrayList<GpodnetPodcast>(
- array.length());
- for (int i = 0; i < array.length(); i++) {
- result.add(readPodcastFromJSONObject(array.getJSONObject(i)));
- }
- return result;
-
- }
-
- private GpodnetPodcast readPodcastFromJSONObject(JSONObject object)
- throws JSONException {
- String url = object.getString("url");
-
- String title;
- Object titleObj = object.opt("title");
- if (titleObj != null && titleObj instanceof String) {
- title = (String) titleObj;
- } else {
- title = url;
- }
-
- String description;
- Object descriptionObj = object.opt("description");
- if (descriptionObj != null && descriptionObj instanceof String) {
- description = (String) descriptionObj;
- } else {
- description = "";
- }
-
- int subscribers = object.getInt("subscribers");
-
- Object logoUrlObj = object.opt("logo_url");
- String logoUrl = (logoUrlObj instanceof String) ? (String) logoUrlObj
- : null;
- if (logoUrl == null) {
- Object scaledLogoUrl = object.opt("scaled_logo_url");
- if (scaledLogoUrl != null && scaledLogoUrl instanceof String) {
- logoUrl = (String) scaledLogoUrl;
- }
- }
-
- String website = null;
- Object websiteObj = object.opt("website");
- if (websiteObj != null && websiteObj instanceof String) {
- website = (String) websiteObj;
- }
- String mygpoLink = object.getString("mygpo_link");
- return new GpodnetPodcast(url, title, description, subscribers,
- logoUrl, website, mygpoLink);
- }
-
- private List<GpodnetDevice> readDeviceListFromJSONArray(JSONArray array)
- throws JSONException {
- Validate.notNull(array);
-
- List<GpodnetDevice> result = new ArrayList<GpodnetDevice>(
- array.length());
- for (int i = 0; i < array.length(); i++) {
- result.add(readDeviceFromJSONObject(array.getJSONObject(i)));
- }
- return result;
- }
-
- private GpodnetDevice readDeviceFromJSONObject(JSONObject object)
- throws JSONException {
- String id = object.getString("id");
- String caption = object.getString("caption");
- String type = object.getString("type");
- int subscriptions = object.getInt("subscriptions");
- return new GpodnetDevice(id, caption, type, subscriptions);
- }
-
- private GpodnetSubscriptionChange readSubscriptionChangesFromJSONObject(
- JSONObject object) throws JSONException {
- Validate.notNull(object);
-
- List<String> added = new LinkedList<String>();
- JSONArray jsonAdded = object.getJSONArray("add");
- for (int i = 0; i < jsonAdded.length(); i++) {
- added.add(jsonAdded.getString(i));
- }
-
- List<String> removed = new LinkedList<String>();
- JSONArray jsonRemoved = object.getJSONArray("remove");
- for (int i = 0; i < jsonRemoved.length(); i++) {
- removed.add(jsonRemoved.getString(i));
- }
-
- long timestamp = object.getLong("timestamp");
- return new GpodnetSubscriptionChange(added, removed, timestamp);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetServiceAuthenticationException.java b/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetServiceAuthenticationException.java
deleted file mode 100644
index 8bd56218c..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetServiceAuthenticationException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package de.danoeh.antennapod.core.gpoddernet;
-
-public class GpodnetServiceAuthenticationException extends GpodnetServiceException {
-
- public GpodnetServiceAuthenticationException() {
- super();
- }
-
- public GpodnetServiceAuthenticationException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public GpodnetServiceAuthenticationException(String message) {
- super(message);
- }
-
- public GpodnetServiceAuthenticationException(Throwable cause) {
- super(cause);
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetServiceBadStatusCodeException.java b/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetServiceBadStatusCodeException.java
deleted file mode 100644
index 16f01f0f4..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetServiceBadStatusCodeException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package de.danoeh.antennapod.core.gpoddernet;
-
-public class GpodnetServiceBadStatusCodeException extends GpodnetServiceException {
- int statusCode;
-
- public GpodnetServiceBadStatusCodeException(String message, int statusCode) {
- super(message);
- this.statusCode = statusCode;
- }
-
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetServiceException.java b/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetServiceException.java
deleted file mode 100644
index ce704f7e3..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetServiceException.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package de.danoeh.antennapod.core.gpoddernet;
-
-public class GpodnetServiceException extends Exception {
-
- public GpodnetServiceException() {
- }
-
- public GpodnetServiceException(String message) {
- super(message);
- }
-
- public GpodnetServiceException(Throwable cause) {
- super(cause);
- }
-
- public GpodnetServiceException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java b/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java
deleted file mode 100644
index 4885a243a..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package de.danoeh.antennapod.core.gpoddernet.model;
-
-import org.apache.commons.lang3.Validate;
-
-public class GpodnetDevice {
-
- private String id;
- private String caption;
- private DeviceType type;
- private int subscriptions;
-
- public GpodnetDevice(String id, String caption, String type,
- int subscriptions) {
- Validate.notNull(id);
-
- this.id = id;
- this.caption = caption;
- this.type = DeviceType.fromString(type);
- this.subscriptions = subscriptions;
- }
-
- @Override
- public String toString() {
- return "GpodnetDevice [id=" + id + ", caption=" + caption + ", type="
- + type + ", subscriptions=" + subscriptions + "]";
- }
-
- public static enum DeviceType {
- DESKTOP, LAPTOP, MOBILE, SERVER, OTHER;
-
- static DeviceType fromString(String s) {
- if (s == null) {
- return OTHER;
- }
-
- if (s.equals("desktop")) {
- return DESKTOP;
- } else if (s.equals("laptop")) {
- return LAPTOP;
- } else if (s.equals("mobile")) {
- return MOBILE;
- } else if (s.equals("server")) {
- return SERVER;
- } else {
- return OTHER;
- }
- }
-
- @Override
- public String toString() {
- return super.toString().toLowerCase();
- }
-
- }
-
- public String getId() {
- return id;
- }
-
- public String getCaption() {
- return caption;
- }
-
- public DeviceType getType() {
- return type;
- }
-
- public int getSubscriptions() {
- return subscriptions;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java b/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java
deleted file mode 100644
index afebf66ac..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package de.danoeh.antennapod.core.gpoddernet.model;
-
-import org.apache.commons.lang3.Validate;
-
-public class GpodnetPodcast {
- private String url;
- private String title;
- private String description;
- private int subscribers;
- private String logoUrl;
- private String website;
- private String mygpoLink;
-
- public GpodnetPodcast(String url, String title, String description,
- int subscribers, String logoUrl, String website, String mygpoLink) {
- Validate.notNull(url);
- Validate.notNull(title);
- Validate.notNull(description);
-
- this.url = url;
- this.title = title;
- this.description = description;
- this.subscribers = subscribers;
- this.logoUrl = logoUrl;
- this.website = website;
- this.mygpoLink = mygpoLink;
- }
-
- @Override
- public String toString() {
- return "GpodnetPodcast [url=" + url + ", title=" + title
- + ", description=" + description + ", subscribers="
- + subscribers + ", logoUrl=" + logoUrl + ", website=" + website
- + ", mygpoLink=" + mygpoLink + "]";
- }
-
- public String getUrl() {
- return url;
- }
-
- public String getTitle() {
- return title;
- }
-
- public String getDescription() {
- return description;
- }
-
- public int getSubscribers() {
- return subscribers;
- }
-
- public String getLogoUrl() {
- return logoUrl;
- }
-
- public String getWebsite() {
- return website;
- }
-
- public String getMygpoLink() {
- return mygpoLink;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java b/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java
deleted file mode 100644
index a5cb8c0f0..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package de.danoeh.antennapod.core.gpoddernet.model;
-
-import org.apache.commons.lang3.Validate;
-
-import java.util.List;
-
-public class GpodnetSubscriptionChange {
- private List<String> added;
- private List<String> removed;
- private long timestamp;
-
- public GpodnetSubscriptionChange(List<String> added, List<String> removed,
- long timestamp) {
- Validate.notNull(added);
- Validate.notNull(removed);
-
- this.added = added;
- this.removed = removed;
- this.timestamp = timestamp;
- }
-
- @Override
- public String toString() {
- return "GpodnetSubscriptionChange [added=" + added.toString()
- + ", removed=" + removed.toString() + ", timestamp="
- + timestamp + "]";
- }
-
- public List<String> getAdded() {
- return added;
- }
-
- public List<String> getRemoved() {
- return removed;
- }
-
- public long getTimestamp() {
- return timestamp;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java b/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java
deleted file mode 100644
index 7178f4be5..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package de.danoeh.antennapod.core.gpoddernet.model;
-
-import org.apache.commons.lang3.Validate;
-
-import java.util.Comparator;
-
-public class GpodnetTag {
-
- private String name;
- private int usage;
-
- public GpodnetTag(String name, int usage) {
- Validate.notNull(name);
-
- this.name = name;
- this.usage = usage;
- }
-
- public GpodnetTag(String name) {
- super();
- this.name = name;
- }
-
- @Override
- public String toString() {
- return "GpodnetTag [name=" + name + ", usage=" + usage + "]";
- }
-
- public String getName() {
- return name;
- }
-
- public int getUsage() {
- return usage;
- }
-
- public static class UsageComparator implements Comparator<GpodnetTag> {
-
- @Override
- public int compare(GpodnetTag o1, GpodnetTag o2) {
- return o1.usage - o2.usage;
- }
-
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java b/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java
deleted file mode 100644
index 5a37efa5e..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package de.danoeh.antennapod.core.gpoddernet.model;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Object returned by {@link de.danoeh.antennapod.core.gpoddernet.GpodnetService} in uploadChanges method.
- */
-public class GpodnetUploadChangesResponse {
-
- /**
- * timestamp/ID that can be used for requesting changes since this upload.
- */
- public final long timestamp;
-
- /**
- * URLs that should be updated. The key of the map is the original URL, the value of the map
- * is the sanitized URL.
- */
- public final Map<String, String> updatedUrls;
-
- public GpodnetUploadChangesResponse(long timestamp, Map<String, String> updatedUrls) {
- this.timestamp = timestamp;
- this.updatedUrls = updatedUrls;
- }
-
- /**
- * Creates a new GpodnetUploadChangesResponse-object from a JSON object that was
- * returned by an uploadChanges call.
- *
- * @throws org.json.JSONException If the method could not parse the JSONObject.
- */
- public static GpodnetUploadChangesResponse fromJSONObject(String objectString) throws JSONException {
- final JSONObject object = new JSONObject(objectString);
- final long timestamp = object.getLong("timestamp");
- Map<String, String> updatedUrls = new HashMap<String, String>();
- JSONArray urls = object.getJSONArray("update_urls");
- for (int i = 0; i < urls.length(); i++) {
- JSONArray urlPair = urls.getJSONArray(i);
- updatedUrls.put(urlPair.getString(0), urlPair.getString(1));
- }
- return new GpodnetUploadChangesResponse(timestamp, updatedUrls);
- }
-
- @Override
- public String toString() {
- return "GpodnetUploadChangesResponse{" +
- "timestamp=" + timestamp +
- ", updatedUrls=" + updatedUrls +
- '}';
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/opml/OpmlElement.java b/app/src/main/java/de/danoeh/antennapod/core/opml/OpmlElement.java
deleted file mode 100644
index 8d0a4a842..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/opml/OpmlElement.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package de.danoeh.antennapod.core.opml;
-
-/** Represents a single feed in an OPML file. */
-public class OpmlElement {
- private String text;
- private String xmlUrl;
- private String htmlUrl;
- private String type;
-
- public OpmlElement() {
-
- }
-
- public String getText() {
- return text;
- }
-
- public void setText(String text) {
- this.text = text;
- }
-
- public String getXmlUrl() {
- return xmlUrl;
- }
-
- public void setXmlUrl(String xmlUrl) {
- this.xmlUrl = xmlUrl;
- }
-
- public String getHtmlUrl() {
- return htmlUrl;
- }
-
- public void setHtmlUrl(String htmlUrl) {
- this.htmlUrl = htmlUrl;
- }
-
- public String getType() {
- return type;
- }
-
- public void setType(String type) {
- this.type = type;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/opml/OpmlReader.java b/app/src/main/java/de/danoeh/antennapod/core/opml/OpmlReader.java
deleted file mode 100644
index aa484954d..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/opml/OpmlReader.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package de.danoeh.antennapod.core.opml;
-
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.util.ArrayList;
-
-/** Reads OPML documents. */
-public class OpmlReader {
- private static final String TAG = "OpmlReader";
-
- // ATTRIBUTES
- private boolean isInOpml = false;
- private ArrayList<OpmlElement> elementList;
-
- /**
- * Reads an Opml document and returns a list of all OPML elements it can
- * find
- *
- * @throws IOException
- * @throws XmlPullParserException
- */
- public ArrayList<OpmlElement> readDocument(Reader reader)
- throws XmlPullParserException, IOException {
- elementList = new ArrayList<OpmlElement>();
- XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
- factory.setNamespaceAware(true);
- XmlPullParser xpp = factory.newPullParser();
- xpp.setInput(reader);
- int eventType = xpp.getEventType();
-
- while (eventType != XmlPullParser.END_DOCUMENT) {
- switch (eventType) {
- case XmlPullParser.START_DOCUMENT:
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Reached beginning of document");
- break;
- case XmlPullParser.START_TAG:
- if (xpp.getName().equals(OpmlSymbols.OPML)) {
- isInOpml = true;
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Reached beginning of OPML tree.");
- } else if (isInOpml && xpp.getName().equals(OpmlSymbols.OUTLINE)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Found new Opml element");
- OpmlElement element = new OpmlElement();
-
- final String title = xpp.getAttributeValue(null, OpmlSymbols.TITLE);
- if (title != null) {
- Log.i(TAG, "Using title: " + title);
- element.setText(title);
- } else {
- Log.i(TAG, "Title not found, using text");
- element.setText(xpp.getAttributeValue(null, OpmlSymbols.TEXT));
- }
- element.setXmlUrl(xpp.getAttributeValue(null, OpmlSymbols.XMLURL));
- element.setHtmlUrl(xpp.getAttributeValue(null, OpmlSymbols.HTMLURL));
- element.setType(xpp.getAttributeValue(null, OpmlSymbols.TYPE));
- if (element.getXmlUrl() != null) {
- if (element.getText() == null) {
- Log.i(TAG, "Opml element has no text attribute.");
- element.setText(element.getXmlUrl());
- }
- elementList.add(element);
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Skipping element because of missing xml url");
- }
- }
- break;
- }
- eventType = xpp.next();
- }
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Parsing finished.");
-
- return elementList;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/opml/OpmlSymbols.java b/app/src/main/java/de/danoeh/antennapod/core/opml/OpmlSymbols.java
deleted file mode 100644
index 2b831ca2a..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/opml/OpmlSymbols.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package de.danoeh.antennapod.core.opml;
-
-/** Contains symbols for reading and writing OPML documents. */
-public final class OpmlSymbols {
-
- public static final String OPML = "opml";
- public static final String BODY = "body";
- public static final String OUTLINE = "outline";
- public static final String TEXT = "text";
- public static final String XMLURL = "xmlUrl";
- public static final String HTMLURL = "htmlUrl";
- public static final String TYPE = "type";
- public static final String VERSION = "version";
- public static final String HEAD = "head";
- public static final String TITLE = "title";
-
- private OpmlSymbols() {
-
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/opml/OpmlWriter.java b/app/src/main/java/de/danoeh/antennapod/core/opml/OpmlWriter.java
deleted file mode 100644
index fe14b4954..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/opml/OpmlWriter.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package de.danoeh.antennapod.core.opml;
-
-import android.util.Log;
-import android.util.Xml;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.feed.Feed;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.List;
-
-/** Writes OPML documents. */
-public class OpmlWriter {
- private static final String TAG = "OpmlWriter";
- private static final String ENCODING = "UTF-8";
- private static final String OPML_VERSION = "2.0";
- private static final String OPML_TITLE = "AntennaPod Subscriptions";
-
- /**
- * Takes a list of feeds and a writer and writes those into an OPML
- * document.
- *
- * @throws IOException
- * @throws IllegalStateException
- * @throws IllegalArgumentException
- */
- public void writeDocument(List<Feed> feeds, Writer writer)
- throws IllegalArgumentException, IllegalStateException, IOException {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Starting to write document");
- XmlSerializer xs = Xml.newSerializer();
- xs.setOutput(writer);
-
- xs.startDocument(ENCODING, false);
- xs.startTag(null, OpmlSymbols.OPML);
- xs.attribute(null, OpmlSymbols.VERSION, OPML_VERSION);
-
- xs.startTag(null, OpmlSymbols.HEAD);
- xs.startTag(null, OpmlSymbols.TITLE);
- xs.text(OPML_TITLE);
- xs.endTag(null, OpmlSymbols.TITLE);
- xs.endTag(null, OpmlSymbols.HEAD);
-
- xs.startTag(null, OpmlSymbols.BODY);
- for (Feed feed : feeds) {
- xs.startTag(null, OpmlSymbols.OUTLINE);
- xs.attribute(null, OpmlSymbols.TEXT, feed.getTitle());
- xs.attribute(null, OpmlSymbols.TITLE, feed.getTitle());
- if (feed.getType() != null) {
- xs.attribute(null, OpmlSymbols.TYPE, feed.getType());
- }
- xs.attribute(null, OpmlSymbols.XMLURL, feed.getDownload_url());
- if (feed.getLink() != null) {
- xs.attribute(null, OpmlSymbols.HTMLURL, feed.getLink());
- }
- xs.endTag(null, OpmlSymbols.OUTLINE);
- }
- xs.endTag(null, OpmlSymbols.BODY);
- xs.endTag(null, OpmlSymbols.OPML);
- xs.endDocument();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Finished writing document");
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java b/app/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java
deleted file mode 100644
index 716a74f53..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java
+++ /dev/null
@@ -1,246 +0,0 @@
-package de.danoeh.antennapod.core.preferences;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.PodcastApp;
-import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
-import de.danoeh.antennapod.core.service.GpodnetSyncService;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * Manages preferences for accessing gpodder.net service
- */
-public class GpodnetPreferences {
-
- private static final String TAG = "GpodnetPreferences";
-
- private static final String PREF_NAME = "gpodder.net";
- public static final String PREF_GPODNET_USERNAME = "de.danoeh.antennapod.preferences.gpoddernet.username";
- public static final String PREF_GPODNET_PASSWORD = "de.danoeh.antennapod.preferences.gpoddernet.password";
- public static final String PREF_GPODNET_DEVICEID = "de.danoeh.antennapod.preferences.gpoddernet.deviceID";
- public static final String PREF_GPODNET_HOSTNAME = "prefGpodnetHostname";
-
-
- public static final String PREF_LAST_SYNC_TIMESTAMP = "de.danoeh.antennapod.preferences.gpoddernet.last_sync_timestamp";
- public static final String PREF_SYNC_ADDED = "de.danoeh.antennapod.preferences.gpoddernet.sync_added";
- public static final String PREF_SYNC_REMOVED = "de.danoeh.antennapod.preferences.gpoddernet.sync_removed";
-
- private static String username;
- private static String password;
- private static String deviceID;
- private static String hostname;
-
- private static ReentrantLock feedListLock = new ReentrantLock();
- private static Set<String> addedFeeds;
- private static Set<String> removedFeeds;
-
- /**
- * Last value returned by getSubscriptionChanges call. Will be used for all subsequent calls of getSubscriptionChanges.
- */
- private static long lastSyncTimestamp;
-
- private static boolean preferencesLoaded = false;
-
- private static SharedPreferences getPreferences() {
- return PodcastApp.getInstance().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
- }
-
- private static synchronized void ensurePreferencesLoaded() {
- if (!preferencesLoaded) {
- SharedPreferences prefs = getPreferences();
- username = prefs.getString(PREF_GPODNET_USERNAME, null);
- password = prefs.getString(PREF_GPODNET_PASSWORD, null);
- deviceID = prefs.getString(PREF_GPODNET_DEVICEID, null);
- lastSyncTimestamp = prefs.getLong(PREF_LAST_SYNC_TIMESTAMP, 0);
- addedFeeds = readListFromString(prefs.getString(PREF_SYNC_ADDED, ""));
- removedFeeds = readListFromString(prefs.getString(PREF_SYNC_REMOVED, ""));
- hostname = checkGpodnetHostname(prefs.getString(PREF_GPODNET_HOSTNAME, GpodnetService.DEFAULT_BASE_HOST));
-
- preferencesLoaded = true;
- }
- }
-
- private static void writePreference(String key, String value) {
- SharedPreferences.Editor editor = getPreferences().edit();
- editor.putString(key, value);
- editor.commit();
- }
-
- private static void writePreference(String key, long value) {
- SharedPreferences.Editor editor = getPreferences().edit();
- editor.putLong(key, value);
- editor.commit();
- }
-
- private static void writePreference(String key, Collection<String> value) {
- SharedPreferences.Editor editor = getPreferences().edit();
- editor.putString(key, writeListToString(value));
- editor.commit();
- }
-
- public static String getUsername() {
- ensurePreferencesLoaded();
- return username;
- }
-
- public static void setUsername(String username) {
- GpodnetPreferences.username = username;
- writePreference(PREF_GPODNET_USERNAME, username);
- }
-
- public static String getPassword() {
- ensurePreferencesLoaded();
- return password;
- }
-
- public static void setPassword(String password) {
- GpodnetPreferences.password = password;
- writePreference(PREF_GPODNET_PASSWORD, password);
- }
-
- public static String getDeviceID() {
- ensurePreferencesLoaded();
- return deviceID;
- }
-
- public static void setDeviceID(String deviceID) {
- GpodnetPreferences.deviceID = deviceID;
- writePreference(PREF_GPODNET_DEVICEID, deviceID);
- }
-
- public static long getLastSyncTimestamp() {
- ensurePreferencesLoaded();
- return lastSyncTimestamp;
- }
-
- public static void setLastSyncTimestamp(long lastSyncTimestamp) {
- GpodnetPreferences.lastSyncTimestamp = lastSyncTimestamp;
- writePreference(PREF_LAST_SYNC_TIMESTAMP, lastSyncTimestamp);
- }
-
- public static String getHostname() {
- ensurePreferencesLoaded();
- return hostname;
- }
-
- public static void setHostname(String value) {
- value = checkGpodnetHostname(value);
- if (!value.equals(hostname)) {
- logout();
- writePreference(PREF_GPODNET_HOSTNAME, value);
- hostname = value;
- }
- }
-
- public static void addAddedFeed(String feed) {
- ensurePreferencesLoaded();
- feedListLock.lock();
- if (addedFeeds.add(feed)) {
- writePreference(PREF_SYNC_ADDED, addedFeeds);
- }
- if (removedFeeds.remove(feed)) {
- writePreference(PREF_SYNC_REMOVED, removedFeeds);
- }
- feedListLock.unlock();
- GpodnetSyncService.sendSyncIntent(PodcastApp.getInstance());
- }
-
- public static void addRemovedFeed(String feed) {
- ensurePreferencesLoaded();
- feedListLock.lock();
- if (removedFeeds.add(feed)) {
- writePreference(PREF_SYNC_REMOVED, removedFeeds);
- }
- if (addedFeeds.remove(feed)) {
- writePreference(PREF_SYNC_ADDED, addedFeeds);
- }
- feedListLock.unlock();
- GpodnetSyncService.sendSyncIntent(PodcastApp.getInstance());
- }
-
- public static Set<String> getAddedFeedsCopy() {
- ensurePreferencesLoaded();
- Set<String> copy = new HashSet<String>();
- feedListLock.lock();
- copy.addAll(addedFeeds);
- feedListLock.unlock();
- return copy;
- }
-
- public static void removeAddedFeeds(Collection<String> removed) {
- ensurePreferencesLoaded();
- feedListLock.lock();
- addedFeeds.removeAll(removed);
- writePreference(PREF_SYNC_ADDED, addedFeeds);
- feedListLock.unlock();
- }
-
- public static Set<String> getRemovedFeedsCopy() {
- ensurePreferencesLoaded();
- Set<String> copy = new HashSet<String>();
- feedListLock.lock();
- copy.addAll(removedFeeds);
- feedListLock.unlock();
- return copy;
- }
-
- public static void removeRemovedFeeds(Collection<String> removed) {
- ensurePreferencesLoaded();
- removedFeeds.removeAll(removed);
- writePreference(PREF_SYNC_REMOVED, removedFeeds);
-
- }
-
- /**
- * Returns true if device ID, username and password have a non-null value
- */
- public static boolean loggedIn() {
- ensurePreferencesLoaded();
- return deviceID != null && username != null && password != null;
- }
-
- public static synchronized void logout() {
- if (BuildConfig.DEBUG) Log.d(TAG, "Logout: Clearing preferences");
- setUsername(null);
- setPassword(null);
- setDeviceID(null);
- addedFeeds.clear();
- writePreference(PREF_SYNC_ADDED, addedFeeds);
- removedFeeds.clear();
- writePreference(PREF_SYNC_REMOVED, removedFeeds);
- setLastSyncTimestamp(0);
- }
-
- private static Set<String> readListFromString(String s) {
- Set<String> result = new HashSet<String>();
- for (String item : s.split(" ")) {
- result.add(item);
- }
- return result;
- }
-
- private static String writeListToString(Collection<String> c) {
- StringBuilder result = new StringBuilder();
- for (String item : c) {
- result.append(item);
- result.append(" ");
- }
- return result.toString().trim();
- }
-
- private static String checkGpodnetHostname(String value) {
- int startIndex = 0;
- if (value.startsWith("http://")) {
- startIndex = "http://".length();
- } else if (value.startsWith("https://")) {
- startIndex = "https://".length();
- }
- return value.substring(startIndex);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java b/app/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
deleted file mode 100644
index 756b4067c..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
+++ /dev/null
@@ -1,146 +0,0 @@
-package de.danoeh.antennapod.core.preferences;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-import android.util.Log;
-
-import org.apache.commons.lang3.Validate;
-
-import de.danoeh.antennapod.BuildConfig;
-
-/**
- * Provides access to preferences set by the playback service. A private
- * instance of this class must first be instantiated via createInstance() or
- * otherwise every public method will throw an Exception when called.
- */
-public class PlaybackPreferences implements
- SharedPreferences.OnSharedPreferenceChangeListener {
- private static final String TAG = "PlaybackPreferences";
-
- /**
- * Contains the feed id of the currently playing item if it is a FeedMedia
- * object.
- */
- public static final String PREF_CURRENTLY_PLAYING_FEED_ID = "de.danoeh.antennapod.preferences.lastPlayedFeedId";
-
- /**
- * Contains the id of the currently playing FeedMedia object or
- * NO_MEDIA_PLAYING if the currently playing media is no FeedMedia object.
- */
- public static final String PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID = "de.danoeh.antennapod.preferences.lastPlayedFeedMediaId";
-
- /**
- * Type of the media object that is currently being played. This preference
- * is set to NO_MEDIA_PLAYING after playback has been completed and is set
- * as soon as the 'play' button is pressed.
- */
- public static final String PREF_CURRENTLY_PLAYING_MEDIA = "de.danoeh.antennapod.preferences.currentlyPlayingMedia";
-
- /** True if last played media was streamed. */
- public static final String PREF_CURRENT_EPISODE_IS_STREAM = "de.danoeh.antennapod.preferences.lastIsStream";
-
- /** True if last played media was a video. */
- public static final String PREF_CURRENT_EPISODE_IS_VIDEO = "de.danoeh.antennapod.preferences.lastIsVideo";
-
- /** Value of PREF_CURRENTLY_PLAYING_MEDIA if no media is playing. */
- public static final long NO_MEDIA_PLAYING = -1;
-
- private long currentlyPlayingFeedId;
- private long currentlyPlayingFeedMediaId;
- private long currentlyPlayingMedia;
- private boolean currentEpisodeIsStream;
- private boolean currentEpisodeIsVideo;
-
- private static PlaybackPreferences instance;
- private Context context;
-
- private PlaybackPreferences(Context context) {
- this.context = context;
- loadPreferences();
- }
-
- /**
- * Sets up the UserPreferences class.
- *
- * @throws IllegalArgumentException
- * if context is null
- * */
- public static void createInstance(Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Creating new instance of UserPreferences");
- Validate.notNull(context);
-
- instance = new PlaybackPreferences(context);
-
- PreferenceManager.getDefaultSharedPreferences(context)
- .registerOnSharedPreferenceChangeListener(instance);
- }
-
- private void loadPreferences() {
- SharedPreferences sp = PreferenceManager
- .getDefaultSharedPreferences(context);
- currentlyPlayingFeedId = sp.getLong(PREF_CURRENTLY_PLAYING_FEED_ID, -1);
- currentlyPlayingFeedMediaId = sp.getLong(
- PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, NO_MEDIA_PLAYING);
- currentlyPlayingMedia = sp.getLong(PREF_CURRENTLY_PLAYING_MEDIA,
- NO_MEDIA_PLAYING);
- currentEpisodeIsStream = sp.getBoolean(PREF_CURRENT_EPISODE_IS_STREAM, true);
- currentEpisodeIsVideo = sp.getBoolean(PREF_CURRENT_EPISODE_IS_VIDEO, false);
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sp, String key) {
- if (key.equals(PREF_CURRENTLY_PLAYING_FEED_ID)) {
- currentlyPlayingFeedId = sp.getLong(PREF_CURRENTLY_PLAYING_FEED_ID,
- -1);
-
- } else if (key.equals(PREF_CURRENTLY_PLAYING_MEDIA)) {
- currentlyPlayingMedia = sp
- .getLong(PREF_CURRENTLY_PLAYING_MEDIA, -1);
-
- } else if (key.equals(PREF_CURRENT_EPISODE_IS_STREAM)) {
- currentEpisodeIsStream = sp.getBoolean(PREF_CURRENT_EPISODE_IS_STREAM, true);
-
- } else if (key.equals(PREF_CURRENT_EPISODE_IS_VIDEO)) {
- currentEpisodeIsVideo = sp.getBoolean(PREF_CURRENT_EPISODE_IS_VIDEO, false);
-
- } else if (key.equals(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID)) {
- currentlyPlayingFeedMediaId = sp.getLong(
- PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, NO_MEDIA_PLAYING);
- }
- }
-
- private static void instanceAvailable() {
- if (instance == null) {
- throw new IllegalStateException(
- "UserPreferences was used before being set up");
- }
- }
-
-
- public static long getLastPlayedFeedId() {
- instanceAvailable();
- return instance.currentlyPlayingFeedId;
- }
-
- public static long getCurrentlyPlayingMedia() {
- instanceAvailable();
- return instance.currentlyPlayingMedia;
- }
-
- public static long getCurrentlyPlayingFeedMediaId() {
- return instance.currentlyPlayingFeedMediaId;
- }
-
- public static boolean getCurrentEpisodeIsStream() {
- instanceAvailable();
- return instance.currentEpisodeIsStream;
- }
-
- public static boolean getCurrentEpisodeIsVideo() {
- instanceAvailable();
- return instance.currentEpisodeIsVideo;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/app/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
deleted file mode 100644
index 1669fc601..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
+++ /dev/null
@@ -1,577 +0,0 @@
-package de.danoeh.antennapod.core.preferences;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-import android.util.Log;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.Validate;
-import org.json.JSONArray;
-import org.json.JSONException;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.receiver.FeedUpdateReceiver;
-
-/**
- * Provides access to preferences set by the user in the settings screen. A
- * private instance of this class must first be instantiated via
- * createInstance() or otherwise every public method will throw an Exception
- * when called.
- */
-public class UserPreferences implements
- SharedPreferences.OnSharedPreferenceChangeListener {
- public static final String IMPORT_DIR = "import/";
- private static final String TAG = "UserPreferences";
-
- public static final String PREF_PAUSE_ON_HEADSET_DISCONNECT = "prefPauseOnHeadsetDisconnect";
- public static final String PREF_FOLLOW_QUEUE = "prefFollowQueue";
- public static final String PREF_DOWNLOAD_MEDIA_ON_WIFI_ONLY = "prefDownloadMediaOnWifiOnly";
- public static final String PREF_UPDATE_INTERVAL = "prefAutoUpdateIntervall";
- public static final String PREF_MOBILE_UPDATE = "prefMobileUpdate";
- public static final String PREF_DISPLAY_ONLY_EPISODES = "prefDisplayOnlyEpisodes";
- public static final String PREF_AUTO_DELETE = "prefAutoDelete";
- public static final String PREF_AUTO_FLATTR = "pref_auto_flattr";
- public static final String PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD = "prefAutoFlattrPlayedDurationThreshold";
- public static final String PREF_THEME = "prefTheme";
- public static final String PREF_DATA_FOLDER = "prefDataFolder";
- public static final String PREF_ENABLE_AUTODL = "prefEnableAutoDl";
- public static final String PREF_ENABLE_AUTODL_WIFI_FILTER = "prefEnableAutoDownloadWifiFilter";
- private static final String PREF_AUTODL_SELECTED_NETWORKS = "prefAutodownloadSelectedNetworks";
- public static final String PREF_EPISODE_CACHE_SIZE = "prefEpisodeCacheSize";
- private static final String PREF_PLAYBACK_SPEED = "prefPlaybackSpeed";
- private static final String PREF_PLAYBACK_SPEED_ARRAY = "prefPlaybackSpeedArray";
- public static final String PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS = "prefPauseForFocusLoss";
- private static final String PREF_SEEK_DELTA_SECS = "prefSeekDeltaSecs";
-
- // TODO: Make this value configurable
- private static final float PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD_DEFAULT = 0.8f;
-
- private static int EPISODE_CACHE_SIZE_UNLIMITED = -1;
-
- private static UserPreferences instance;
- private final Context context;
-
- // Preferences
- private boolean pauseOnHeadsetDisconnect;
- private boolean followQueue;
- private boolean downloadMediaOnWifiOnly;
- private long updateInterval;
- private boolean allowMobileUpdate;
- private boolean displayOnlyEpisodes;
- private boolean autoDelete;
- private boolean autoFlattr;
- private float autoFlattrPlayedDurationThreshold;
- private int theme;
- private boolean enableAutodownload;
- private boolean enableAutodownloadWifiFilter;
- private String[] autodownloadSelectedNetworks;
- private int episodeCacheSize;
- private String playbackSpeed;
- private String[] playbackSpeedArray;
- private boolean pauseForFocusLoss;
- private int seekDeltaSecs;
- private boolean isFreshInstall;
-
- private UserPreferences(Context context) {
- this.context = context;
- loadPreferences();
- }
-
- /**
- * Sets up the UserPreferences class.
- *
- * @throws IllegalArgumentException if context is null
- */
- public static void createInstance(Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Creating new instance of UserPreferences");
- Validate.notNull(context);
-
- instance = new UserPreferences(context);
-
- createImportDirectory();
- createNoMediaFile();
- PreferenceManager.getDefaultSharedPreferences(context)
- .registerOnSharedPreferenceChangeListener(instance);
-
- }
-
- private void loadPreferences() {
- SharedPreferences sp = PreferenceManager
- .getDefaultSharedPreferences(context);
- EPISODE_CACHE_SIZE_UNLIMITED = context.getResources().getInteger(
- R.integer.episode_cache_size_unlimited);
- pauseOnHeadsetDisconnect = sp.getBoolean(
- PREF_PAUSE_ON_HEADSET_DISCONNECT, true);
- followQueue = sp.getBoolean(PREF_FOLLOW_QUEUE, false);
- downloadMediaOnWifiOnly = sp.getBoolean(
- PREF_DOWNLOAD_MEDIA_ON_WIFI_ONLY, true);
- updateInterval = readUpdateInterval(sp.getString(PREF_UPDATE_INTERVAL,
- "0"));
- allowMobileUpdate = sp.getBoolean(PREF_MOBILE_UPDATE, false);
- displayOnlyEpisodes = sp.getBoolean(PREF_DISPLAY_ONLY_EPISODES, false);
- autoDelete = sp.getBoolean(PREF_AUTO_DELETE, false);
- autoFlattr = sp.getBoolean(PREF_AUTO_FLATTR, false);
- autoFlattrPlayedDurationThreshold = sp.getFloat(PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD,
- PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD_DEFAULT);
- theme = readThemeValue(sp.getString(PREF_THEME, "0"));
- enableAutodownloadWifiFilter = sp.getBoolean(
- PREF_ENABLE_AUTODL_WIFI_FILTER, false);
- autodownloadSelectedNetworks = StringUtils.split(
- sp.getString(PREF_AUTODL_SELECTED_NETWORKS, ""), ',');
- episodeCacheSize = readEpisodeCacheSizeInternal(sp.getString(
- PREF_EPISODE_CACHE_SIZE, "20"));
- enableAutodownload = sp.getBoolean(PREF_ENABLE_AUTODL, false);
- playbackSpeed = sp.getString(PREF_PLAYBACK_SPEED, "1.0");
- playbackSpeedArray = readPlaybackSpeedArray(sp.getString(
- PREF_PLAYBACK_SPEED_ARRAY, null));
- pauseForFocusLoss = sp.getBoolean(PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, false);
- seekDeltaSecs = Integer.valueOf(sp.getString(PREF_SEEK_DELTA_SECS, "30"));
- }
-
- private int readThemeValue(String valueFromPrefs) {
- switch (Integer.parseInt(valueFromPrefs)) {
- case 0:
- return R.style.Theme_AntennaPod_Light;
- case 1:
- return R.style.Theme_AntennaPod_Dark;
- default:
- return R.style.Theme_AntennaPod_Light;
- }
- }
-
- private long readUpdateInterval(String valueFromPrefs) {
- int hours = Integer.parseInt(valueFromPrefs);
- return TimeUnit.HOURS.toMillis(hours);
- }
-
- private int readEpisodeCacheSizeInternal(String valueFromPrefs) {
- if (valueFromPrefs.equals(context
- .getString(R.string.pref_episode_cache_unlimited))) {
- return EPISODE_CACHE_SIZE_UNLIMITED;
- } else {
- return Integer.valueOf(valueFromPrefs);
- }
- }
-
- private String[] readPlaybackSpeedArray(String valueFromPrefs) {
- String[] selectedSpeeds = null;
- // If this preference hasn't been set yet, return the default options
- if (valueFromPrefs == null) {
- String[] allSpeeds = context.getResources().getStringArray(
- R.array.playback_speed_values);
- List<String> speedList = new LinkedList<String>();
- for (String speedStr : allSpeeds) {
- float speed = Float.parseFloat(speedStr);
- if (speed < 2.0001 && speed * 10 % 1 == 0) {
- speedList.add(speedStr);
- }
- }
- selectedSpeeds = speedList.toArray(new String[speedList.size()]);
- } else {
- try {
- JSONArray jsonArray = new JSONArray(valueFromPrefs);
- selectedSpeeds = new String[jsonArray.length()];
- for (int i = 0; i < jsonArray.length(); i++) {
- selectedSpeeds[i] = jsonArray.getString(i);
- }
- } catch (JSONException e) {
- Log.e(TAG,
- "Got JSON error when trying to get speeds from JSONArray");
- e.printStackTrace();
- }
- }
- return selectedSpeeds;
- }
-
- private static void instanceAvailable() {
- if (instance == null) {
- throw new IllegalStateException(
- "UserPreferences was used before being set up");
- }
- }
-
- public static boolean isPauseOnHeadsetDisconnect() {
- instanceAvailable();
- return instance.pauseOnHeadsetDisconnect;
- }
-
- public static boolean isFollowQueue() {
- instanceAvailable();
- return instance.followQueue;
- }
-
- public static boolean isDownloadMediaOnWifiOnly() {
- instanceAvailable();
- return instance.downloadMediaOnWifiOnly;
- }
-
- public static long getUpdateInterval() {
- instanceAvailable();
- return instance.updateInterval;
- }
-
- public static boolean isAllowMobileUpdate() {
- instanceAvailable();
- return instance.allowMobileUpdate;
- }
-
- public static boolean isDisplayOnlyEpisodes() {
- instanceAvailable();
- //return instance.displayOnlyEpisodes;
- return false;
- }
-
- public static boolean isAutoDelete() {
- instanceAvailable();
- return instance.autoDelete;
- }
-
- public static boolean isAutoFlattr() {
- instanceAvailable();
- return instance.autoFlattr;
- }
-
- /**
- * Returns the time after which an episode should be auto-flattr'd in percent of the episode's
- * duration.
- */
- public static float getAutoFlattrPlayedDurationThreshold() {
- instanceAvailable();
- return instance.autoFlattrPlayedDurationThreshold;
- }
-
- public static int getTheme() {
- instanceAvailable();
- return instance.theme;
- }
-
- public static boolean isEnableAutodownloadWifiFilter() {
- instanceAvailable();
- return instance.enableAutodownloadWifiFilter;
- }
-
- public static String[] getAutodownloadSelectedNetworks() {
- instanceAvailable();
- return instance.autodownloadSelectedNetworks;
- }
-
- public static int getEpisodeCacheSizeUnlimited() {
- return EPISODE_CACHE_SIZE_UNLIMITED;
- }
-
- public static String getPlaybackSpeed() {
- instanceAvailable();
- return instance.playbackSpeed;
- }
-
- public static String[] getPlaybackSpeedArray() {
- instanceAvailable();
- return instance.playbackSpeedArray;
- }
-
- public static int getSeekDeltaMs() {
- instanceAvailable();
- return 1000 * instance.seekDeltaSecs;
- }
-
- /**
- * Returns the capacity of the episode cache. This method will return the
- * negative integer EPISODE_CACHE_SIZE_UNLIMITED if the cache size is set to
- * 'unlimited'.
- */
- public static int getEpisodeCacheSize() {
- instanceAvailable();
- return instance.episodeCacheSize;
- }
-
- public static boolean isEnableAutodownload() {
- instanceAvailable();
- return instance.enableAutodownload;
- }
-
- public static boolean shouldPauseForFocusLoss() {
- instanceAvailable();
- return instance.pauseForFocusLoss;
- }
-
- public static boolean isFreshInstall() {
- instanceAvailable();
- return instance.isFreshInstall;
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sp, String key) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Registered change of user preferences. Key: " + key);
-
- if (key.equals(PREF_DOWNLOAD_MEDIA_ON_WIFI_ONLY)) {
- downloadMediaOnWifiOnly = sp.getBoolean(
- PREF_DOWNLOAD_MEDIA_ON_WIFI_ONLY, true);
-
- } else if (key.equals(PREF_MOBILE_UPDATE)) {
- allowMobileUpdate = sp.getBoolean(PREF_MOBILE_UPDATE, false);
-
- } else if (key.equals(PREF_FOLLOW_QUEUE)) {
- followQueue = sp.getBoolean(PREF_FOLLOW_QUEUE, false);
-
- } else if (key.equals(PREF_UPDATE_INTERVAL)) {
- updateInterval = readUpdateInterval(sp.getString(
- PREF_UPDATE_INTERVAL, "0"));
- restartUpdateAlarm(updateInterval);
-
- } else if (key.equals(PREF_AUTO_DELETE)) {
- autoDelete = sp.getBoolean(PREF_AUTO_DELETE, false);
-
- } else if (key.equals(PREF_AUTO_FLATTR)) {
- autoFlattr = sp.getBoolean(PREF_AUTO_FLATTR, false);
- } else if (key.equals(PREF_DISPLAY_ONLY_EPISODES)) {
- displayOnlyEpisodes = sp.getBoolean(PREF_DISPLAY_ONLY_EPISODES,
- false);
- } else if (key.equals(PREF_THEME)) {
- theme = readThemeValue(sp.getString(PREF_THEME, ""));
- } else if (key.equals(PREF_ENABLE_AUTODL_WIFI_FILTER)) {
- enableAutodownloadWifiFilter = sp.getBoolean(
- PREF_ENABLE_AUTODL_WIFI_FILTER, false);
- } else if (key.equals(PREF_AUTODL_SELECTED_NETWORKS)) {
- autodownloadSelectedNetworks = StringUtils.split(
- sp.getString(PREF_AUTODL_SELECTED_NETWORKS, ""), ',');
- } else if (key.equals(PREF_EPISODE_CACHE_SIZE)) {
- episodeCacheSize = readEpisodeCacheSizeInternal(sp.getString(
- PREF_EPISODE_CACHE_SIZE, "20"));
- } else if (key.equals(PREF_ENABLE_AUTODL)) {
- enableAutodownload = sp.getBoolean(PREF_ENABLE_AUTODL, false);
- } else if (key.equals(PREF_PLAYBACK_SPEED)) {
- playbackSpeed = sp.getString(PREF_PLAYBACK_SPEED, "1.0");
- } else if (key.equals(PREF_PLAYBACK_SPEED_ARRAY)) {
- playbackSpeedArray = readPlaybackSpeedArray(sp.getString(
- PREF_PLAYBACK_SPEED_ARRAY, null));
- } else if (key.equals(PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS)) {
- pauseForFocusLoss = sp.getBoolean(PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, false);
- } else if (key.equals(PREF_SEEK_DELTA_SECS)) {
- seekDeltaSecs = Integer.valueOf(sp.getString(PREF_SEEK_DELTA_SECS, "30"));
- } else if (key.equals(PREF_PAUSE_ON_HEADSET_DISCONNECT)) {
- pauseOnHeadsetDisconnect = sp.getBoolean(PREF_PAUSE_ON_HEADSET_DISCONNECT, true);
- } else if (key.equals(PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD)) {
- autoFlattrPlayedDurationThreshold = sp.getFloat(PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD,
- PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD_DEFAULT);
- }
- }
-
- public static void setPlaybackSpeed(String speed) {
- PreferenceManager.getDefaultSharedPreferences(instance.context).edit()
- .putString(PREF_PLAYBACK_SPEED, speed).apply();
- }
-
- public static void setPlaybackSpeedArray(String[] speeds) {
- JSONArray jsonArray = new JSONArray();
- for (String speed : speeds) {
- jsonArray.put(speed);
- }
- PreferenceManager.getDefaultSharedPreferences(instance.context).edit()
- .putString(PREF_PLAYBACK_SPEED_ARRAY, jsonArray.toString())
- .apply();
- }
-
- public static void setAutodownloadSelectedNetworks(Context context,
- String[] value) {
- SharedPreferences.Editor editor = PreferenceManager
- .getDefaultSharedPreferences(context.getApplicationContext())
- .edit();
- editor.putString(PREF_AUTODL_SELECTED_NETWORKS,
- StringUtils.join(value, ','));
- editor.commit();
- }
-
- /**
- * Sets the update interval value. Should only be used for testing purposes!
- */
- public static void setUpdateInterval(Context context, long newValue) {
- instanceAvailable();
- SharedPreferences.Editor editor = PreferenceManager
- .getDefaultSharedPreferences(context.getApplicationContext())
- .edit();
- editor.putString(PREF_UPDATE_INTERVAL,
- String.valueOf(newValue));
- editor.commit();
- instance.updateInterval = newValue;
- }
-
- /**
- * Change the auto-flattr settings
- *
- * @param context For accessing the shared preferences
- * @param enabled Whether automatic flattring should be enabled at all
- * @param autoFlattrThreshold The percentage of playback time after which an episode should be
- * flattrd. Must be a value between 0 and 1 (inclusive)
- * */
- public static void setAutoFlattrSettings(Context context, boolean enabled, float autoFlattrThreshold) {
- instanceAvailable();
- Validate.inclusiveBetween(0.0, 1.0, autoFlattrThreshold);
- PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext())
- .edit()
- .putBoolean(PREF_AUTO_FLATTR, enabled)
- .putFloat(PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD, autoFlattrThreshold)
- .commit();
- instance.autoFlattr = enabled;
- instance.autoFlattrPlayedDurationThreshold = autoFlattrThreshold;
- }
-
- /**
- * Return the folder where the app stores all of its data. This method will
- * return the standard data folder if none has been set by the user.
- *
- * @param type The name of the folder inside the data folder. May be null
- * when accessing the root of the data folder.
- * @return The data folder that has been requested or null if the folder
- * could not be created.
- */
- public static File getDataFolder(Context context, String type) {
- instanceAvailable();
- SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(context.getApplicationContext());
- String strDir = prefs.getString(PREF_DATA_FOLDER, null);
- if (strDir == null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Using default data folder");
- return context.getExternalFilesDir(type);
- } else {
- File dataDir = new File(strDir);
- if (!dataDir.exists()) {
- if (!dataDir.mkdir()) {
- Log.w(TAG, "Could not create data folder");
- return null;
- }
- }
-
- if (type == null) {
- return dataDir;
- } else {
- // handle path separators
- String[] dirs = type.split("/");
- for (int i = 0; i < dirs.length; i++) {
- if (dirs.length > 0) {
- if (i < dirs.length - 1) {
- dataDir = getDataFolder(context, dirs[i]);
- if (dataDir == null) {
- return null;
- }
- }
- type = dirs[i];
- }
- }
- File typeDir = new File(dataDir, type);
- if (!typeDir.exists()) {
- if (dataDir.canWrite()) {
- if (!typeDir.mkdir()) {
- Log.e(TAG, "Could not create data folder named "
- + type);
- return null;
- }
- }
- }
- return typeDir;
- }
-
- }
- }
-
- public static void setDataFolder(String dir) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Result from DirectoryChooser: " + dir);
- instanceAvailable();
- SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(instance.context);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(PREF_DATA_FOLDER, dir);
- editor.commit();
- createImportDirectory();
- }
-
- /**
- * Create a .nomedia file to prevent scanning by the media scanner.
- */
- private static void createNoMediaFile() {
- File f = new File(instance.context.getExternalFilesDir(null),
- ".nomedia");
- if (!f.exists()) {
- try {
- f.createNewFile();
- } catch (IOException e) {
- Log.e(TAG, "Could not create .nomedia file");
- e.printStackTrace();
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, ".nomedia file created");
- }
- }
-
- /**
- * Creates the import directory if it doesn't exist and if storage is
- * available
- */
- private static void createImportDirectory() {
- File importDir = getDataFolder(instance.context,
- IMPORT_DIR);
- if (importDir != null) {
- if (importDir.exists()) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Import directory already exists");
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Creating import directory");
- importDir.mkdir();
- }
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Could not access external storage.");
- }
- }
-
- /**
- * Updates alarm registered with the AlarmManager service or deactivates it.
- *
- * @param millis new value to register with AlarmManager. If millis is 0, the
- * alarm is deactivated.
- */
- public static void restartUpdateAlarm(long millis) {
- instanceAvailable();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Restarting update alarm. New value: " + millis);
- AlarmManager alarmManager = (AlarmManager) instance.context
- .getSystemService(Context.ALARM_SERVICE);
- PendingIntent updateIntent = PendingIntent.getBroadcast(
- instance.context, 0, new Intent(
- FeedUpdateReceiver.ACTION_REFRESH_FEEDS), 0
- );
- alarmManager.cancel(updateIntent);
- if (millis != 0) {
- alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, millis, millis,
- updateIntent);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Changed alarm to new interval");
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Automatic update was deactivated");
- }
- }
-
- /**
- * Reads episode cache size as it is saved in the episode_cache_size_values array.
- */
- public static int readEpisodeCacheSize(String valueFromPrefs) {
- instanceAvailable();
- return instance.readEpisodeCacheSizeInternal(valueFromPrefs);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/receiver/AlarmUpdateReceiver.java b/app/src/main/java/de/danoeh/antennapod/core/receiver/AlarmUpdateReceiver.java
deleted file mode 100644
index 2057b0881..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/receiver/AlarmUpdateReceiver.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package de.danoeh.antennapod.core.receiver;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-import org.apache.commons.lang3.StringUtils;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-
-/** Listens for events that make it necessary to reset the update alarm. */
-public class AlarmUpdateReceiver extends BroadcastReceiver {
- private static final String TAG = "AlarmUpdateReceiver";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received intent");
- if (StringUtils.equals(intent.getAction(), Intent.ACTION_BOOT_COMPLETED)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Resetting update alarm after reboot");
- } else if (StringUtils.equals(intent.getAction(), Intent.ACTION_PACKAGE_REPLACED)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Resetting update alarm after app upgrade");
- }
-
- UserPreferences.restartUpdateAlarm(UserPreferences.getUpdateInterval());
-
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/receiver/ConnectivityActionReceiver.java b/app/src/main/java/de/danoeh/antennapod/core/receiver/ConnectivityActionReceiver.java
deleted file mode 100644
index e6b1a1b49..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/receiver/ConnectivityActionReceiver.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package de.danoeh.antennapod.core.receiver;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.util.Log;
-
-import org.apache.commons.lang3.StringUtils;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.storage.DBTasks;
-import de.danoeh.antennapod.core.storage.DownloadRequester;
-import de.danoeh.antennapod.core.util.NetworkUtils;
-
-public class ConnectivityActionReceiver extends BroadcastReceiver {
- private static final String TAG = "ConnectivityActionReceiver";
-
- @Override
- public void onReceive(final Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), ConnectivityManager.CONNECTIVITY_ACTION)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received intent");
-
- if (NetworkUtils.autodownloadNetworkAvailable(context)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "auto-dl network available, starting auto-download");
- DBTasks.autodownloadUndownloadedItems(context);
- } else { // if new network is Wi-Fi, finish ongoing downloads,
- // otherwise cancel all downloads
- ConnectivityManager cm = (ConnectivityManager) context
- .getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo ni = cm.getActiveNetworkInfo();
- if (ni == null || ni.getType() != ConnectivityManager.TYPE_WIFI) {
- if (BuildConfig.DEBUG)
- Log.i(TAG,
- "Device is no longer connected to Wi-Fi. Cancelling ongoing downloads");
- DownloadRequester.getInstance().cancelAllDownloads(context);
- }
-
- }
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java b/app/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java
deleted file mode 100644
index ec63bc2ae..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package de.danoeh.antennapod.core.receiver;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.util.Log;
-
-import org.apache.commons.lang3.StringUtils;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.DBTasks;
-
-/** Refreshes all feeds when it receives an intent */
-public class FeedUpdateReceiver extends BroadcastReceiver {
- private static final String TAG = "FeedUpdateReceiver";
- public static final String ACTION_REFRESH_FEEDS = "de.danoeh.antennapod.feedupdatereceiver.refreshFeeds";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), ACTION_REFRESH_FEEDS)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received intent");
- boolean mobileUpdate = UserPreferences.isAllowMobileUpdate();
- if (mobileUpdate || connectedToWifi(context)) {
- DBTasks.refreshExpiredFeeds(context);
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Blocking automatic update: no wifi available / no mobile updates allowed");
- }
- }
- }
-
- private boolean connectedToWifi(Context context) {
- ConnectivityManager connManager = (ConnectivityManager) context
- .getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo mWifi = connManager
- .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
-
- return mWifi.isConnected();
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java b/app/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java
deleted file mode 100644
index be54148cf..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package de.danoeh.antennapod.core.receiver;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-import android.view.KeyEvent;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.service.playback.PlaybackService;
-
-/** Receives media button events. */
-public class MediaButtonReceiver extends BroadcastReceiver {
- private static final String TAG = "MediaButtonReceiver";
- public static final String EXTRA_KEYCODE = "de.danoeh.antennapod.core.service.extra.MediaButtonReceiver.KEYCODE";
-
- public static final String NOTIFY_BUTTON_RECEIVER = "de.danoeh.antennapod.NOTIFY_BUTTON_RECEIVER";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Received intent");
- KeyEvent event = (KeyEvent) intent.getExtras().get(
- Intent.EXTRA_KEY_EVENT);
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- Intent serviceIntent = new Intent(context, PlaybackService.class);
- int keycode = event.getKeyCode();
- serviceIntent.putExtra(EXTRA_KEYCODE, keycode);
- context.startService(serviceIntent);
- }
-
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java b/app/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java
deleted file mode 100644
index 8a2659029..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java
+++ /dev/null
@@ -1,245 +0,0 @@
-package de.danoeh.antennapod.core.service;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.os.IBinder;
-import android.support.v4.app.NotificationCompat;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
-import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceAuthenticationException;
-import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException;
-import de.danoeh.antennapod.core.gpoddernet.model.GpodnetSubscriptionChange;
-import de.danoeh.antennapod.core.gpoddernet.model.GpodnetUploadChangesResponse;
-import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DBTasks;
-import de.danoeh.antennapod.core.storage.DownloadRequestException;
-import de.danoeh.antennapod.core.storage.DownloadRequester;
-import de.danoeh.antennapod.core.util.NetworkUtils;
-
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Synchronizes local subscriptions with gpodder.net service. The service should be started with ACTION_SYNC as an action argument.
- * This class also provides static methods for starting the GpodnetSyncService.
- */
-public class GpodnetSyncService extends Service {
- private static final String TAG = "GpodnetSyncService";
-
- private static final long WAIT_INTERVAL = 5000L;
-
- public static final String ARG_ACTION = "action";
-
- public static final String ACTION_SYNC = "de.danoeh.antennapod.intent.action.sync";
-
- private GpodnetService service;
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- final String action = (intent != null) ? intent.getStringExtra(ARG_ACTION) : null;
- if (action != null && action.equals(ACTION_SYNC)) {
- Log.d(TAG, String.format("Waiting %d milliseconds before uploading changes", WAIT_INTERVAL));
- syncWaiterThread.restart();
- } else {
- Log.e(TAG, "Received invalid intent: action argument is null or invalid");
- }
- return START_FLAG_REDELIVERY;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- if (BuildConfig.DEBUG) Log.d(TAG, "onDestroy");
- syncWaiterThread.interrupt();
-
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- private synchronized GpodnetService tryLogin() throws GpodnetServiceException {
- if (service == null) {
- service = new GpodnetService();
- service.authenticate(GpodnetPreferences.getUsername(), GpodnetPreferences.getPassword());
- }
- return service;
- }
-
- private synchronized void syncChanges() {
- if (GpodnetPreferences.loggedIn() && NetworkUtils.networkAvailable(this)) {
- final long timestamp = GpodnetPreferences.getLastSyncTimestamp();
- try {
- final List<String> localSubscriptions = DBReader.getFeedListDownloadUrls(this);
- GpodnetService service = tryLogin();
-
- if (timestamp == 0) {
- // first sync: download all subscriptions...
- GpodnetSubscriptionChange changes =
- service.getSubscriptionChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), 0);
- if (BuildConfig.DEBUG) Log.d(TAG, "Downloaded subscription changes: " + changes);
- processSubscriptionChanges(localSubscriptions, changes);
-
- // ... then upload all local subscriptions
- if (BuildConfig.DEBUG) Log.d(TAG, "Uploading subscription list: " + localSubscriptions);
- GpodnetUploadChangesResponse uploadChangesResponse =
- service.uploadChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), localSubscriptions, new LinkedList<String>());
- if (BuildConfig.DEBUG) Log.d(TAG, "Uploading changes response: " + uploadChangesResponse);
- GpodnetPreferences.removeAddedFeeds(localSubscriptions);
- GpodnetPreferences.removeRemovedFeeds(GpodnetPreferences.getRemovedFeedsCopy());
- GpodnetPreferences.setLastSyncTimestamp(uploadChangesResponse.timestamp);
- } else {
- Set<String> added = GpodnetPreferences.getAddedFeedsCopy();
- Set<String> removed = GpodnetPreferences.getRemovedFeedsCopy();
-
- // download remote changes first...
- GpodnetSubscriptionChange subscriptionChanges = service.getSubscriptionChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), timestamp);
- if (BuildConfig.DEBUG) Log.d(TAG, "Downloaded subscription changes: " + subscriptionChanges);
- processSubscriptionChanges(localSubscriptions, subscriptionChanges);
-
- // ... then upload changes local changes
- if (BuildConfig.DEBUG) Log.d(TAG, String.format("Uploading subscriptions, Added: %s\nRemoved: %s",
- added.toString(), removed));
- GpodnetUploadChangesResponse uploadChangesResponse = service.uploadChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), added, removed);
- if (BuildConfig.DEBUG) Log.d(TAG, "Upload subscriptions response: " + uploadChangesResponse);
-
- GpodnetPreferences.removeAddedFeeds(added);
- GpodnetPreferences.removeRemovedFeeds(removed);
- GpodnetPreferences.setLastSyncTimestamp(uploadChangesResponse.timestamp);
- }
- clearErrorNotifications();
- } catch (GpodnetServiceException e) {
- e.printStackTrace();
- updateErrorNotification(e);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- }
- }
- stopSelf();
- }
-
- private synchronized void processSubscriptionChanges(List<String> localSubscriptions, GpodnetSubscriptionChange changes) throws DownloadRequestException {
- for (String downloadUrl : changes.getAdded()) {
- if (!localSubscriptions.contains(downloadUrl)) {
- Feed feed = new Feed(downloadUrl, new Date());
- DownloadRequester.getInstance().downloadFeed(this, feed);
- }
- }
- for (String downloadUrl : changes.getRemoved()) {
- DBTasks.removeFeedWithDownloadUrl(GpodnetSyncService.this, downloadUrl);
- }
- }
-
- private void clearErrorNotifications() {
- NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
- nm.cancel(R.id.notification_gpodnet_sync_error);
- nm.cancel(R.id.notification_gpodnet_sync_autherror);
- }
-
- private void updateErrorNotification(GpodnetServiceException exception) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Posting error notification");
-
- NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
- final String title;
- final String description;
- final int id;
- if (exception instanceof GpodnetServiceAuthenticationException) {
- title = getString(R.string.gpodnetsync_auth_error_title);
- description = getString(R.string.gpodnetsync_auth_error_descr);
- id = R.id.notification_gpodnet_sync_autherror;
- } else {
- title = getString(R.string.gpodnetsync_error_title);
- description = getString(R.string.gpodnetsync_error_descr) + exception.getMessage();
- id = R.id.notification_gpodnet_sync_error;
- }
-
- PendingIntent activityIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
-// TODO getGpodnetSyncServiceErrorNotificationPendingIntent
- Notification notification = builder.setContentTitle(title)
- .setContentText(description)
- .setContentIntent(activityIntent)
- .setSmallIcon(R.drawable.stat_notify_sync_error)
- .setAutoCancel(true)
- .build();
- NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- nm.notify(id, notification);
- }
-
- private WaiterThread syncWaiterThread = new WaiterThread(WAIT_INTERVAL) {
- @Override
- public void onWaitCompleted() {
- syncChanges();
- }
- };
-
- private abstract class WaiterThread {
- private long waitInterval;
- private Thread thread;
-
- private WaiterThread(long waitInterval) {
- this.waitInterval = waitInterval;
- reinit();
- }
-
- public abstract void onWaitCompleted();
-
- public void exec() {
- if (!thread.isAlive()) {
- thread.start();
- }
- }
-
- private void reinit() {
- if (thread != null && thread.isAlive()) {
- Log.d(TAG, "Interrupting waiter thread");
- thread.interrupt();
- }
- thread = new Thread() {
- @Override
- public void run() {
- try {
- Thread.sleep(waitInterval);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- if (!isInterrupted()) {
- synchronized (this) {
- onWaitCompleted();
- }
- }
- }
- };
- }
-
- public void restart() {
- reinit();
- exec();
- }
-
- public void interrupt() {
- if (thread != null && thread.isAlive()) {
- thread.interrupt();
- }
- }
- }
-
- public static void sendSyncIntent(Context context) {
- if (GpodnetPreferences.loggedIn()) {
- Intent intent = new Intent(context, GpodnetSyncService.class);
- intent.putExtra(ARG_ACTION, ACTION_SYNC);
- context.startService(intent);
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/service/download/APRedirectHandler.java b/app/src/main/java/de/danoeh/antennapod/core/service/download/APRedirectHandler.java
deleted file mode 100644
index 1c62eaa77..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/service/download/APRedirectHandler.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package de.danoeh.antennapod.core.service.download;
-
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import org.apache.http.Header;
-import org.apache.http.HttpResponse;
-import org.apache.http.impl.client.DefaultRedirectHandler;
-import org.apache.http.protocol.HttpContext;
-
-import java.net.URI;
-
-public class APRedirectHandler extends DefaultRedirectHandler {
- // Identifier for logger
- private static final String TAG = "APRedirectHandler";
- // Header field, which has to be potentially fixed
- private static final String LOC = "Location";
- // Regular expressions for character strings, which should not appear in URLs
- private static final String CHi[] = { "\\{", "\\}", "\\|", "\\\\", "\\^", "~", "\\[", "\\]", "\\`"};
- private static final String CHo[] = { "%7B", "%7D", "%7C", "%5C", "%5E", "%7E", "%5B", "%5D", "%60"};
-
- /**
- * Workaround for broken URLs in redirection.
- * Proper solution involves LaxRedirectStrategy() which is not available in
- * current API yet.
- */
- @Override
- public URI getLocationURI(HttpResponse response, HttpContext context)
- throws org.apache.http.ProtocolException {
-
- Header h[] = response.getHeaders(LOC);
- if (h.length>0) {
- String s = h[0].getValue();
-
- // Fix broken URL
- for(int i=0; i<CHi.length;i++)
- s = s.replaceAll(CHi[i], CHo[i]);
-
- // If anything had to be fixed, then replace the header
- if (!s.equals(h[0].getValue()))
- {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Original URL: " + h[0].getValue());
-
- response.setHeader(LOC, s);
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Fixed URL: " + s);
- }
- }
-
- // call DefaultRedirectHandler with fixed URL
- return super.getLocationURI(response, context);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java b/app/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
deleted file mode 100644
index dc792db81..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package de.danoeh.antennapod.core.service.download;
-
-import android.util.Log;
-import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.BuildConfig;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.params.HttpClientParams;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.params.ConnManagerPNames;
-import org.apache.http.conn.scheme.PlainSocketFactory;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.conn.ssl.SSLSocketFactory;
-import org.apache.http.impl.client.AbstractHttpClient;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.CoreProtocolPNames;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * Provides access to a HttpClient singleton.
- */
-public class AntennapodHttpClient {
- private static final String TAG = "AntennapodHttpClient";
-
- public static final long EXPIRED_CONN_TIMEOUT_SEC = 30;
-
- public static final int MAX_REDIRECTS = 5;
- public static final int CONNECTION_TIMEOUT = 30000;
- public static final int SOCKET_TIMEOUT = 30000;
-
- public static final int MAX_CONNECTIONS = 8;
-
-
- private static volatile HttpClient httpClient = null;
-
- /**
- * Returns the HttpClient singleton.
- */
- public static synchronized HttpClient getHttpClient() {
- if (httpClient == null) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Creating new instance of HTTP client");
-
- HttpParams params = new BasicHttpParams();
- params.setParameter(CoreProtocolPNames.USER_AGENT, AppConfig.USER_AGENT);
- params.setIntParameter("http.protocol.max-redirects", MAX_REDIRECTS);
- params.setBooleanParameter("http.protocol.reject-relative-redirect",
- false);
- HttpConnectionParams.setSoTimeout(params, SOCKET_TIMEOUT);
- HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT);
- HttpClientParams.setRedirecting(params, true);
-
- httpClient = new DefaultHttpClient(createClientConnectionManager(), params);
- // Workaround for broken URLs in redirection
- ((AbstractHttpClient) httpClient)
- .setRedirectHandler(new APRedirectHandler());
- }
- return httpClient;
- }
-
- /**
- * Closes expired connections. This method should be called by the using class once has finished its work with
- * the HTTP client.
- */
- public static synchronized void cleanup() {
- if (httpClient != null) {
- httpClient.getConnectionManager().closeExpiredConnections();
- httpClient.getConnectionManager().closeIdleConnections(EXPIRED_CONN_TIMEOUT_SEC, TimeUnit.SECONDS);
- }
- }
-
-
- private static ClientConnectionManager createClientConnectionManager() {
- HttpParams params = new BasicHttpParams();
- params.setIntParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, MAX_CONNECTIONS);
- return new ThreadSafeClientConnManager(params, prepareSchemeRegistry());
- }
-
- private static SchemeRegistry prepareSchemeRegistry() {
- SchemeRegistry sr = new SchemeRegistry();
-
- Scheme http = new Scheme("http",
- PlainSocketFactory.getSocketFactory(), 80);
- sr.register(http);
- Scheme https = new Scheme("https",
- SSLSocketFactory.getSocketFactory(), 443);
- sr.register(https);
-
- return sr;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java b/app/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
deleted file mode 100644
index c79da0a48..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
+++ /dev/null
@@ -1,209 +0,0 @@
-package de.danoeh.antennapod.core.service.download;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import org.apache.commons.lang3.Validate;
-
-public class DownloadRequest implements Parcelable {
-
- private final String destination;
- private final String source;
- private final String title;
- private String username;
- private String password;
- private boolean deleteOnFailure;
- private final long feedfileId;
- private final int feedfileType;
-
- protected int progressPercent;
- protected long soFar;
- protected long size;
- protected int statusMsg;
-
- public DownloadRequest(String destination, String source, String title,
- long feedfileId, int feedfileType, String username, String password, boolean deleteOnFailure) {
- Validate.notNull(destination);
- Validate.notNull(source);
- Validate.notNull(title);
-
- this.destination = destination;
- this.source = source;
- this.title = title;
- this.feedfileId = feedfileId;
- this.feedfileType = feedfileType;
- this.username = username;
- this.password = password;
- this.deleteOnFailure = deleteOnFailure;
- }
-
- public DownloadRequest(String destination, String source, String title,
- long feedfileId, int feedfileType) {
- this(destination, source, title, feedfileId, feedfileType, null, null, true);
- }
-
- private DownloadRequest(Parcel in) {
- destination = in.readString();
- source = in.readString();
- title = in.readString();
- feedfileId = in.readLong();
- feedfileType = in.readInt();
- deleteOnFailure = (in.readByte() > 0);
- if (in.dataAvail() > 0) {
- username = in.readString();
- } else {
- username = null;
- }
- if (in.dataAvail() > 0) {
- password = in.readString();
- } else {
- password = null;
- }
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(destination);
- dest.writeString(source);
- dest.writeString(title);
- dest.writeLong(feedfileId);
- dest.writeInt(feedfileType);
- dest.writeByte((deleteOnFailure) ? (byte) 1 : 0);
- if (username != null) {
- dest.writeString(username);
- }
- if (password != null) {
- dest.writeString(password);
- }
- }
-
- public static final Parcelable.Creator<DownloadRequest> CREATOR = new Parcelable.Creator<DownloadRequest>() {
- public DownloadRequest createFromParcel(Parcel in) {
- return new DownloadRequest(in);
- }
-
- public DownloadRequest[] newArray(int size) {
- return new DownloadRequest[size];
- }
- };
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- DownloadRequest that = (DownloadRequest) o;
-
- if (deleteOnFailure != that.deleteOnFailure) return false;
- if (feedfileId != that.feedfileId) return false;
- if (feedfileType != that.feedfileType) return false;
- if (progressPercent != that.progressPercent) return false;
- if (size != that.size) return false;
- if (soFar != that.soFar) return false;
- if (statusMsg != that.statusMsg) return false;
- if (destination != null ? !destination.equals(that.destination) : that.destination != null)
- return false;
- if (password != null ? !password.equals(that.password) : that.password != null)
- return false;
- if (source != null ? !source.equals(that.source) : that.source != null) return false;
- if (title != null ? !title.equals(that.title) : that.title != null) return false;
- if (username != null ? !username.equals(that.username) : that.username != null)
- return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = destination != null ? destination.hashCode() : 0;
- result = 31 * result + (source != null ? source.hashCode() : 0);
- result = 31 * result + (title != null ? title.hashCode() : 0);
- result = 31 * result + (username != null ? username.hashCode() : 0);
- result = 31 * result + (password != null ? password.hashCode() : 0);
- result = 31 * result + (deleteOnFailure ? 1 : 0);
- result = 31 * result + (int) (feedfileId ^ (feedfileId >>> 32));
- result = 31 * result + feedfileType;
- result = 31 * result + progressPercent;
- result = 31 * result + (int) (soFar ^ (soFar >>> 32));
- result = 31 * result + (int) (size ^ (size >>> 32));
- result = 31 * result + statusMsg;
- return result;
- }
-
- public String getDestination() {
- return destination;
- }
-
- public String getSource() {
- return source;
- }
-
- public String getTitle() {
- return title;
- }
-
- public long getFeedfileId() {
- return feedfileId;
- }
-
- public int getFeedfileType() {
- return feedfileType;
- }
-
- public int getProgressPercent() {
- return progressPercent;
- }
-
- public void setProgressPercent(int progressPercent) {
- this.progressPercent = progressPercent;
- }
-
- public long getSoFar() {
- return soFar;
- }
-
- public void setSoFar(long soFar) {
- this.soFar = soFar;
- }
-
- public long getSize() {
- return size;
- }
-
- public void setSize(long size) {
- this.size = size;
- }
-
- public int getStatusMsg() {
- return statusMsg;
- }
-
- public void setStatusMsg(int statusMsg) {
- this.statusMsg = statusMsg;
- }
-
- public String getUsername() {
- return username;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- public boolean isDeleteOnFailure() {
- return deleteOnFailure;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java b/app/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java
deleted file mode 100644
index e9381d509..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java
+++ /dev/null
@@ -1,1230 +0,0 @@
-package de.danoeh.antennapod.core.service.download;
-
-import android.annotation.SuppressLint;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.media.MediaMetadataRetriever;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.support.v4.app.NotificationCompat;
-import android.util.Log;
-import android.webkit.URLUtil;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.Validate;
-import org.apache.http.HttpStatus;
-import org.xml.sax.SAXException;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CompletionService;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorCompletionService;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.RejectedExecutionHandler;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.xml.parsers.ParserConfigurationException;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.DownloadAuthenticationActivity;
-import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.adapter.NavListAdapter;
-import de.danoeh.antennapod.core.feed.EventDistributor;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedImage;
-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.fragment.DownloadsFragment;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DBTasks;
-import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.storage.DownloadRequestException;
-import de.danoeh.antennapod.core.storage.DownloadRequester;
-import de.danoeh.antennapod.core.syndication.handler.FeedHandler;
-import de.danoeh.antennapod.core.syndication.handler.UnsupportedFeedtypeException;
-import de.danoeh.antennapod.core.util.ChapterUtils;
-import de.danoeh.antennapod.core.util.DownloadError;
-import de.danoeh.antennapod.core.util.InvalidFeedException;
-
-/**
- * Manages the download of feedfiles in the app. Downloads can be enqueued viathe startService intent.
- * The argument of the intent is an instance of DownloadRequest in the EXTRA_REQUEST field of
- * the intent.
- * After the downloads have finished, the downloaded object will be passed on to a specific handler, depending on the
- * type of the feedfile.
- */
-public class DownloadService extends Service {
- private static final String TAG = "DownloadService";
-
- /**
- * Cancels one download. The intent MUST have an EXTRA_DOWNLOAD_URL extra that contains the download URL of the
- * object whose download should be cancelled.
- */
- public static final String ACTION_CANCEL_DOWNLOAD = "action.de.danoeh.antennapod.core.service.cancelDownload";
-
- /**
- * Cancels all running downloads.
- */
- public static final String ACTION_CANCEL_ALL_DOWNLOADS = "action.de.danoeh.antennapod.core.service.cancelAllDownloads";
-
- /**
- * Extra for ACTION_CANCEL_DOWNLOAD
- */
- public static final String EXTRA_DOWNLOAD_URL = "downloadUrl";
-
- /**
- * Sent by the DownloadService when the content of the downloads list
- * changes.
- */
- public static final String ACTION_DOWNLOADS_CONTENT_CHANGED = "action.de.danoeh.antennapod.core.service.downloadsContentChanged";
-
- /**
- * Extra for ACTION_ENQUEUE_DOWNLOAD intent.
- */
- public static final String EXTRA_REQUEST = "request";
-
- /**
- * Stores new media files that will be queued for auto-download if possible.
- */
- private List<Long> newMediaFiles;
-
- /**
- * Contains all completed downloads that have not been included in the report yet.
- */
- private List<DownloadStatus> reportQueue;
-
- private ExecutorService syncExecutor;
- private CompletionService<Downloader> downloadExecutor;
- private FeedSyncThread feedSyncThread;
-
- /**
- * Number of threads of downloadExecutor.
- */
- private static final int NUM_PARALLEL_DOWNLOADS = 6;
-
- private DownloadRequester requester;
-
-
- private NotificationCompat.Builder notificationCompatBuilder;
- private Notification.BigTextStyle notificationBuilder;
- private int NOTIFICATION_ID = 2;
- private int REPORT_ID = 3;
-
- /**
- * Currently running downloads.
- */
- private List<Downloader> downloads;
-
- /**
- * Number of running downloads.
- */
- private AtomicInteger numberOfDownloads;
-
- /**
- * True if service is running.
- */
- public static boolean isRunning = false;
-
- private Handler handler;
-
- private NotificationUpdater notificationUpdater;
- private ScheduledFuture notificationUpdaterFuture;
- private static final int SCHED_EX_POOL_SIZE = 1;
- private ScheduledThreadPoolExecutor schedExecutor;
-
- private final IBinder mBinder = new LocalBinder();
-
- public class LocalBinder extends Binder {
- public DownloadService getService() {
- return DownloadService.this;
- }
- }
-
- private Thread downloadCompletionThread = new Thread() {
- private static final String TAG = "downloadCompletionThread";
-
- @Override
- public void run() {
- if (BuildConfig.DEBUG) Log.d(TAG, "downloadCompletionThread was started");
- while (!isInterrupted()) {
- try {
- Downloader downloader = downloadExecutor.take().get();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received 'Download Complete' - message.");
- removeDownload(downloader);
- DownloadStatus status = downloader.getResult();
- boolean successful = status.isSuccessful();
-
- final int type = status.getFeedfileType();
- if (successful) {
- if (type == Feed.FEEDFILETYPE_FEED) {
- handleCompletedFeedDownload(downloader
- .getDownloadRequest());
- } else if (type == FeedImage.FEEDFILETYPE_FEEDIMAGE) {
- handleCompletedImageDownload(status, downloader.getDownloadRequest());
- } else if (type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
- handleCompletedFeedMediaDownload(status, downloader.getDownloadRequest());
- }
- } else {
- numberOfDownloads.decrementAndGet();
- if (!status.isCancelled()) {
- if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) {
- postAuthenticationNotification(downloader.getDownloadRequest());
- } else if (status.getReason() == DownloadError.ERROR_HTTP_DATA_ERROR
- && Integer.valueOf(status.getReasonDetailed()) == HttpStatus.SC_REQUESTED_RANGE_NOT_SATISFIABLE) {
-
- Log.d(TAG, "Requested invalid range, restarting download from the beginning");
- FileUtils.deleteQuietly(new File(downloader.getDownloadRequest().getDestination()));
- DownloadRequester.getInstance().download(DownloadService.this, downloader.getDownloadRequest());
- } else {
- Log.e(TAG, "Download failed");
- saveDownloadStatus(status);
- handleFailedDownload(status, downloader.getDownloadRequest());
- }
- }
- sendDownloadHandledIntent();
- queryDownloadsAsync();
- }
- } catch (InterruptedException e) {
- if (BuildConfig.DEBUG) Log.d(TAG, "DownloadCompletionThread was interrupted");
- } catch (ExecutionException e) {
- e.printStackTrace();
- numberOfDownloads.decrementAndGet();
- }
- }
- if (BuildConfig.DEBUG) Log.d(TAG, "End of downloadCompletionThread");
- }
- };
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- if (intent.getParcelableExtra(EXTRA_REQUEST) != null) {
- onDownloadQueued(intent);
- } else if (numberOfDownloads.get() == 0) {
- stopSelf();
- }
- return Service.START_NOT_STICKY;
- }
-
- @SuppressLint("NewApi")
- @Override
- public void onCreate() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Service started");
- isRunning = true;
- handler = new Handler();
- newMediaFiles = Collections.synchronizedList(new ArrayList<Long>());
- reportQueue = Collections.synchronizedList(new ArrayList<DownloadStatus>());
- downloads = new ArrayList<Downloader>();
- numberOfDownloads = new AtomicInteger(0);
-
- IntentFilter cancelDownloadReceiverFilter = new IntentFilter();
- cancelDownloadReceiverFilter.addAction(ACTION_CANCEL_ALL_DOWNLOADS);
- cancelDownloadReceiverFilter.addAction(ACTION_CANCEL_DOWNLOAD);
- registerReceiver(cancelDownloadReceiver, cancelDownloadReceiverFilter);
- syncExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
-
- @Override
- public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setPriority(Thread.MIN_PRIORITY);
- return t;
- }
- });
- downloadExecutor = new ExecutorCompletionService<Downloader>(
- Executors.newFixedThreadPool(NUM_PARALLEL_DOWNLOADS,
- new ThreadFactory() {
-
- @Override
- public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setPriority(Thread.MIN_PRIORITY);
- return t;
- }
- }
- )
- );
- schedExecutor = new ScheduledThreadPoolExecutor(SCHED_EX_POOL_SIZE,
- new ThreadFactory() {
-
- @Override
- public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setPriority(Thread.MIN_PRIORITY);
- return t;
- }
- }, new RejectedExecutionHandler() {
-
- @Override
- public void rejectedExecution(Runnable r,
- ThreadPoolExecutor executor) {
- Log.w(TAG, "SchedEx rejected submission of new task");
- }
- }
- );
- downloadCompletionThread.start();
- feedSyncThread = new FeedSyncThread();
- feedSyncThread.start();
-
- setupNotificationBuilders();
- requester = DownloadRequester.getInstance();
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
-
- @Override
- public void onDestroy() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Service shutting down");
- isRunning = false;
- updateReport();
-
- stopForeground(true);
- NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
- nm.cancel(NOTIFICATION_ID);
-
- downloadCompletionThread.interrupt();
- syncExecutor.shutdown();
- schedExecutor.shutdown();
- feedSyncThread.shutdown();
- cancelNotificationUpdater();
- unregisterReceiver(cancelDownloadReceiver);
-
- if (!newMediaFiles.isEmpty()) {
- DBTasks.autodownloadUndownloadedItems(getApplicationContext(),
- ArrayUtils.toPrimitive(newMediaFiles.toArray(new Long[newMediaFiles.size()])));
- }
- }
-
- @SuppressLint("NewApi")
- private void setupNotificationBuilders() { // TODO getNotificationContentIntent
- Intent intent = new Intent(this, MainActivity.class);
- intent.putExtra(MainActivity.EXTRA_NAV_TYPE, NavListAdapter.VIEW_TYPE_NAV);
- intent.putExtra(MainActivity.EXTRA_NAV_INDEX, MainActivity.POS_DOWNLOADS);
- Bundle args = new Bundle();
- args.putInt(DownloadsFragment.ARG_SELECTED_TAB, DownloadsFragment.POS_RUNNING);
- intent.putExtra(MainActivity.EXTRA_FRAGMENT_ARGS, args);
-
- PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent,
- PendingIntent.FLAG_UPDATE_CURRENT
- );
-
-
- Bitmap icon = BitmapFactory.decodeResource(getResources(),
- R.drawable.stat_notify_sync);
-
- if (android.os.Build.VERSION.SDK_INT >= 16) {
- notificationBuilder = new Notification.BigTextStyle(
- new Notification.Builder(this).setOngoing(true)
- .setContentIntent(pIntent).setLargeIcon(icon)
- .setSmallIcon(R.drawable.stat_notify_sync)
- );
- } else {
- notificationCompatBuilder = new NotificationCompat.Builder(this)
- .setOngoing(true).setContentIntent(pIntent)
- .setLargeIcon(icon)
- .setSmallIcon(R.drawable.stat_notify_sync);
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Notification set up");
- }
-
- /**
- * Updates the contents of the service's notifications. Should be called
- * before setupNotificationBuilders.
- */
- @SuppressLint("NewApi")
- private Notification updateNotifications() {
- String contentTitle = getString(R.string.download_notification_title);
- int numDownloads = requester.getNumberOfDownloads();
- String downloadsLeft;
- if (numDownloads > 0) {
- downloadsLeft = requester.getNumberOfDownloads()
- + getString(R.string.downloads_left);
- } else {
- downloadsLeft = getString(R.string.downloads_processing);
- }
- if (android.os.Build.VERSION.SDK_INT >= 16) {
-
- if (notificationBuilder != null) {
-
- StringBuilder bigText = new StringBuilder("");
- for (int i = 0; i < downloads.size(); i++) {
- Downloader downloader = downloads.get(i);
- final DownloadRequest request = downloader
- .getDownloadRequest();
- if (request.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
- if (request.getTitle() != null) {
- if (i > 0) {
- bigText.append("\n");
- }
- bigText.append("\u2022 " + request.getTitle());
- }
- } else if (request.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
- if (request.getTitle() != null) {
- if (i > 0) {
- bigText.append("\n");
- }
- bigText.append("\u2022 " + request.getTitle()
- + " (" + request.getProgressPercent()
- + "%)");
- }
- }
-
- }
- notificationBuilder.setSummaryText(downloadsLeft);
- notificationBuilder.setBigContentTitle(contentTitle);
- if (bigText != null) {
- notificationBuilder.bigText(bigText.toString());
- }
- return notificationBuilder.build();
- }
- } else {
- if (notificationCompatBuilder != null) {
- notificationCompatBuilder.setContentTitle(contentTitle);
- notificationCompatBuilder.setContentText(downloadsLeft);
- return notificationCompatBuilder.build();
- }
- }
- return null;
- }
-
- private Downloader getDownloader(String downloadUrl) {
- for (Downloader downloader : downloads) {
- if (downloader.getDownloadRequest().getSource().equals(downloadUrl)) {
- return downloader;
- }
- }
- return null;
- }
-
- private BroadcastReceiver cancelDownloadReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), ACTION_CANCEL_DOWNLOAD)) {
- String url = intent.getStringExtra(EXTRA_DOWNLOAD_URL);
- Validate.notNull(url, "ACTION_CANCEL_DOWNLOAD intent needs download url extra");
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Cancelling download with url " + url);
- Downloader d = getDownloader(url);
- if (d != null) {
- d.cancel();
- } else {
- Log.e(TAG, "Could not cancel download with url " + url);
- }
-
- } else if (StringUtils.equals(intent.getAction(), ACTION_CANCEL_ALL_DOWNLOADS)) {
- for (Downloader d : downloads) {
- d.cancel();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Cancelled all downloads");
- }
- sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
-
- }
- queryDownloads();
- }
-
- };
-
- private void onDownloadQueued(Intent intent) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received enqueue request");
- DownloadRequest request = intent.getParcelableExtra(EXTRA_REQUEST);
- if (request == null) {
- throw new IllegalArgumentException(
- "ACTION_ENQUEUE_DOWNLOAD intent needs request extra");
- }
-
- Downloader downloader = getDownloader(request);
- if (downloader != null) {
- numberOfDownloads.incrementAndGet();
- downloads.add(downloader);
- downloadExecutor.submit(downloader);
- sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
- }
-
- queryDownloads();
- }
-
- private Downloader getDownloader(DownloadRequest request) {
- if (URLUtil.isHttpUrl(request.getSource())
- || URLUtil.isHttpsUrl(request.getSource())) {
- return new HttpDownloader(request);
- }
- Log.e(TAG,
- "Could not find appropriate downloader for "
- + request.getSource()
- );
- return null;
- }
-
- /**
- * Remove download from the DownloadRequester list and from the
- * DownloadService list.
- */
- private void removeDownload(final Downloader d) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Removing downloader: "
- + d.getDownloadRequest().getSource());
- boolean rc = downloads.remove(d);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Result of downloads.remove: " + rc);
- DownloadRequester.getInstance().removeDownload(d.getDownloadRequest());
- sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
- }
- });
- }
-
- /**
- * Adds a new DownloadStatus object to the list of completed downloads and
- * saves it in the database
- *
- * @param status the download that is going to be saved
- */
- private void saveDownloadStatus(DownloadStatus status) {
- reportQueue.add(status);
- DBWriter.addDownloadStatus(this, status);
- }
-
- private void sendDownloadHandledIntent() {
- EventDistributor.getInstance().sendDownloadHandledBroadcast();
- }
-
- /**
- * Creates a notification at the end of the service lifecycle to notify the
- * user about the number of completed downloads. A report will only be
- * created if the number of successfully downloaded feeds is bigger than 1
- * or if there is at least one failed download which is not an image or if
- * there is at least one downloaded media file.
- */
- private void updateReport() {
- // check if report should be created
- boolean createReport = false;
- int successfulDownloads = 0;
- int failedDownloads = 0;
-
- // a download report is created if at least one download has failed
- // (excluding failed image downloads)
- for (DownloadStatus status : reportQueue) {
- if (status.isSuccessful()) {
- successfulDownloads++;
- } else if (!status.isCancelled()) {
- if (status.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE) {
- createReport = true;
- }
- failedDownloads++;
- }
- }
-
- if (createReport) { // TODO getReportNotificationContentIntent
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Creating report");
- Intent intent = new Intent(this, MainActivity.class);
- intent.putExtra(MainActivity.EXTRA_NAV_TYPE, NavListAdapter.VIEW_TYPE_NAV);
- intent.putExtra(MainActivity.EXTRA_NAV_INDEX, MainActivity.POS_DOWNLOADS);
- Bundle args = new Bundle();
- args.putInt(DownloadsFragment.ARG_SELECTED_TAB, DownloadsFragment.POS_LOG);
- intent.putExtra(MainActivity.EXTRA_FRAGMENT_ARGS, args);
-
- // create notification object
- Notification notification = new NotificationCompat.Builder(this)
- .setTicker(
- getString(de.danoeh.antennapod.R.string.download_report_title))
- .setContentTitle(
- getString(de.danoeh.antennapod.R.string.download_report_title))
- .setContentText(
- String.format(
- getString(R.string.download_report_content),
- successfulDownloads, failedDownloads)
- )
- .setSmallIcon(R.drawable.stat_notify_sync)
- .setLargeIcon(
- BitmapFactory.decodeResource(getResources(),
- R.drawable.stat_notify_sync)
- )
- .setContentIntent(
- PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
- )
- .setAutoCancel(true).build();
- NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- nm.notify(REPORT_ID, notification);
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "No report is created");
- }
- reportQueue.clear();
- }
-
- /**
- * Calls query downloads on the services main thread. This method should be used instead of queryDownloads if it is
- * used from a thread other than the main thread.
- */
- void queryDownloadsAsync() {
- handler.post(new Runnable() {
- public void run() {
- queryDownloads();
- ;
- }
- });
- }
-
- /**
- * Check if there's something else to download, otherwise stop
- */
- void queryDownloads() {
- if (BuildConfig.DEBUG) {
- Log.d(TAG, numberOfDownloads.get() + " downloads left");
- }
-
- if (numberOfDownloads.get() <= 0 && DownloadRequester.getInstance().hasNoDownloads()) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Number of downloads is " + numberOfDownloads.get() + ", attempting shutdown");
- stopSelf();
- } else {
- setupNotificationUpdater();
- startForeground(NOTIFICATION_ID, updateNotifications());
- }
- }
-
- private void postAuthenticationNotification(final DownloadRequest downloadRequest) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- final String resourceTitle = (downloadRequest.getTitle() != null)
- ? downloadRequest.getTitle() : downloadRequest.getSource();
-
- // TODO getAuthentificationNotificationContentIntent
- final Intent activityIntent = new Intent(getApplicationContext(), DownloadAuthenticationActivity.class);
- activityIntent.putExtra(DownloadAuthenticationActivity.ARG_DOWNLOAD_REQUEST, downloadRequest);
- activityIntent.putExtra(DownloadAuthenticationActivity.ARG_SEND_TO_DOWNLOAD_REQUESTER_BOOL, true);
- final PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, activityIntent, PendingIntent.FLAG_ONE_SHOT);
-
- NotificationCompat.Builder builder = new NotificationCompat.Builder(DownloadService.this);
- builder.setTicker(getText(R.string.authentication_notification_title))
- .setContentTitle(getText(R.string.authentication_notification_title))
- .setContentText(getText(R.string.authentication_notification_msg))
- .setStyle(new NotificationCompat.BigTextStyle().bigText(getText(R.string.authentication_notification_msg)
- + ": " + resourceTitle))
- .setSmallIcon(R.drawable.ic_stat_authentication)
- .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_stat_authentication))
- .setAutoCancel(true)
- .setContentIntent(contentIntent);
- Notification n = builder.build();
- NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- nm.notify(downloadRequest.getSource().hashCode(), n);
- }
- });
- }
-
- /**
- * Is called whenever a Feed is downloaded
- */
- private void handleCompletedFeedDownload(DownloadRequest request) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Handling completed Feed Download");
- feedSyncThread.submitCompletedDownload(request);
-
- }
-
- /**
- * Is called whenever a Feed-Image is downloaded
- */
- private void handleCompletedImageDownload(DownloadStatus status, DownloadRequest request) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Handling completed Image Download");
- syncExecutor.execute(new ImageHandlerThread(status, request));
- }
-
- /**
- * Is called whenever a FeedMedia is downloaded.
- */
- private void handleCompletedFeedMediaDownload(DownloadStatus status, DownloadRequest request) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Handling completed FeedMedia Download");
- syncExecutor.execute(new MediaHandlerThread(status, request));
- }
-
- private void handleFailedDownload(DownloadStatus status, DownloadRequest request) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Handling failed download");
- syncExecutor.execute(new FailedDownloadHandler(status, request));
- }
-
- /**
- * Takes a single Feed, parses the corresponding file and refreshes
- * information in the manager
- */
- class FeedSyncThread extends Thread {
- private static final String TAG = "FeedSyncThread";
-
- private BlockingQueue<DownloadRequest> completedRequests = new LinkedBlockingDeque<DownloadRequest>();
- private CompletionService<Feed> parserService = new ExecutorCompletionService<Feed>(Executors.newSingleThreadExecutor());
- private ExecutorService dbService = Executors.newSingleThreadExecutor();
- private Future<?> dbUpdateFuture;
- private volatile boolean isActive = true;
- private volatile boolean isCollectingRequests = false;
-
- private final long WAIT_TIMEOUT = 3000;
-
-
- /**
- * Waits for completed requests. Once the first request has been taken, the method will wait WAIT_TIMEOUT ms longer to
- * collect more completed requests.
- *
- * @return Collected feeds or null if the method has been interrupted during the first waiting period.
- */
- private List<Feed> collectCompletedRequests() {
- List<Feed> results = new LinkedList<Feed>();
- DownloadRequester requester = DownloadRequester.getInstance();
- int tasks = 0;
-
- try {
- DownloadRequest request = completedRequests.take();
- parserService.submit(new FeedParserTask(request));
- tasks++;
- } catch (InterruptedException e) {
- return null;
- }
-
- tasks += pollCompletedDownloads();
-
- isCollectingRequests = true;
-
- if (requester.isDownloadingFeeds()) {
- // wait for completion of more downloads
- long startTime = System.currentTimeMillis();
- long currentTime = startTime;
- while (requester.isDownloadingFeeds() && (currentTime - startTime) < WAIT_TIMEOUT) {
- try {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Waiting for " + (startTime + WAIT_TIMEOUT - currentTime) + " ms");
- sleep(startTime + WAIT_TIMEOUT - currentTime);
- } catch (InterruptedException e) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "interrupted while waiting for more downloads");
- tasks += pollCompletedDownloads();
- } finally {
- currentTime = System.currentTimeMillis();
- }
- }
-
- tasks += pollCompletedDownloads();
-
- }
-
- isCollectingRequests = false;
-
- for (int i = 0; i < tasks; i++) {
- try {
- Feed f = parserService.take().get();
- if (f != null) {
- results.add(f);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
-
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
-
- return results;
- }
-
- private int pollCompletedDownloads() {
- int tasks = 0;
- for (int i = 0; i < completedRequests.size(); i++) {
- parserService.submit(new FeedParserTask(completedRequests.poll()));
- tasks++;
- }
- return tasks;
- }
-
- @Override
- public void run() {
- while (isActive) {
- final List<Feed> feeds = collectCompletedRequests();
-
- if (feeds == null) {
- continue;
- }
-
- if (BuildConfig.DEBUG) Log.d(TAG, "Bundling " + feeds.size() + " feeds");
-
- for (Feed feed : feeds) {
- removeDuplicateImages(feed); // duplicate images have to removed because the DownloadRequester does not accept two downloads with the same download URL yet.
- }
-
- // Save information of feed in DB
- if (dbUpdateFuture != null) {
- try {
- dbUpdateFuture.get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
-
- dbUpdateFuture = dbService.submit(new Runnable() {
- @Override
- public void run() {
- Feed[] savedFeeds = DBTasks.updateFeed(DownloadService.this, feeds.toArray(new Feed[feeds.size()]));
-
- for (Feed savedFeed : savedFeeds) {
- // Download Feed Image if provided and not downloaded
- if (savedFeed.getImage() != null
- && savedFeed.getImage().isDownloaded() == false) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Feed has image; Downloading....");
- savedFeed.getImage().setOwner(savedFeed);
- final Feed savedFeedRef = savedFeed;
- try {
- requester.downloadImage(DownloadService.this,
- savedFeedRef.getImage());
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DBWriter.addDownloadStatus(
- DownloadService.this,
- new DownloadStatus(
- savedFeedRef.getImage(),
- savedFeedRef
- .getImage()
- .getHumanReadableIdentifier(),
- DownloadError.ERROR_REQUEST_ERROR,
- false, e.getMessage()
- )
- );
- }
- }
-
- // queue new media files for automatic download
- for (FeedItem item : savedFeed.getItems()) {
- if (!item.isRead() && item.hasMedia() && !item.getMedia().isDownloaded()) {
- newMediaFiles.add(item.getMedia().getId());
- }
- }
-
- numberOfDownloads.decrementAndGet();
- }
-
- sendDownloadHandledIntent();
-
- queryDownloadsAsync();
- }
- });
-
- }
-
- if (dbUpdateFuture != null) {
- try {
- dbUpdateFuture.get();
- } catch (InterruptedException e) {
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
-
- if (BuildConfig.DEBUG) Log.d(TAG, "Shutting down");
-
- }
-
- private class FeedParserTask implements Callable<Feed> {
-
- private DownloadRequest request;
-
- private FeedParserTask(DownloadRequest request) {
- this.request = request;
- }
-
- @Override
- public Feed call() throws Exception {
- return parseFeed(request);
- }
- }
-
- private Feed parseFeed(DownloadRequest request) {
- Feed savedFeed = null;
-
- Feed feed = new Feed(request.getSource(), new Date());
- feed.setFile_url(request.getDestination());
- feed.setId(request.getFeedfileId());
- feed.setDownloaded(true);
- feed.setPreferences(new FeedPreferences(0, true, request.getUsername(), request.getPassword()));
-
- DownloadError reason = null;
- String reasonDetailed = null;
- boolean successful = true;
- FeedHandler feedHandler = new FeedHandler();
-
- try {
- feed = feedHandler.parseFeed(feed).feed;
- if (BuildConfig.DEBUG)
- Log.d(TAG, feed.getTitle() + " parsed");
- if (checkFeedData(feed) == false) {
- throw new InvalidFeedException();
- }
-
- } catch (SAXException e) {
- successful = false;
- e.printStackTrace();
- reason = DownloadError.ERROR_PARSER_EXCEPTION;
- reasonDetailed = e.getMessage();
- } catch (IOException e) {
- successful = false;
- e.printStackTrace();
- reason = DownloadError.ERROR_PARSER_EXCEPTION;
- reasonDetailed = e.getMessage();
- } catch (ParserConfigurationException e) {
- successful = false;
- e.printStackTrace();
- reason = DownloadError.ERROR_PARSER_EXCEPTION;
- reasonDetailed = e.getMessage();
- } catch (UnsupportedFeedtypeException e) {
- e.printStackTrace();
- successful = false;
- reason = DownloadError.ERROR_UNSUPPORTED_TYPE;
- reasonDetailed = e.getMessage();
- } catch (InvalidFeedException e) {
- e.printStackTrace();
- successful = false;
- reason = DownloadError.ERROR_PARSER_EXCEPTION;
- reasonDetailed = e.getMessage();
- }
-
- // cleanup();
- if (savedFeed == null) {
- savedFeed = feed;
- }
-
-
- if (successful) {
- return savedFeed;
- } else {
- numberOfDownloads.decrementAndGet();
- saveDownloadStatus(new DownloadStatus(savedFeed,
- savedFeed.getHumanReadableIdentifier(), reason, successful,
- reasonDetailed));
- return null;
- }
- }
-
-
- /**
- * Checks if the feed was parsed correctly.
- */
- private boolean checkFeedData(Feed feed) {
- if (feed.getTitle() == null) {
- Log.e(TAG, "Feed has no title.");
- return false;
- }
- if (!hasValidFeedItems(feed)) {
- Log.e(TAG, "Feed has invalid items");
- return false;
- }
- return true;
- }
-
- /**
- * Checks if the FeedItems of this feed have images that point
- * to the same URL. If two FeedItems have an image that points to
- * the same URL, the reference of the second item is removed, so that every image
- * reference is unique.
- */
- private void removeDuplicateImages(Feed feed) {
- for (int x = 0; x < feed.getItems().size(); x++) {
- for (int y = x + 1; y < feed.getItems().size(); y++) {
- FeedItem item1 = feed.getItems().get(x);
- FeedItem item2 = feed.getItems().get(y);
- if (item1.hasItemImage() && item2.hasItemImage()) {
- if (StringUtils.equals(item1.getImage().getDownload_url(), item2.getImage().getDownload_url())) {
- item2.setImage(null);
- }
- }
- }
- }
- }
-
- private boolean hasValidFeedItems(Feed feed) {
- for (FeedItem item : feed.getItems()) {
- if (item.getTitle() == null) {
- Log.e(TAG, "Item has no title");
- return false;
- }
- if (item.getPubDate() == null) {
- Log.e(TAG,
- "Item has no pubDate. Using current time as pubDate");
- if (item.getTitle() != null) {
- Log.e(TAG, "Title of invalid item: " + item.getTitle());
- }
- item.setPubDate(new Date());
- }
- }
- return true;
- }
-
- /**
- * Delete files that aren't needed anymore
- */
- private void cleanup(Feed feed) {
- if (feed.getFile_url() != null) {
- if (new File(feed.getFile_url()).delete())
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Successfully deleted cache file.");
- else
- Log.e(TAG, "Failed to delete cache file.");
- feed.setFile_url(null);
- } else if (BuildConfig.DEBUG) {
- Log.d(TAG, "Didn't delete cache file: File url is not set.");
- }
- }
-
- public void shutdown() {
- isActive = false;
- if (isCollectingRequests) {
- interrupt();
- }
- }
-
- public void submitCompletedDownload(DownloadRequest request) {
- completedRequests.offer(request);
- if (isCollectingRequests) {
- interrupt();
- }
- }
-
- }
-
- /**
- * Handles failed downloads.
- * <p/>
- * If the file has been partially downloaded, this handler will set the file_url of the FeedFile to the location
- * of the downloaded file.
- * <p/>
- * Currently, this handler only handles FeedMedia objects, because Feeds and FeedImages are deleted if the download fails.
- */
- class FailedDownloadHandler implements Runnable {
-
- private DownloadRequest request;
- private DownloadStatus status;
-
- FailedDownloadHandler(DownloadStatus status, DownloadRequest request) {
- this.request = request;
- this.status = status;
- }
-
- @Override
- public void run() {
- if (request.isDeleteOnFailure()) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Ignoring failed download, deleteOnFailure=true");
- } else {
- File dest = new File(request.getDestination());
- if (dest.exists() && request.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
- Log.d(TAG, "File has been partially downloaded. Writing file url");
- FeedMedia media = DBReader.getFeedMedia(DownloadService.this, request.getFeedfileId());
- media.setFile_url(request.getDestination());
- try {
- DBWriter.setFeedMedia(DownloadService.this, media).get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
-
- /**
- * Handles a completed image download.
- */
- class ImageHandlerThread implements Runnable {
-
- private DownloadRequest request;
- private DownloadStatus status;
-
- public ImageHandlerThread(DownloadStatus status, DownloadRequest request) {
- Validate.notNull(status);
- Validate.notNull(request);
-
- this.status = status;
- this.request = request;
- }
-
- @Override
- public void run() {
- FeedImage image = DBReader.getFeedImage(DownloadService.this, request.getFeedfileId());
- if (image == null) {
- throw new IllegalStateException("Could not find downloaded image in database");
- }
-
- image.setFile_url(request.getDestination());
- image.setDownloaded(true);
-
- saveDownloadStatus(status);
- sendDownloadHandledIntent();
- DBWriter.setFeedImage(DownloadService.this, image);
- numberOfDownloads.decrementAndGet();
- queryDownloadsAsync();
- }
- }
-
- /**
- * Handles a completed media download.
- */
- class MediaHandlerThread implements Runnable {
-
- private DownloadRequest request;
- private DownloadStatus status;
-
- public MediaHandlerThread(DownloadStatus status, DownloadRequest request) {
- Validate.notNull(status);
- Validate.notNull(request);
-
- this.status = status;
- this.request = request;
- }
-
- @Override
- public void run() {
- FeedMedia media = DBReader.getFeedMedia(DownloadService.this,
- request.getFeedfileId());
- if (media == null) {
- throw new IllegalStateException(
- "Could not find downloaded media object in database");
- }
- boolean chaptersRead = false;
- media.setDownloaded(true);
- media.setFile_url(request.getDestination());
-
- // Get duration
- MediaMetadataRetriever mmr = null;
- try {
- mmr = new MediaMetadataRetriever();
- mmr.setDataSource(media.getFile_url());
- String durationStr = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
- media.setDuration(Integer.parseInt(durationStr));
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Duration of file is " + media.getDuration());
- } catch (NumberFormatException e) {
- e.printStackTrace();
- } catch (RuntimeException e) {
- e.printStackTrace();
- } finally {
- if (mmr != null) {
- mmr.release();
- }
- }
-
- if (media.getItem().getChapters() == null) {
- ChapterUtils.loadChaptersFromFileUrl(media);
- if (media.getItem().getChapters() != null) {
- chaptersRead = true;
- }
- }
-
- try {
- if (chaptersRead) {
- DBWriter.setFeedItem(DownloadService.this, media.getItem()).get();
- }
- DBWriter.setFeedMedia(DownloadService.this, media).get();
- if (!DBTasks.isInQueue(DownloadService.this, media.getItem().getId())) {
- DBWriter.addQueueItem(DownloadService.this, media.getItem().getId()).get();
- }
- } catch (ExecutionException e) {
- e.printStackTrace();
- status = new DownloadStatus(media, media.getEpisodeTitle(), DownloadError.ERROR_DB_ACCESS_ERROR, false, e.getMessage());
- } catch (InterruptedException e) {
- e.printStackTrace();
- status = new DownloadStatus(media, media.getEpisodeTitle(), DownloadError.ERROR_DB_ACCESS_ERROR, false, e.getMessage());
- }
-
- saveDownloadStatus(status);
- sendDownloadHandledIntent();
-
- numberOfDownloads.decrementAndGet();
- queryDownloadsAsync();
- }
- }
-
- /**
- * Schedules the notification updater task if it hasn't been scheduled yet.
- */
- private void setupNotificationUpdater() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Setting up notification updater");
- if (notificationUpdater == null) {
- notificationUpdater = new NotificationUpdater();
- notificationUpdaterFuture = schedExecutor.scheduleAtFixedRate(
- notificationUpdater, 5L, 5L, TimeUnit.SECONDS);
- }
- }
-
- private void cancelNotificationUpdater() {
- boolean result = false;
- if (notificationUpdaterFuture != null) {
- result = notificationUpdaterFuture.cancel(true);
- }
- notificationUpdater = null;
- notificationUpdaterFuture = null;
- Log.d(TAG, "NotificationUpdater cancelled. Result: " + result);
- }
-
- private class NotificationUpdater implements Runnable {
- public void run() {
- handler.post(new Runnable() {
- @Override
- public void run() {
- Notification n = updateNotifications();
- if (n != null) {
- NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- nm.notify(NOTIFICATION_ID, n);
- }
- }
- });
- }
- }
-
- public List<Downloader> getDownloads() {
- return downloads;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java b/app/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java
deleted file mode 100644
index d05650d10..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java
+++ /dev/null
@@ -1,181 +0,0 @@
-package de.danoeh.antennapod.core.service.download;
-
-import org.apache.commons.lang3.Validate;
-
-import de.danoeh.antennapod.core.feed.FeedFile;
-import de.danoeh.antennapod.core.util.DownloadError;
-
-import java.util.Date;
-
-/** Contains status attributes for one download */
-public class DownloadStatus {
- /**
- * Downloaders should use this constant for the size attribute if necessary
- * so that the listadapters etc. can react properly.
- */
- public static final int SIZE_UNKNOWN = -1;
-
- // ----------------------------------- ATTRIBUTES STORED IN DB
- /** Unique id for storing the object in database. */
- protected long id;
- /**
- * A human-readable string which is shown to the user so that he can
- * identify the download. Should be the title of the item/feed/media or the
- * URL if the download has no other title.
- */
- protected String title;
- protected DownloadError reason;
- /**
- * A message which can be presented to the user to give more information.
- * Should be null if Download was successful.
- */
- protected String reasonDetailed;
- protected boolean successful;
- protected Date completionDate;
- protected long feedfileId;
- /**
- * Is used to determine the type of the feedfile even if the feedfile does
- * not exist anymore. The value should be FEEDFILETYPE_FEED,
- * FEEDFILETYPE_FEEDIMAGE or FEEDFILETYPE_FEEDMEDIA
- */
- protected int feedfileType;
-
- // ------------------------------------ NOT STORED IN DB
- protected boolean done;
- protected boolean cancelled;
-
- /** Constructor for restoring Download status entries from DB. */
- public DownloadStatus(long id, String title, long feedfileId,
- int feedfileType, boolean successful, DownloadError reason,
- Date completionDate, String reasonDetailed) {
- this.id = id;
- this.title = title;
- this.done = true;
- this.feedfileId = feedfileId;
- this.reason = reason;
- this.successful = successful;
- this.completionDate = (Date) completionDate.clone();
- this.reasonDetailed = reasonDetailed;
- this.feedfileType = feedfileType;
- }
-
- public DownloadStatus(DownloadRequest request, DownloadError reason,
- boolean successful, boolean cancelled, String reasonDetailed) {
- Validate.notNull(request);
-
- this.title = request.getTitle();
- this.feedfileId = request.getFeedfileId();
- this.feedfileType = request.getFeedfileType();
- this.reason = reason;
- this.successful = successful;
- this.cancelled = cancelled;
- this.reasonDetailed = reasonDetailed;
- this.completionDate = new Date();
- }
-
- /** Constructor for creating new completed downloads. */
- public DownloadStatus(FeedFile feedfile, String title, DownloadError reason,
- boolean successful, String reasonDetailed) {
- Validate.notNull(feedfile);
-
- this.title = title;
- this.done = true;
- this.feedfileId = feedfile.getId();
- this.feedfileType = feedfile.getTypeAsInt();
- this.reason = reason;
- this.successful = successful;
- this.completionDate = new Date();
- this.reasonDetailed = reasonDetailed;
- }
-
- /** Constructor for creating new completed downloads. */
- public DownloadStatus(long feedfileId, int feedfileType, String title,
- DownloadError reason, boolean successful, String reasonDetailed) {
- this.title = title;
- this.done = true;
- this.feedfileId = feedfileId;
- this.feedfileType = feedfileType;
- this.reason = reason;
- this.successful = successful;
- this.completionDate = new Date();
- this.reasonDetailed = reasonDetailed;
- }
-
- @Override
- public String toString() {
- return "DownloadStatus [id=" + id + ", title=" + title + ", reason="
- + reason + ", reasonDetailed=" + reasonDetailed
- + ", successful=" + successful + ", completionDate="
- + completionDate + ", feedfileId=" + feedfileId
- + ", feedfileType=" + feedfileType + ", done=" + done
- + ", cancelled=" + cancelled + "]";
- }
-
- public long getId() {
- return id;
- }
-
- public String getTitle() {
- return title;
- }
-
- public DownloadError getReason() {
- return reason;
- }
-
- public String getReasonDetailed() {
- return reasonDetailed;
- }
-
- public boolean isSuccessful() {
- return successful;
- }
-
- public Date getCompletionDate() {
- return (Date) completionDate.clone();
- }
-
- public long getFeedfileId() {
- return feedfileId;
- }
-
- public int getFeedfileType() {
- return feedfileType;
- }
-
- public boolean isDone() {
- return done;
- }
-
- public boolean isCancelled() {
- return cancelled;
- }
-
- public void setSuccessful() {
- this.successful = true;
- this.reason = DownloadError.SUCCESS;
- this.done = true;
- }
-
- public void setFailed(DownloadError reason, String reasonDetailed) {
- this.successful = false;
- this.reason = reason;
- this.reasonDetailed = reasonDetailed;
- this.done = true;
- }
-
- public void setCancelled() {
- this.successful = false;
- this.reason = DownloadError.ERROR_DOWNLOAD_CANCELLED;
- this.done = true;
- this.cancelled = true;
- }
-
- public void setCompletionDate(Date completionDate) {
- this.completionDate = (Date) completionDate.clone();
- }
-
- public void setId(long id) {
- this.id = id;
- }
-} \ No newline at end of file
diff --git a/app/src/main/java/de/danoeh/antennapod/core/service/download/Downloader.java b/app/src/main/java/de/danoeh/antennapod/core/service/download/Downloader.java
deleted file mode 100644
index 5af9c2d05..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/service/download/Downloader.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package de.danoeh.antennapod.core.service.download;
-
-import android.content.Context;
-import android.net.wifi.WifiManager;
-import de.danoeh.antennapod.PodcastApp;
-import de.danoeh.antennapod.R;
-
-import java.util.concurrent.Callable;
-
-/** Downloads files */
-public abstract class Downloader implements Callable<Downloader> {
- private static final String TAG = "Downloader";
-
- protected volatile boolean finished;
-
- protected volatile boolean cancelled;
-
- protected DownloadRequest request;
- protected DownloadStatus result;
-
- public Downloader(DownloadRequest request) {
- super();
- this.request = request;
- this.request.setStatusMsg(R.string.download_pending);
- this.cancelled = false;
- this.result = new DownloadStatus(request, null, false, false, null);
- }
-
- protected abstract void download();
-
- public final Downloader call() {
- WifiManager wifiManager = (WifiManager) PodcastApp.getInstance().getSystemService(Context.WIFI_SERVICE);
- WifiManager.WifiLock wifiLock = null;
- if (wifiManager != null) {
- wifiLock = wifiManager.createWifiLock(TAG);
- wifiLock.acquire();
- }
-
- download();
-
- if (wifiLock != null) {
- wifiLock.release();
- }
-
- if (result == null) {
- throw new IllegalStateException(
- "Downloader hasn't created DownloadStatus object");
- }
- finished = true;
- return this;
- }
-
- public DownloadRequest getDownloadRequest() {
- return request;
- }
-
- public DownloadStatus getResult() {
- return result;
- }
-
- public boolean isFinished() {
- return finished;
- }
-
- public void cancel() {
- cancelled = true;
- }
-
-} \ No newline at end of file
diff --git a/app/src/main/java/de/danoeh/antennapod/core/service/download/DownloaderCallback.java b/app/src/main/java/de/danoeh/antennapod/core/service/download/DownloaderCallback.java
deleted file mode 100644
index 2d9347b0a..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/service/download/DownloaderCallback.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package de.danoeh.antennapod.core.service.download;
-
-/**
- * Callback used by the Downloader-classes to notify the requester that the
- * download has completed.
- */
-public interface DownloaderCallback {
-
- public void onDownloadCompleted(Downloader downloader);
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java b/app/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
deleted file mode 100644
index cba59be01..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
+++ /dev/null
@@ -1,246 +0,0 @@
-package de.danoeh.antennapod.core.service.download;
-
-import android.net.http.AndroidHttpClient;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.PodcastApp;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.feed.FeedImage;
-import de.danoeh.antennapod.core.util.DownloadError;
-import de.danoeh.antennapod.core.util.StorageUtils;
-import de.danoeh.antennapod.core.util.URIUtil;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.auth.BasicScheme;
-import org.apache.http.message.BasicHeader;
-
-import java.io.*;
-import java.net.HttpURLConnection;
-import java.net.SocketTimeoutException;
-import java.net.UnknownHostException;
-
-public class HttpDownloader extends Downloader {
- private static final String TAG = "HttpDownloader";
-
- private static final int BUFFER_SIZE = 8 * 1024;
-
- public HttpDownloader(DownloadRequest request) {
- super(request);
- }
-
- @Override
- protected void download() {
- File destination = new File(request.getDestination());
- final boolean fileExists = destination.exists();
-
- if (request.isDeleteOnFailure() && fileExists) {
- Log.w(TAG, "File already exists");
- if (request.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE) {
- onFail(DownloadError.ERROR_FILE_EXISTS, null);
- return;
- } else {
- onSuccess();
- return;
- }
- }
-
- HttpClient httpClient = AntennapodHttpClient.getHttpClient();
- RandomAccessFile out = null;
- InputStream connection = null;
- try {
- HttpGet httpGet = new HttpGet(URIUtil.getURIFromRequestUrl(request.getSource()));
-
- // add authentication information
- String userInfo = httpGet.getURI().getUserInfo();
- if (userInfo != null) {
- String[] parts = userInfo.split(":");
- if (parts.length == 2) {
- httpGet.addHeader(BasicScheme.authenticate(
- new UsernamePasswordCredentials(parts[0], parts[1]),
- "UTF-8", false));
- }
- } else if (!StringUtils.isEmpty(request.getUsername()) && request.getPassword() != null) {
- httpGet.addHeader(BasicScheme.authenticate(new UsernamePasswordCredentials(request.getUsername(),
- request.getPassword()), "UTF-8", false));
- }
-
- // add range header if necessary
- if (fileExists) {
- request.setSoFar(destination.length());
- httpGet.addHeader(new BasicHeader("Range",
- "bytes=" + request.getSoFar() + "-"));
- if (BuildConfig.DEBUG) Log.d(TAG, "Adding range header: " + request.getSoFar());
- }
-
- HttpResponse response = httpClient.execute(httpGet);
- HttpEntity httpEntity = response.getEntity();
- int responseCode = response.getStatusLine().getStatusCode();
- Header contentEncodingHeader = response.getFirstHeader("Content-Encoding");
-
- final boolean isGzip = contentEncodingHeader != null &&
- contentEncodingHeader.getValue().equalsIgnoreCase("gzip");
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Response code is " + responseCode);
-
- if (responseCode / 100 != 2 || httpEntity == null) {
- final DownloadError error;
- final String details;
- if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
- error = DownloadError.ERROR_UNAUTHORIZED;
- details = String.valueOf(responseCode);
- } else {
- error = DownloadError.ERROR_HTTP_DATA_ERROR;
- details = String.valueOf(responseCode);
- }
- onFail(error, details);
- return;
- }
-
- if (!StorageUtils.storageAvailable(PodcastApp.getInstance())) {
- onFail(DownloadError.ERROR_DEVICE_NOT_FOUND, null);
- return;
- }
-
- connection = new BufferedInputStream(AndroidHttpClient
- .getUngzippedContent(httpEntity));
-
- Header[] contentRangeHeaders = (fileExists) ? response.getHeaders("Content-Range") : null;
-
- if (fileExists && responseCode == HttpStatus.SC_PARTIAL_CONTENT
- && contentRangeHeaders != null && contentRangeHeaders.length > 0) {
- String start = contentRangeHeaders[0].getValue().substring("bytes ".length(),
- contentRangeHeaders[0].getValue().indexOf("-"));
- request.setSoFar(Long.valueOf(start));
- Log.d(TAG, "Starting download at position " + request.getSoFar());
-
- out = new RandomAccessFile(destination, "rw");
- out.seek(request.getSoFar());
- } else {
- destination.delete();
- destination.createNewFile();
- out = new RandomAccessFile(destination, "rw");
- }
-
-
- byte[] buffer = new byte[BUFFER_SIZE];
- int count = 0;
- request.setStatusMsg(R.string.download_running);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Getting size of download");
- request.setSize(httpEntity.getContentLength() + request.getSoFar());
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Size is " + request.getSize());
- if (request.getSize() < 0) {
- request.setSize(DownloadStatus.SIZE_UNKNOWN);
- }
-
- long freeSpace = StorageUtils.getFreeSpaceAvailable();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Free space is " + freeSpace);
-
- if (request.getSize() != DownloadStatus.SIZE_UNKNOWN
- && request.getSize() > freeSpace) {
- onFail(DownloadError.ERROR_NOT_ENOUGH_SPACE, null);
- return;
- }
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Starting download");
- while (!cancelled
- && (count = connection.read(buffer)) != -1) {
- out.write(buffer, 0, count);
- request.setSoFar(request.getSoFar() + count);
- request.setProgressPercent((int) (((double) request
- .getSoFar() / (double) request
- .getSize()) * 100));
- }
- if (cancelled) {
- onCancelled();
- } else {
- // check if size specified in the response header is the same as the size of the
- // written file. This check cannot be made if compression was used
- if (!isGzip && request.getSize() != DownloadStatus.SIZE_UNKNOWN &&
- request.getSoFar() != request.getSize()) {
- onFail(DownloadError.ERROR_IO_ERROR,
- "Download completed but size: " +
- request.getSoFar() +
- " does not equal expected size " +
- request.getSize()
- );
- return;
- }
- onSuccess();
- }
-
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- onFail(DownloadError.ERROR_MALFORMED_URL, e.getMessage());
- } catch (SocketTimeoutException e) {
- e.printStackTrace();
- onFail(DownloadError.ERROR_CONNECTION_ERROR, e.getMessage());
- } catch (UnknownHostException e) {
- e.printStackTrace();
- onFail(DownloadError.ERROR_UNKNOWN_HOST, e.getMessage());
- } catch (IOException e) {
- e.printStackTrace();
- onFail(DownloadError.ERROR_IO_ERROR, e.getMessage());
- } catch (NullPointerException e) {
- // might be thrown by connection.getInputStream()
- e.printStackTrace();
- onFail(DownloadError.ERROR_CONNECTION_ERROR, request.getSource());
- } finally {
- IOUtils.closeQuietly(out);
- AntennapodHttpClient.cleanup();
- }
- }
-
- private void onSuccess() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Download was successful");
- result.setSuccessful();
- }
-
- private void onFail(DownloadError reason, String reasonDetailed) {
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "Download failed");
- }
- result.setFailed(reason, reasonDetailed);
- if (request.isDeleteOnFailure()) {
- cleanup();
- }
- }
-
- private void onCancelled() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Download was cancelled");
- result.setCancelled();
- cleanup();
- }
-
- /**
- * Deletes unfinished downloads.
- */
- private void cleanup() {
- if (request.getDestination() != null) {
- File dest = new File(request.getDestination());
- if (dest.exists()) {
- boolean rc = dest.delete();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Deleted file " + dest.getName() + "; Result: "
- + rc);
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "cleanup() didn't delete file: does not exist.");
- }
- }
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/app/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
deleted file mode 100644
index c191c9521..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ /dev/null
@@ -1,1080 +0,0 @@
-package de.danoeh.antennapod.core.service.playback;
-
-import android.annotation.SuppressLint;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.media.AudioManager;
-import android.media.MediaMetadataRetriever;
-import android.media.MediaPlayer;
-import android.media.RemoteControlClient;
-import android.media.RemoteControlClient.MetadataEditor;
-import android.os.AsyncTask;
-import android.os.Binder;
-import android.os.Build;
-import android.os.IBinder;
-import android.preference.PreferenceManager;
-import android.support.v4.app.NotificationCompat;
-import android.util.Log;
-import android.util.Pair;
-import android.view.KeyEvent;
-import android.view.SurfaceHolder;
-import android.widget.Toast;
-
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.IOException;
-import java.util.List;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.AudioplayerActivity;
-import de.danoeh.antennapod.activity.VideoplayerActivity;
-import de.danoeh.antennapod.core.asynctask.PicassoProvider;
-import de.danoeh.antennapod.core.feed.Chapter;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.feed.MediaType;
-import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
-import de.danoeh.antennapod.core.receiver.PlayerWidget;
-import de.danoeh.antennapod.core.storage.DBTasks;
-import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.util.QueueAccess;
-import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
-import de.danoeh.antennapod.core.util.playback.Playable;
-
-/**
- * Controls the MediaPlayer that plays a FeedMedia-file
- */
-public class PlaybackService extends Service {
- /**
- * Logging tag
- */
- private static final String TAG = "PlaybackService";
-
- /**
- * Parcelable of type Playable.
- */
- public static final String EXTRA_PLAYABLE = "PlaybackService.PlayableExtra";
- /**
- * True if media should be streamed.
- */
- public static final String EXTRA_SHOULD_STREAM = "extra.de.danoeh.antennapod.core.service.shouldStream";
- /**
- * True if playback should be started immediately after media has been
- * prepared.
- */
- public static final String EXTRA_START_WHEN_PREPARED = "extra.de.danoeh.antennapod.core.service.startWhenPrepared";
-
- public static final String EXTRA_PREPARE_IMMEDIATELY = "extra.de.danoeh.antennapod.core.service.prepareImmediately";
-
- public static final String ACTION_PLAYER_STATUS_CHANGED = "action.de.danoeh.antennapod.core.service.playerStatusChanged";
- private static final String AVRCP_ACTION_PLAYER_STATUS_CHANGED = "com.android.music.playstatechanged";
- private static final String AVRCP_ACTION_META_CHANGED = "com.android.music.metachanged";
-
- public static final String ACTION_PLAYER_NOTIFICATION = "action.de.danoeh.antennapod.core.service.playerNotification";
- public static final String EXTRA_NOTIFICATION_CODE = "extra.de.danoeh.antennapod.core.service.notificationCode";
- public static final String EXTRA_NOTIFICATION_TYPE = "extra.de.danoeh.antennapod.core.service.notificationType";
-
- /**
- * If the PlaybackService receives this action, it will stop playback and
- * try to shutdown.
- */
- public static final String ACTION_SHUTDOWN_PLAYBACK_SERVICE = "action.de.danoeh.antennapod.core.service.actionShutdownPlaybackService";
-
- /**
- * If the PlaybackService receives this action, it will end playback of the
- * current episode and load the next episode if there is one available.
- */
- public static final String ACTION_SKIP_CURRENT_EPISODE = "action.de.danoeh.antennapod.core.service.skipCurrentEpisode";
-
- /**
- * Used in NOTIFICATION_TYPE_RELOAD.
- */
- public static final int EXTRA_CODE_AUDIO = 1;
- public static final int EXTRA_CODE_VIDEO = 2;
-
- public static final int NOTIFICATION_TYPE_ERROR = 0;
- public static final int NOTIFICATION_TYPE_INFO = 1;
- public static final int NOTIFICATION_TYPE_BUFFER_UPDATE = 2;
-
- /**
- * Receivers of this intent should update their information about the curently playing media
- */
- public static final int NOTIFICATION_TYPE_RELOAD = 3;
- /**
- * The state of the sleeptimer changed.
- */
- public static final int NOTIFICATION_TYPE_SLEEPTIMER_UPDATE = 4;
- public static final int NOTIFICATION_TYPE_BUFFER_START = 5;
- public static final int NOTIFICATION_TYPE_BUFFER_END = 6;
- /**
- * No more episodes are going to be played.
- */
- public static final int NOTIFICATION_TYPE_PLAYBACK_END = 7;
-
- /**
- * Playback speed has changed
- */
- public static final int NOTIFICATION_TYPE_PLAYBACK_SPEED_CHANGE = 8;
-
- /**
- * Returned by getPositionSafe() or getDurationSafe() if the playbackService
- * is in an invalid state.
- */
- public static final int INVALID_TIME = -1;
-
- /**
- * Is true if service is running.
- */
- public static boolean isRunning = false;
- /**
- * Is true if service has received a valid start command.
- */
- public static boolean started = false;
-
- private static final int NOTIFICATION_ID = 1;
-
- private RemoteControlClient remoteControlClient;
- private PlaybackServiceMediaPlayer mediaPlayer;
- private PlaybackServiceTaskManager taskManager;
-
- private static volatile MediaType currentMediaType = MediaType.UNKNOWN;
-
- private final IBinder mBinder = new LocalBinder();
-
- public class LocalBinder extends Binder {
- public PlaybackService getService() {
- return PlaybackService.this;
- }
- }
-
- @Override
- public boolean onUnbind(Intent intent) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received onUnbind event");
- return super.onUnbind(intent);
- }
-
- /**
- * Returns an intent which starts an audio- or videoplayer, depending on the
- * type of media that is being played. If the playbackservice is not
- * running, the type of the last played media will be looked up.
- */
- public static Intent getPlayerActivityIntent(Context context) {
- if (isRunning) { // TODO getPlayerActivityIntent
- if (currentMediaType == MediaType.VIDEO) {
- return new Intent(context, VideoplayerActivity.class);
- } else {
- return new Intent(context, AudioplayerActivity.class);
- }
- } else {
- if (PlaybackPreferences.getCurrentEpisodeIsVideo()) {
- return new Intent(context, VideoplayerActivity.class);
- } else {
- return new Intent(context, AudioplayerActivity.class);
- }
- }
- }
-
- /**
- * Same as getPlayerActivityIntent(context), but here the type of activity
- * depends on the FeedMedia that is provided as an argument.
- */
- public static Intent getPlayerActivityIntent(Context context, Playable media) {
- MediaType mt = media.getMediaType();
- if (mt == MediaType.VIDEO) {
- return new Intent(context, VideoplayerActivity.class);
- } else {
- return new Intent(context, AudioplayerActivity.class);
- }
- }
-
- @SuppressLint("NewApi")
- @Override
- public void onCreate() {
- super.onCreate();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Service created.");
- isRunning = true;
-
- registerReceiver(headsetDisconnected, new IntentFilter(
- Intent.ACTION_HEADSET_PLUG));
- registerReceiver(shutdownReceiver, new IntentFilter(
- ACTION_SHUTDOWN_PLAYBACK_SERVICE));
- registerReceiver(audioBecomingNoisy, new IntentFilter(
- AudioManager.ACTION_AUDIO_BECOMING_NOISY));
- registerReceiver(skipCurrentEpisodeReceiver, new IntentFilter(
- ACTION_SKIP_CURRENT_EPISODE));
- remoteControlClient = setupRemoteControlClient();
- taskManager = new PlaybackServiceTaskManager(this, taskManagerCallback);
- mediaPlayer = new PlaybackServiceMediaPlayer(this, mediaPlayerCallback);
-
- }
-
- @SuppressLint("NewApi")
- @Override
- public void onDestroy() {
- super.onDestroy();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Service is about to be destroyed");
- isRunning = false;
- started = false;
- currentMediaType = MediaType.UNKNOWN;
-
- unregisterReceiver(headsetDisconnected);
- unregisterReceiver(shutdownReceiver);
- unregisterReceiver(audioBecomingNoisy);
- unregisterReceiver(skipCurrentEpisodeReceiver);
- mediaPlayer.shutdown();
- taskManager.shutdown();
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received onBind event");
- return mBinder;
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- super.onStartCommand(intent, flags, startId);
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "OnStartCommand called");
- final int keycode = intent.getIntExtra(MediaButtonReceiver.EXTRA_KEYCODE, -1);
- final Playable playable = intent.getParcelableExtra(EXTRA_PLAYABLE);
- if (keycode == -1 && playable == null) {
- Log.e(TAG, "PlaybackService was started with no arguments");
- stopSelf();
- }
-
- if ((flags & Service.START_FLAG_REDELIVERY) != 0) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "onStartCommand is a redelivered intent, calling stopForeground now.");
- stopForeground(true);
- } else {
-
- if (keycode != -1) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received media button event");
- handleKeycode(keycode);
- } else {
- started = true;
- boolean stream = intent.getBooleanExtra(EXTRA_SHOULD_STREAM,
- true);
- boolean startWhenPrepared = intent.getBooleanExtra(EXTRA_START_WHEN_PREPARED, false);
- boolean prepareImmediately = intent.getBooleanExtra(EXTRA_PREPARE_IMMEDIATELY, false);
- sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, 0);
- mediaPlayer.playMediaObject(playable, stream, startWhenPrepared, prepareImmediately);
- }
- }
-
- return Service.START_REDELIVER_INTENT;
- }
-
- /**
- * Handles media button events
- */
- private void handleKeycode(int keycode) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Handling keycode: " + keycode);
-
- final PlaybackServiceMediaPlayer.PSMPInfo info = mediaPlayer.getPSMPInfo();
- final PlayerStatus status = info.playerStatus;
- switch (keycode) {
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- if (status == PlayerStatus.PLAYING) {
- mediaPlayer.pause(true, true);
- } else if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) {
- mediaPlayer.resume();
- } else if (status == PlayerStatus.PREPARING) {
- mediaPlayer.setStartWhenPrepared(!mediaPlayer.isStartWhenPrepared());
- } else if (status == PlayerStatus.INITIALIZED) {
- mediaPlayer.setStartWhenPrepared(true);
- mediaPlayer.prepare();
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) {
- mediaPlayer.resume();
- } else if (status == PlayerStatus.INITIALIZED) {
- mediaPlayer.setStartWhenPrepared(true);
- mediaPlayer.prepare();
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_PAUSE:
- if (status == PlayerStatus.PLAYING) {
- mediaPlayer.pause(true, true);
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
- mediaPlayer.seekDelta(UserPreferences.getSeekDeltaMs());
- break;
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_REWIND:
- mediaPlayer.seekDelta(-UserPreferences.getSeekDeltaMs());
- break;
- default:
- if (info.playable != null && info.playerStatus == PlayerStatus.PLAYING) { // only notify the user about an unknown key event if it is actually doing something
- String message = String.format(getResources().getString(R.string.unknown_media_key), keycode);
- Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
- }
- break;
- }
- }
-
- /**
- * Called by a mediaplayer Activity as soon as it has prepared its
- * mediaplayer.
- */
- public void setVideoSurface(SurfaceHolder sh) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Setting display");
- mediaPlayer.setVideoSurface(sh);
- }
-
- /**
- * Called when the surface holder of the mediaplayer has to be changed.
- */
- private void resetVideoSurface() {
- taskManager.cancelPositionSaver();
- mediaPlayer.resetVideoSurface();
- }
-
- public void notifyVideoSurfaceAbandoned() {
- stopForeground(true);
- mediaPlayer.resetVideoSurface();
- }
-
- private final PlaybackServiceTaskManager.PSTMCallback taskManagerCallback = new PlaybackServiceTaskManager.PSTMCallback() {
- @Override
- public void positionSaverTick() {
- saveCurrentPosition(true, PlaybackServiceTaskManager.POSITION_SAVER_WAITING_INTERVAL);
- }
-
- @Override
- public void onSleepTimerExpired() {
- mediaPlayer.pause(true, true);
- sendNotificationBroadcast(NOTIFICATION_TYPE_SLEEPTIMER_UPDATE, 0);
- }
-
-
- @Override
- public void onWidgetUpdaterTick() {
- updateWidget();
- }
-
- @Override
- public void onChapterLoaded(Playable media) {
- sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, 0);
- }
- };
-
- private final PlaybackServiceMediaPlayer.PSMPCallback mediaPlayerCallback = new PlaybackServiceMediaPlayer.PSMPCallback() {
- @Override
- public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
- currentMediaType = mediaPlayer.getCurrentMediaType();
- switch (newInfo.playerStatus) {
- case INITIALIZED:
- writePlaybackPreferences();
- break;
-
- case PREPARED:
- taskManager.startChapterLoader(newInfo.playable);
- break;
-
- case PAUSED:
- taskManager.cancelPositionSaver();
- saveCurrentPosition(false, 0);
- taskManager.cancelWidgetUpdater();
- stopForeground(true);
- break;
-
- case STOPPED:
- //setCurrentlyPlayingMedia(PlaybackPreferences.NO_MEDIA_PLAYING);
- //stopSelf();
- break;
-
- case PLAYING:
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Audiofocus successfully requested");
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Resuming/Starting playback");
-
- taskManager.startPositionSaver();
- taskManager.startWidgetUpdater();
- setupNotification(newInfo);
- break;
- case ERROR:
- writePlaybackPreferencesNoMediaPlaying();
- break;
-
- }
-
- sendBroadcast(new Intent(ACTION_PLAYER_STATUS_CHANGED));
- updateWidget();
- refreshRemoteControlClientState(newInfo);
- bluetoothNotifyChange(newInfo, AVRCP_ACTION_PLAYER_STATUS_CHANGED);
- bluetoothNotifyChange(newInfo, AVRCP_ACTION_META_CHANGED);
- }
-
- @Override
- public void shouldStop() {
- stopSelf();
- }
-
- @Override
- public void playbackSpeedChanged(float s) {
- sendNotificationBroadcast(
- NOTIFICATION_TYPE_PLAYBACK_SPEED_CHANGE, 0);
- }
-
- @Override
- public void onBufferingUpdate(int percent) {
- sendNotificationBroadcast(NOTIFICATION_TYPE_BUFFER_UPDATE, percent);
- }
-
- @Override
- public boolean onMediaPlayerInfo(int code) {
- switch (code) {
- case MediaPlayer.MEDIA_INFO_BUFFERING_START:
- sendNotificationBroadcast(NOTIFICATION_TYPE_BUFFER_START, 0);
- return true;
- case MediaPlayer.MEDIA_INFO_BUFFERING_END:
- sendNotificationBroadcast(NOTIFICATION_TYPE_BUFFER_END, 0);
- return true;
- default:
- return false;
- }
- }
-
- @Override
- public boolean onMediaPlayerError(Object inObj, int what, int extra) {
- final String TAG = "PlaybackService.onErrorListener";
- Log.w(TAG, "An error has occured: " + what + " " + extra);
- if (mediaPlayer.getPSMPInfo().playerStatus == PlayerStatus.PLAYING) {
- mediaPlayer.pause(true, false);
- }
- sendNotificationBroadcast(NOTIFICATION_TYPE_ERROR, what);
- writePlaybackPreferencesNoMediaPlaying();
- stopSelf();
- return true;
- }
-
- @Override
- public boolean endPlayback(boolean playNextEpisode) {
- PlaybackService.this.endPlayback(true);
- return true;
- }
-
- @Override
- public RemoteControlClient getRemoteControlClient() {
- return remoteControlClient;
- }
- };
-
- private void endPlayback(boolean playNextEpisode) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Playback ended");
-
- final Playable media = mediaPlayer.getPSMPInfo().playable;
- if (media == null) {
- Log.e(TAG, "Cannot end playback: media was null");
- return;
- }
-
- taskManager.cancelPositionSaver();
-
- boolean isInQueue = false;
- FeedItem nextItem = null;
-
- if (media instanceof FeedMedia) {
- FeedItem item = ((FeedMedia) media).getItem();
- DBWriter.markItemRead(PlaybackService.this, item, true, true);
-
- try {
- final List<FeedItem> queue = taskManager.getQueue();
- isInQueue = QueueAccess.ItemListAccess(queue).contains(((FeedMedia) media).getItem().getId());
- nextItem = DBTasks.getQueueSuccessorOfItem(this, item.getId(), queue);
- } catch (InterruptedException e) {
- e.printStackTrace();
- // isInQueue remains false
- }
- if (isInQueue) {
- DBWriter.removeQueueItem(PlaybackService.this, item.getId(), true);
- }
- DBWriter.addItemToPlaybackHistory(PlaybackService.this, (FeedMedia) media);
-
- // auto-flattr if enabled
- if (isAutoFlattrable(media) && UserPreferences.getAutoFlattrPlayedDurationThreshold() == 1.0f) {
- DBTasks.flattrItemIfLoggedIn(PlaybackService.this, item);
- }
- }
-
- // Load next episode if previous episode was in the queue and if there
- // is an episode in the queue left.
- // Start playback immediately if continuous playback is enabled
- Playable nextMedia = null;
- boolean loadNextItem = isInQueue && nextItem != null;
- playNextEpisode = playNextEpisode && loadNextItem
- && UserPreferences.isFollowQueue();
- if (loadNextItem) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Loading next item in queue");
- nextMedia = nextItem.getMedia();
- }
- final boolean prepareImmediately;
- final boolean startWhenPrepared;
- final boolean stream;
-
- if (playNextEpisode) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Playback of next episode will start immediately.");
- prepareImmediately = startWhenPrepared = true;
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "No more episodes available to play");
-
- prepareImmediately = startWhenPrepared = false;
- stopForeground(true);
- stopWidgetUpdater();
- }
-
- writePlaybackPreferencesNoMediaPlaying();
- if (nextMedia != null) {
- stream = !media.localFileAvailable();
- mediaPlayer.playMediaObject(nextMedia, stream, startWhenPrepared, prepareImmediately);
- sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD,
- (nextMedia.getMediaType() == MediaType.VIDEO) ? EXTRA_CODE_VIDEO : EXTRA_CODE_AUDIO);
- } else {
- sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0);
- mediaPlayer.stop();
- //stopSelf();
- }
- }
-
- public void setSleepTimer(long waitingTime) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Setting sleep timer to " + Long.toString(waitingTime)
- + " milliseconds");
- taskManager.setSleepTimer(waitingTime);
- sendNotificationBroadcast(NOTIFICATION_TYPE_SLEEPTIMER_UPDATE, 0);
- }
-
- public void disableSleepTimer() {
- taskManager.disableSleepTimer();
- sendNotificationBroadcast(NOTIFICATION_TYPE_SLEEPTIMER_UPDATE, 0);
- }
-
- private void writePlaybackPreferencesNoMediaPlaying() {
- SharedPreferences.Editor editor = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext()).edit();
- editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA,
- PlaybackPreferences.NO_MEDIA_PLAYING);
- editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID,
- PlaybackPreferences.NO_MEDIA_PLAYING);
- editor.putLong(
- PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID,
- PlaybackPreferences.NO_MEDIA_PLAYING);
- editor.commit();
- }
-
-
- private void writePlaybackPreferences() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Writing playback preferences");
-
- SharedPreferences.Editor editor = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext()).edit();
- PlaybackServiceMediaPlayer.PSMPInfo info = mediaPlayer.getPSMPInfo();
- MediaType mediaType = mediaPlayer.getCurrentMediaType();
- boolean stream = mediaPlayer.isStreaming();
-
- if (info.playable != null) {
- editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA,
- info.playable.getPlayableType());
- editor.putBoolean(
- PlaybackPreferences.PREF_CURRENT_EPISODE_IS_STREAM,
- stream);
- editor.putBoolean(
- PlaybackPreferences.PREF_CURRENT_EPISODE_IS_VIDEO,
- mediaType == MediaType.VIDEO);
- if (info.playable instanceof FeedMedia) {
- FeedMedia fMedia = (FeedMedia) info.playable;
- editor.putLong(
- PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID,
- fMedia.getItem().getFeed().getId());
- editor.putLong(
- PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID,
- fMedia.getId());
- } else {
- editor.putLong(
- PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID,
- PlaybackPreferences.NO_MEDIA_PLAYING);
- editor.putLong(
- PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID,
- PlaybackPreferences.NO_MEDIA_PLAYING);
- }
- info.playable.writeToPreferences(editor);
- } else {
- editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA,
- PlaybackPreferences.NO_MEDIA_PLAYING);
- editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID,
- PlaybackPreferences.NO_MEDIA_PLAYING);
- editor.putLong(
- PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID,
- PlaybackPreferences.NO_MEDIA_PLAYING);
- }
-
- editor.commit();
- }
-
- /**
- * Send ACTION_PLAYER_STATUS_CHANGED without changing the status attribute.
- */
- private void postStatusUpdateIntent() {
- sendBroadcast(new Intent(ACTION_PLAYER_STATUS_CHANGED));
- }
-
- private void sendNotificationBroadcast(int type, int code) {
- Intent intent = new Intent(ACTION_PLAYER_NOTIFICATION);
- intent.putExtra(EXTRA_NOTIFICATION_TYPE, type);
- intent.putExtra(EXTRA_NOTIFICATION_CODE, code);
- sendBroadcast(intent);
- }
-
- /**
- * Used by setupNotification to load notification data in another thread.
- */
- private AsyncTask<Void, Void, Void> notificationSetupTask;
-
- /**
- * Prepares notification and starts the service in the foreground.
- */
- @SuppressLint("NewApi")
- private void setupNotification(final PlaybackServiceMediaPlayer.PSMPInfo info) {
- final PendingIntent pIntent = PendingIntent.getActivity(this, 0,
- PlaybackService.getPlayerActivityIntent(this),
- PendingIntent.FLAG_UPDATE_CURRENT);
-
- if (notificationSetupTask != null) {
- notificationSetupTask.cancel(true);
- }
- notificationSetupTask = new AsyncTask<Void, Void, Void>() {
- Bitmap icon = null;
-
- @Override
- protected Void doInBackground(Void... params) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Starting background work");
- if (android.os.Build.VERSION.SDK_INT >= 11) {
- if (info.playable != null) {
- try {
- int iconSize = getResources().getDimensionPixelSize(
- android.R.dimen.notification_large_icon_width);
- icon = PicassoProvider.getMediaMetadataPicassoInstance(PlaybackService.this)
- .load(info.playable.getImageUri())
- .resize(iconSize, iconSize)
- .get();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- }
- if (icon == null) {
- icon = BitmapFactory.decodeResource(getResources(),
- R.drawable.ic_stat_antenna);
- }
-
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- super.onPostExecute(result);
- if (!isCancelled() && info.playerStatus == PlayerStatus.PLAYING
- && info.playable != null) {
- String contentText = info.playable.getFeedTitle();
- String contentTitle = info.playable.getEpisodeTitle();
- Notification notification = null;
- if (android.os.Build.VERSION.SDK_INT >= 16) {
- Intent pauseButtonIntent = new Intent(
- PlaybackService.this, PlaybackService.class);
- pauseButtonIntent.putExtra(
- MediaButtonReceiver.EXTRA_KEYCODE,
- KeyEvent.KEYCODE_MEDIA_PAUSE);
- PendingIntent pauseButtonPendingIntent = PendingIntent
- .getService(PlaybackService.this, 0,
- pauseButtonIntent,
- PendingIntent.FLAG_UPDATE_CURRENT);
- Notification.Builder notificationBuilder = new Notification.Builder(
- PlaybackService.this)
- .setContentTitle(contentTitle)
- .setContentText(contentText)
- .setOngoing(true)
- .setContentIntent(pIntent)
- .setLargeIcon(icon)
- .setSmallIcon(R.drawable.ic_stat_antenna)
- .addAction(android.R.drawable.ic_media_pause,
- getString(R.string.pause_label),
- pauseButtonPendingIntent);
- notification = notificationBuilder.build();
- } else {
- NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(
- PlaybackService.this)
- .setContentTitle(contentTitle)
- .setContentText(contentText).setOngoing(true)
- .setContentIntent(pIntent).setLargeIcon(icon)
- .setSmallIcon(R.drawable.ic_stat_antenna);
- notification = notificationBuilder.getNotification();
- }
- startForeground(NOTIFICATION_ID, notification);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Notification set up");
- }
- }
-
- };
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- notificationSetupTask
- .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- notificationSetupTask.execute();
- }
-
- }
-
- /**
- * Saves the current position of the media file to the DB
- *
- * @param updatePlayedDuration true if played_duration should be updated. This applies only to FeedMedia objects
- * @param deltaPlayedDuration value by which played_duration should be increased.
- */
- private synchronized void saveCurrentPosition(boolean updatePlayedDuration, int deltaPlayedDuration) {
- int position = getCurrentPosition();
- int duration = getDuration();
- float playbackSpeed = getCurrentPlaybackSpeed();
- final Playable playable = mediaPlayer.getPSMPInfo().playable;
- if (position != INVALID_TIME && duration != INVALID_TIME && playable != null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Saving current position to " + position);
- if (updatePlayedDuration && playable instanceof FeedMedia) {
- FeedMedia m = (FeedMedia) playable;
- FeedItem item = m.getItem();
- m.setPlayedDuration(m.getPlayedDuration() + ((int) (deltaPlayedDuration * playbackSpeed)));
- // Auto flattr
- if (isAutoFlattrable(m) &&
- (m.getPlayedDuration() > UserPreferences.getAutoFlattrPlayedDurationThreshold() * duration)) {
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "saveCurrentPosition: performing auto flattr since played duration " + Integer.toString(m.getPlayedDuration())
- + " is " + UserPreferences.getAutoFlattrPlayedDurationThreshold() * 100 + "% of file duration " + Integer.toString(duration));
- DBTasks.flattrItemIfLoggedIn(this, item);
- }
- }
- playable.saveCurrentPosition(PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext()),
- position
- );
- }
- }
-
- private void stopWidgetUpdater() {
- taskManager.cancelWidgetUpdater();
- sendBroadcast(new Intent(PlayerWidget.STOP_WIDGET_UPDATE));
- }
-
- private void updateWidget() {
- PlaybackService.this.sendBroadcast(new Intent(
- PlayerWidget.FORCE_WIDGET_UPDATE));
- }
-
- public boolean sleepTimerActive() {
- return taskManager.isSleepTimerActive();
- }
-
- public long getSleepTimerTimeLeft() {
- return taskManager.getSleepTimerTimeLeft();
- }
-
- @SuppressLint("NewApi")
- private RemoteControlClient setupRemoteControlClient() {
- if (Build.VERSION.SDK_INT < 14) {
- return null;
- }
-
- Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
- mediaButtonIntent.setComponent(new ComponentName(getPackageName(),
- MediaButtonReceiver.class.getName()));
- PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(
- getApplicationContext(), 0, mediaButtonIntent, 0);
- remoteControlClient = new RemoteControlClient(mediaPendingIntent);
- int controlFlags;
- if (android.os.Build.VERSION.SDK_INT < 16) {
- controlFlags = RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE
- | RemoteControlClient.FLAG_KEY_MEDIA_NEXT;
- } else {
- controlFlags = RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE;
- }
- remoteControlClient.setTransportControlFlags(controlFlags);
- return remoteControlClient;
- }
-
- /**
- * Refresh player status and metadata.
- */
- @SuppressLint("NewApi")
- private void refreshRemoteControlClientState(PlaybackServiceMediaPlayer.PSMPInfo info) {
- if (android.os.Build.VERSION.SDK_INT >= 14) {
- if (remoteControlClient != null) {
- switch (info.playerStatus) {
- case PLAYING:
- remoteControlClient
- .setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
- break;
- case PAUSED:
- case INITIALIZED:
- remoteControlClient
- .setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED);
- break;
- case STOPPED:
- remoteControlClient
- .setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED);
- break;
- case ERROR:
- remoteControlClient
- .setPlaybackState(RemoteControlClient.PLAYSTATE_ERROR);
- break;
- default:
- remoteControlClient
- .setPlaybackState(RemoteControlClient.PLAYSTATE_BUFFERING);
- }
- if (info.playable != null) {
- MetadataEditor editor = remoteControlClient
- .editMetadata(false);
- editor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE,
- info.playable.getEpisodeTitle());
-
- editor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM,
- info.playable.getFeedTitle());
-
- editor.apply();
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, "RemoteControlClient state was refreshed");
- }
- }
- }
-
- private void bluetoothNotifyChange(PlaybackServiceMediaPlayer.PSMPInfo info, String whatChanged) {
- boolean isPlaying = false;
-
- if (info.playerStatus == PlayerStatus.PLAYING) {
- isPlaying = true;
- }
-
- if (info.playable != null) {
- Intent i = new Intent(whatChanged);
- i.putExtra("id", 1);
- i.putExtra("artist", "");
- i.putExtra("album", info.playable.getFeedTitle());
- i.putExtra("track", info.playable.getEpisodeTitle());
- i.putExtra("playing", isPlaying);
- final List<FeedItem> queue = taskManager.getQueueIfLoaded();
- if (queue != null) {
- i.putExtra("ListSize", queue.size());
- }
- i.putExtra("duration", info.playable.getDuration());
- i.putExtra("position", info.playable.getPosition());
- sendBroadcast(i);
- }
- }
-
- /**
- * Pauses playback when the headset is disconnected and the preference is
- * set
- */
- private BroadcastReceiver headsetDisconnected = new BroadcastReceiver() {
- private static final String TAG = "headsetDisconnected";
- private static final int UNPLUGGED = 0;
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), Intent.ACTION_HEADSET_PLUG)) {
- int state = intent.getIntExtra("state", -1);
- if (state != -1) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Headset plug event. State is " + state);
- if (state == UNPLUGGED) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Headset was unplugged during playback.");
- pauseIfPauseOnDisconnect();
- }
- } else {
- Log.e(TAG, "Received invalid ACTION_HEADSET_PLUG intent");
- }
- }
- }
- };
-
- private BroadcastReceiver audioBecomingNoisy = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- // sound is about to change, eg. bluetooth -> speaker
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Pausing playback because audio is becoming noisy");
- pauseIfPauseOnDisconnect();
- }
- // android.media.AUDIO_BECOMING_NOISY
- };
-
- /**
- * Pauses playback if PREF_PAUSE_ON_HEADSET_DISCONNECT was set to true.
- */
- private void pauseIfPauseOnDisconnect() {
- if (UserPreferences.isPauseOnHeadsetDisconnect()) {
- mediaPlayer.pause(true, true);
- }
- }
-
- private BroadcastReceiver shutdownReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), ACTION_SHUTDOWN_PLAYBACK_SERVICE)) {
- stopSelf();
- }
- }
-
- };
-
- private BroadcastReceiver skipCurrentEpisodeReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), ACTION_SKIP_CURRENT_EPISODE)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received SKIP_CURRENT_EPISODE intent");
- mediaPlayer.endPlayback();
- }
- }
- };
-
- public static MediaType getCurrentMediaType() {
- return currentMediaType;
- }
-
- public void resume() {
- mediaPlayer.resume();
- }
-
- public void prepare() {
- mediaPlayer.prepare();
- }
-
- public void pause(boolean abandonAudioFocus, boolean reinit) {
- mediaPlayer.pause(abandonAudioFocus, reinit);
- }
-
- public void reinit() {
- mediaPlayer.reinit();
- }
-
- public PlaybackServiceMediaPlayer.PSMPInfo getPSMPInfo() {
- return mediaPlayer.getPSMPInfo();
- }
-
- public PlayerStatus getStatus() {
- return mediaPlayer.getPSMPInfo().playerStatus;
- }
-
- public Playable getPlayable() {
- return mediaPlayer.getPSMPInfo().playable;
- }
-
- public void setSpeed(float speed) {
- mediaPlayer.setSpeed(speed);
- }
-
- public boolean canSetSpeed() {
- return mediaPlayer.canSetSpeed();
- }
-
- public float getCurrentPlaybackSpeed() {
- return mediaPlayer.getPlaybackSpeed();
- }
-
- public boolean isStartWhenPrepared() {
- return mediaPlayer.isStartWhenPrepared();
- }
-
- public void setStartWhenPrepared(boolean s) {
- mediaPlayer.setStartWhenPrepared(s);
- }
-
-
- public void seekTo(final int t) {
- mediaPlayer.seekTo(t);
- }
-
-
- public void seekDelta(final int d) {
- mediaPlayer.seekDelta(d);
- }
-
- /**
- * @see de.danoeh.antennapod.core.service.playback.PlaybackServiceMediaPlayer#seekToChapter(de.danoeh.antennapod.core.feed.Chapter)
- */
- public void seekToChapter(Chapter c) {
- mediaPlayer.seekToChapter(c);
- }
-
- /**
- * call getDuration() on mediaplayer or return INVALID_TIME if player is in
- * an invalid state.
- */
- public int getDuration() {
- return mediaPlayer.getDuration();
- }
-
- /**
- * call getCurrentPosition() on mediaplayer or return INVALID_TIME if player
- * is in an invalid state.
- */
- public int getCurrentPosition() {
- return mediaPlayer.getPosition();
- }
-
- public boolean isStreaming() {
- return mediaPlayer.isStreaming();
- }
-
- public Pair<Integer, Integer> getVideoSize() {
- return mediaPlayer.getVideoSize();
- }
-
- private boolean isAutoFlattrable(Playable p) {
- if (p != null && p instanceof FeedMedia) {
- FeedMedia media = (FeedMedia) p;
- FeedItem item = ((FeedMedia) p).getItem();
- return item != null && FlattrUtils.hasToken() && UserPreferences.isAutoFlattr() && item.getPaymentLink() != null && item.getFlattrStatus().getUnflattred();
- } else {
- return false;
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/app/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
deleted file mode 100644
index 62ad59166..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
+++ /dev/null
@@ -1,979 +0,0 @@
-package de.danoeh.antennapod.core.service.playback;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.media.AudioManager;
-import android.media.RemoteControlClient;
-import android.net.wifi.WifiManager;
-import android.os.PowerManager;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.util.Pair;
-import android.view.SurfaceHolder;
-
-import org.apache.commons.lang3.Validate;
-
-import java.io.IOException;
-import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.RejectedExecutionHandler;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.locks.ReentrantLock;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.feed.Chapter;
-import de.danoeh.antennapod.core.feed.MediaType;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
-import de.danoeh.antennapod.core.util.playback.AudioPlayer;
-import de.danoeh.antennapod.core.util.playback.IPlayer;
-import de.danoeh.antennapod.core.util.playback.Playable;
-import de.danoeh.antennapod.core.util.playback.VideoPlayer;
-
-/**
- * Manages the MediaPlayer object of the PlaybackService.
- */
-public class PlaybackServiceMediaPlayer {
- public static final String TAG = "PlaybackServiceMediaPlayer";
-
- /**
- * Return value of some PSMP methods if the method call failed.
- */
- public static final int INVALID_TIME = -1;
-
- private final AudioManager audioManager;
-
- private volatile PlayerStatus playerStatus;
- private volatile PlayerStatus statusBeforeSeeking;
- private volatile IPlayer mediaPlayer;
- private volatile Playable media;
-
- private volatile boolean stream;
- private volatile MediaType mediaType;
- private volatile AtomicBoolean startWhenPrepared;
- private volatile boolean pausedBecauseOfTransientAudiofocusLoss;
- private volatile Pair<Integer, Integer> videoSize;
-
- /**
- * Some asynchronous calls might change the state of the MediaPlayer object. Therefore calls in other threads
- * have to wait until these operations have finished.
- */
- private final ReentrantLock playerLock;
-
- private final PSMPCallback callback;
- private final Context context;
-
- private final ThreadPoolExecutor executor;
-
- /**
- * A wifi-lock that is acquired if the media file is being streamed.
- */
- private WifiManager.WifiLock wifiLock;
-
- public PlaybackServiceMediaPlayer(Context context, PSMPCallback callback) {
- Validate.notNull(context);
- Validate.notNull(callback);
-
- this.context = context;
- this.callback = callback;
- this.audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- this.playerLock = new ReentrantLock();
- this.startWhenPrepared = new AtomicBoolean(false);
- executor = new ThreadPoolExecutor(1, 1, 5, TimeUnit.MINUTES, new LinkedBlockingDeque<Runnable>(),
- new RejectedExecutionHandler() {
- @Override
- public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Rejected execution of runnable");
- }
- }
- );
-
- mediaPlayer = null;
- statusBeforeSeeking = null;
- pausedBecauseOfTransientAudiofocusLoss = false;
- mediaType = MediaType.UNKNOWN;
- playerStatus = PlayerStatus.STOPPED;
- videoSize = null;
- }
-
- /**
- * Starts or prepares playback of the specified Playable object. If another Playable object is already being played, the currently playing
- * episode will be stopped and replaced with the new Playable object. If the Playable object is already being played, the method will
- * not do anything.
- * Whether playback starts immediately depends on the given parameters. See below for more details.
- * <p/>
- * States:
- * During execution of the method, the object will be in the INITIALIZING state. The end state depends on the given parameters.
- * <p/>
- * If 'prepareImmediately' is set to true, the method will go into PREPARING state and after that into PREPARED state. If
- * 'startWhenPrepared' is set to true, the method will additionally go into PLAYING state.
- * <p/>
- * If an unexpected error occurs while loading the Playable's metadata or while setting the MediaPlayers data source, the object
- * will enter the ERROR state.
- * <p/>
- * This method is executed on an internal executor service.
- *
- * @param playable The Playable object that is supposed to be played. This parameter must not be null.
- * @param stream The type of playback. If false, the Playable object MUST provide access to a locally available file via
- * getLocalMediaUrl. If true, the Playable object MUST provide access to a resource that can be streamed by
- * the Android MediaPlayer via getStreamUrl.
- * @param startWhenPrepared Sets the 'startWhenPrepared' flag. This flag determines whether playback will start immediately after the
- * episode has been prepared for playback. Setting this flag to true does NOT mean that the episode will be prepared
- * for playback immediately (see 'prepareImmediately' parameter for more details)
- * @param prepareImmediately Set to true if the method should also prepare the episode for playback.
- */
- public void playMediaObject(final Playable playable, final boolean stream, final boolean startWhenPrepared, final boolean prepareImmediately) {
- Validate.notNull(playable);
-
- if (BuildConfig.DEBUG) Log.d(TAG, "Play media object.");
- executor.submit(new Runnable() {
- @Override
- public void run() {
- playerLock.lock();
- try {
- playMediaObject(playable, false, stream, startWhenPrepared, prepareImmediately);
- } catch (RuntimeException e) {
- e.printStackTrace();
- throw e;
- } finally {
- playerLock.unlock();
- }
- }
- });
- }
-
- /**
- * Internal implementation of playMediaObject. This method has an additional parameter that allows the caller to force a media player reset even if
- * the given playable parameter is the same object as the currently playing media.
- * <p/>
- * This method requires the playerLock and is executed on the caller's thread.
- *
- * @see #playMediaObject(de.danoeh.antennapod.core.util.playback.Playable, boolean, boolean, boolean)
- */
- private void playMediaObject(final Playable playable, final boolean forceReset, final boolean stream, final boolean startWhenPrepared, final boolean prepareImmediately) {
- Validate.notNull(playable);
- if (!playerLock.isHeldByCurrentThread())
- throw new IllegalStateException("method requires playerLock");
-
-
- if (media != null) {
- if (!forceReset && media.getIdentifier().equals(playable.getIdentifier())) {
- // episode is already playing -> ignore method call
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Method call to playMediaObject was ignored: media file already playing.");
- return;
- } else {
- // stop playback of this episode
- if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PLAYING || playerStatus == PlayerStatus.PREPARED) {
- mediaPlayer.stop();
- }
- setPlayerStatus(PlayerStatus.INDETERMINATE, null);
- }
- }
-
- this.media = playable;
- this.stream = stream;
- this.mediaType = media.getMediaType();
- this.videoSize = null;
- createMediaPlayer();
- PlaybackServiceMediaPlayer.this.startWhenPrepared.set(startWhenPrepared);
- setPlayerStatus(PlayerStatus.INITIALIZING, media);
- try {
- media.loadMetadata();
- if (stream) {
- mediaPlayer.setDataSource(media.getStreamUrl());
- } else {
- mediaPlayer.setDataSource(media.getLocalMediaUrl());
- }
- setPlayerStatus(PlayerStatus.INITIALIZED, media);
-
- if (mediaType == MediaType.VIDEO) {
- VideoPlayer vp = (VideoPlayer) mediaPlayer;
- // vp.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT);
- }
-
- if (prepareImmediately) {
- setPlayerStatus(PlayerStatus.PREPARING, media);
- mediaPlayer.prepare();
- onPrepared(startWhenPrepared);
- }
-
- } catch (Playable.PlayableException e) {
- e.printStackTrace();
- setPlayerStatus(PlayerStatus.ERROR, null);
- } catch (IOException e) {
- e.printStackTrace();
- setPlayerStatus(PlayerStatus.ERROR, null);
- } catch (IllegalStateException e) {
- e.printStackTrace();
- setPlayerStatus(PlayerStatus.ERROR, null);
- }
- }
-
-
- /**
- * Resumes playback if the PSMP object is in PREPARED or PAUSED state. If the PSMP object is in an invalid state.
- * nothing will happen.
- * <p/>
- * This method is executed on an internal executor service.
- */
- public void resume() {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- playerLock.lock();
- resumeSync();
- playerLock.unlock();
- }
- });
- }
-
- private void resumeSync() {
- if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) {
- int focusGained = audioManager.requestAudioFocus(
- audioFocusChangeListener, AudioManager.STREAM_MUSIC,
- AudioManager.AUDIOFOCUS_GAIN);
- if (focusGained == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
- acquireWifiLockIfNecessary();
- setSpeed(Float.parseFloat(UserPreferences.getPlaybackSpeed()));
- mediaPlayer.start();
- if (playerStatus == PlayerStatus.PREPARED && media.getPosition() > 0) {
- mediaPlayer.seekTo(media.getPosition());
- }
-
- setPlayerStatus(PlayerStatus.PLAYING, media);
- pausedBecauseOfTransientAudiofocusLoss = false;
- if (android.os.Build.VERSION.SDK_INT >= 14) {
- RemoteControlClient remoteControlClient = callback.getRemoteControlClient();
- if (remoteControlClient != null) {
- audioManager
- .registerRemoteControlClient(remoteControlClient);
- }
- }
- audioManager
- .registerMediaButtonEventReceiver(new ComponentName(context.getPackageName(),
- MediaButtonReceiver.class.getName()));
- media.onPlaybackStart();
-
- } else {
- if (BuildConfig.DEBUG) Log.e(TAG, "Failed to request audio focus");
- }
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Call to resume() was ignored because current state of PSMP object is " + playerStatus);
- }
- }
-
-
- /**
- * Saves the current position and pauses playback. Note that, if audiofocus
- * is abandoned, the lockscreen controls will also disapear.
- * <p/>
- * This method is executed on an internal executor service.
- *
- * @param abandonFocus is true if the service should release audio focus
- * @param reinit is true if service should reinit after pausing if the media
- * file is being streamed
- */
- public void pause(final boolean abandonFocus, final boolean reinit) {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- playerLock.lock();
- releaseWifiLockIfNecessary();
- if (playerStatus == PlayerStatus.PLAYING) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Pausing playback.");
- mediaPlayer.pause();
- setPlayerStatus(PlayerStatus.PAUSED, media);
-
- if (abandonFocus) {
- audioManager.abandonAudioFocus(audioFocusChangeListener);
- pausedBecauseOfTransientAudiofocusLoss = false;
- }
- if (stream && reinit) {
- reinit();
- }
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Ignoring call to pause: Player is in " + playerStatus + " state");
- }
-
- playerLock.unlock();
- }
- });
- }
-
- /**
- * Prepared media player for playback if the service is in the INITALIZED
- * state.
- * <p/>
- * This method is executed on an internal executor service.
- */
- public void prepare() {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- playerLock.lock();
-
- if (playerStatus == PlayerStatus.INITIALIZED) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Preparing media player");
- setPlayerStatus(PlayerStatus.PREPARING, media);
- try {
- mediaPlayer.prepare();
- onPrepared(startWhenPrepared.get());
- } catch (IOException e) {
- e.printStackTrace();
- setPlayerStatus(PlayerStatus.ERROR, null);
- }
- }
- playerLock.unlock();
-
- }
- });
- }
-
- /**
- * Called after media player has been prepared. This method is executed on the caller's thread.
- */
- void onPrepared(final boolean startWhenPrepared) {
- playerLock.lock();
-
- if (playerStatus != PlayerStatus.PREPARING) {
- playerLock.unlock();
- throw new IllegalStateException("Player is not in PREPARING state");
- }
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Resource prepared");
-
- if (mediaType == MediaType.VIDEO) {
- VideoPlayer vp = (VideoPlayer) mediaPlayer;
- videoSize = new Pair<Integer, Integer>(vp.getVideoWidth(), vp.getVideoHeight());
- }
-
- if (media.getPosition() > 0) {
- mediaPlayer.seekTo(media.getPosition());
- }
-
- if (media.getDuration() == 0) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Setting duration of media");
- media.setDuration(mediaPlayer.getDuration());
- }
- setPlayerStatus(PlayerStatus.PREPARED, media);
-
- if (startWhenPrepared) {
- resumeSync();
- }
-
- playerLock.unlock();
- }
-
- /**
- * Resets the media player and moves it into INITIALIZED state.
- * <p/>
- * This method is executed on an internal executor service.
- */
- public void reinit() {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- playerLock.lock();
- releaseWifiLockIfNecessary();
- if (media != null) {
- playMediaObject(media, true, stream, startWhenPrepared.get(), false);
- } else if (mediaPlayer != null) {
- mediaPlayer.reset();
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Call to reinit was ignored: media and mediaPlayer were null");
- }
- playerLock.unlock();
- }
- });
- }
-
-
- /**
- * Seeks to the specified position. If the PSMP object is in an invalid state, this method will do nothing.
- *
- * @param t The position to seek to in milliseconds. t < 0 will be interpreted as t = 0
- * <p/>
- * This method is executed on the caller's thread.
- */
- private void seekToSync(int t) {
- if (t < 0) {
- t = 0;
- }
- playerLock.lock();
-
- if (playerStatus == PlayerStatus.PLAYING
- || playerStatus == PlayerStatus.PAUSED
- || playerStatus == PlayerStatus.PREPARED) {
- if (stream) {
- // statusBeforeSeeking = playerStatus;
- // setPlayerStatus(PlayerStatus.SEEKING, media);
- }
- mediaPlayer.seekTo(t);
-
- } else if (playerStatus == PlayerStatus.INITIALIZED) {
- media.setPosition(t);
- startWhenPrepared.set(true);
- prepare();
- }
- playerLock.unlock();
- }
-
- /**
- * Seeks to the specified position. If the PSMP object is in an invalid state, this method will do nothing.
- * Invalid time values (< 0) will be ignored.
- * <p/>
- * This method is executed on an internal executor service.
- */
- public void seekTo(final int t) {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- seekToSync(t);
- }
- });
- }
-
- /**
- * Seek a specific position from the current position
- *
- * @param d offset from current position (positive or negative)
- */
- public void seekDelta(final int d) {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- playerLock.lock();
- int currentPosition = getPosition();
- if (currentPosition != INVALID_TIME) {
- seekToSync(currentPosition + d);
- } else {
- Log.e(TAG, "getPosition() returned INVALID_TIME in seekDelta");
- }
-
- playerLock.unlock();
- }
- });
- }
-
- /**
- * Seek to the start of the specified chapter.
- */
- public void seekToChapter(Chapter c) {
- Validate.notNull(c);
-
- seekTo((int) c.getStart());
- }
-
- /**
- * Returns the duration of the current media object or INVALID_TIME if the duration could not be retrieved.
- */
- public int getDuration() {
- if (!playerLock.tryLock()) {
- return INVALID_TIME;
- }
-
- int retVal = INVALID_TIME;
- if (playerStatus == PlayerStatus.PLAYING
- || playerStatus == PlayerStatus.PAUSED
- || playerStatus == PlayerStatus.PREPARED) {
- retVal = mediaPlayer.getDuration();
- } else if (media != null && media.getDuration() > 0) {
- retVal = media.getDuration();
- }
-
- playerLock.unlock();
- return retVal;
- }
-
- /**
- * Returns the position of the current media object or INVALID_TIME if the position could not be retrieved.
- */
- public int getPosition() {
- if (!playerLock.tryLock()) {
- return INVALID_TIME;
- }
-
- int retVal = INVALID_TIME;
- if (playerStatus == PlayerStatus.PLAYING
- || playerStatus == PlayerStatus.PAUSED
- || playerStatus == PlayerStatus.PREPARED) {
- retVal = mediaPlayer.getCurrentPosition();
- } else if (media != null && media.getPosition() > 0) {
- retVal = media.getPosition();
- }
-
- playerLock.unlock();
- return retVal;
- }
-
- public boolean isStartWhenPrepared() {
- return startWhenPrepared.get();
- }
-
- public void setStartWhenPrepared(boolean startWhenPrepared) {
- this.startWhenPrepared.set(startWhenPrepared);
- }
-
- /**
- * Returns true if the playback speed can be adjusted.
- */
- public boolean canSetSpeed() {
- boolean retVal = false;
- if (mediaPlayer != null && media != null && media.getMediaType() == MediaType.AUDIO) {
- retVal = (mediaPlayer).canSetSpeed();
- }
- return retVal;
- }
-
- /**
- * Sets the playback speed.
- * This method is executed on the caller's thread.
- */
- private void setSpeedSync(float speed) {
- playerLock.lock();
- if (media != null && media.getMediaType() == MediaType.AUDIO) {
- if (mediaPlayer.canSetSpeed()) {
- mediaPlayer.setPlaybackSpeed((float) speed);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Playback speed was set to " + speed);
- callback.playbackSpeedChanged(speed);
- }
- }
- playerLock.unlock();
- }
-
- /**
- * Sets the playback speed.
- * This method is executed on an internal executor service.
- */
- public void setSpeed(final float speed) {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- setSpeedSync(speed);
- }
- });
- }
-
- /**
- * Returns the current playback speed. If the playback speed could not be retrieved, 1 is returned.
- */
- public float getPlaybackSpeed() {
- if (!playerLock.tryLock()) {
- return 1;
- }
-
- float retVal = 1;
- if ((playerStatus == PlayerStatus.PLAYING
- || playerStatus == PlayerStatus.PAUSED
- || playerStatus == PlayerStatus.PREPARED) && mediaPlayer.canSetSpeed()) {
- retVal = mediaPlayer.getCurrentSpeedMultiplier();
- }
- playerLock.unlock();
- return retVal;
- }
-
- public MediaType getCurrentMediaType() {
- return mediaType;
- }
-
- public boolean isStreaming() {
- return stream;
- }
-
-
- /**
- * Releases internally used resources. This method should only be called when the object is not used anymore.
- */
- public void shutdown() {
- executor.shutdown();
- if (mediaPlayer != null) {
- mediaPlayer.release();
- }
- releaseWifiLockIfNecessary();
- }
-
- public void setVideoSurface(final SurfaceHolder surface) {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- playerLock.lock();
- if (mediaPlayer != null) {
- mediaPlayer.setDisplay(surface);
- }
- playerLock.unlock();
- }
- });
- }
-
- public void resetVideoSurface() {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- playerLock.lock();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Resetting video surface");
- mediaPlayer.setDisplay(null);
- reinit();
- playerLock.unlock();
- }
- });
- }
-
- /**
- * Return width and height of the currently playing video as a pair.
- *
- * @return Width and height as a Pair or null if the video size could not be determined. The method might still
- * return an invalid non-null value if the getVideoWidth() and getVideoHeight() methods of the media player return
- * invalid values.
- */
- public Pair<Integer, Integer> getVideoSize() {
- if (!playerLock.tryLock()) {
- // use cached value if lock can't be aquired
- return videoSize;
- }
- Pair<Integer, Integer> res;
- if (mediaPlayer == null || playerStatus == PlayerStatus.ERROR || mediaType != MediaType.VIDEO) {
- res = null;
- } else {
- VideoPlayer vp = (VideoPlayer) mediaPlayer;
- videoSize = new Pair<Integer, Integer>(vp.getVideoWidth(), vp.getVideoHeight());
- res = videoSize;
- }
- playerLock.unlock();
- return res;
- }
-
- /**
- * Returns a PSMInfo object that contains information about the current state of the PSMP object.
- *
- * @return The PSMPInfo object.
- */
- public synchronized PSMPInfo getPSMPInfo() {
- return new PSMPInfo(playerStatus, media);
- }
-
- /**
- * Sets the player status of the PSMP object. PlayerStatus and media attributes have to be set at the same time
- * so that getPSMPInfo can't return an invalid state (e.g. status is PLAYING, but media is null).
- * <p/>
- * This method will notify the callback about the change of the player status (even if the new status is the same
- * as the old one).
- *
- * @param newStatus The new PlayerStatus. This must not be null.
- * @param newMedia The new playable object of the PSMP object. This can be null.
- */
- private synchronized void setPlayerStatus(PlayerStatus newStatus, Playable newMedia) {
- Validate.notNull(newStatus);
-
- if (BuildConfig.DEBUG) Log.d(TAG, "Setting player status to " + newStatus);
-
- this.playerStatus = newStatus;
- this.media = newMedia;
- callback.statusChanged(new PSMPInfo(playerStatus, media));
- }
-
- private IPlayer createMediaPlayer() {
- if (mediaPlayer != null) {
- mediaPlayer.release();
- }
- if (media == null || media.getMediaType() == MediaType.VIDEO) {
- mediaPlayer = new VideoPlayer();
- } else {
- mediaPlayer = new AudioPlayer(context);
- }
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- mediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK);
- return setMediaPlayerListeners(mediaPlayer);
- }
-
- private final AudioManager.OnAudioFocusChangeListener audioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {
-
- @Override
- public void onAudioFocusChange(final int focusChange) {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- playerLock.lock();
-
- // If there is an incoming call, playback should be paused permanently
- TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- final int callState = (tm != null) ? tm.getCallState() : 0;
- if (BuildConfig.DEBUG) Log.d(TAG, "Call state: " + callState);
- Log.i(TAG, "Call state:" + callState);
-
- if (focusChange == AudioManager.AUDIOFOCUS_LOSS || callState != TelephonyManager.CALL_STATE_IDLE) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Lost audio focus");
- pause(true, false);
- callback.shouldStop();
- } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Gained audio focus");
- if (pausedBecauseOfTransientAudiofocusLoss) { // we paused => play now
- resume();
- } else { // we ducked => raise audio level back
- audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
- AudioManager.ADJUST_RAISE, 0);
- }
- } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
- if (playerStatus == PlayerStatus.PLAYING) {
- if (!UserPreferences.shouldPauseForFocusLoss()) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Lost audio focus temporarily. Ducking...");
- audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
- AudioManager.ADJUST_LOWER, 0);
- pausedBecauseOfTransientAudiofocusLoss = false;
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Lost audio focus temporarily. Could duck, but won't, pausing...");
- pause(false, false);
- pausedBecauseOfTransientAudiofocusLoss = true;
- }
- }
- } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
- if (playerStatus == PlayerStatus.PLAYING) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Lost audio focus temporarily. Pausing...");
- pause(false, false);
- pausedBecauseOfTransientAudiofocusLoss = true;
- }
- playerLock.unlock();
- }
- }
- });
- }
- };
-
-
- public void endPlayback() {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- playerLock.lock();
- releaseWifiLockIfNecessary();
-
- if (playerStatus != PlayerStatus.INDETERMINATE) {
- setPlayerStatus(PlayerStatus.INDETERMINATE, media);
- }
- if (mediaPlayer != null) {
- mediaPlayer.reset();
-
- }
- audioManager.abandonAudioFocus(audioFocusChangeListener);
- callback.endPlayback(true);
-
- playerLock.unlock();
- }
- });
- }
-
- /**
- * Moves the PlaybackServiceMediaPlayer into STOPPED state. This call is only valid if the player is currently in
- * INDETERMINATE state, for example after a call to endPlayback.
- * This method will only take care of changing the PlayerStatus of this object! Other tasks like
- * abandoning audio focus have to be done with other methods.
- */
- public void stop() {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- playerLock.lock();
- releaseWifiLockIfNecessary();
-
- if (playerStatus == PlayerStatus.INDETERMINATE) {
- setPlayerStatus(PlayerStatus.STOPPED, null);
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Ignored call to stop: Current player state is: " + playerStatus);
- }
- playerLock.unlock();
-
- }
- });
- }
-
- private synchronized void acquireWifiLockIfNecessary() {
- if (stream) {
- if (wifiLock == null) {
- wifiLock = ((WifiManager) context.getSystemService(Context.WIFI_SERVICE))
- .createWifiLock(WifiManager.WIFI_MODE_FULL, TAG);
- wifiLock.setReferenceCounted(false);
- }
- wifiLock.acquire();
- }
- }
-
- private synchronized void releaseWifiLockIfNecessary() {
- if (wifiLock != null && wifiLock.isHeld()) {
- wifiLock.release();
- }
- }
-
- /**
- * Holds information about a PSMP object.
- */
- public class PSMPInfo {
- public PlayerStatus playerStatus;
- public Playable playable;
-
- public PSMPInfo(PlayerStatus playerStatus, Playable playable) {
- this.playerStatus = playerStatus;
- this.playable = playable;
- }
- }
-
- public static interface PSMPCallback {
- public void statusChanged(PSMPInfo newInfo);
-
- public void shouldStop();
-
- public void playbackSpeedChanged(float s);
-
- public void onBufferingUpdate(int percent);
-
- public boolean onMediaPlayerInfo(int code);
-
- public boolean onMediaPlayerError(Object inObj, int what, int extra);
-
- public boolean endPlayback(boolean playNextEpisode);
-
- public RemoteControlClient getRemoteControlClient();
- }
-
- private IPlayer setMediaPlayerListeners(IPlayer mp) {
- if (mp != null && media != null) {
- if (media.getMediaType() == MediaType.AUDIO) {
- ((AudioPlayer) mp)
- .setOnCompletionListener(audioCompletionListener);
- ((AudioPlayer) mp)
- .setOnSeekCompleteListener(audioSeekCompleteListener);
- ((AudioPlayer) mp).setOnErrorListener(audioErrorListener);
- ((AudioPlayer) mp)
- .setOnBufferingUpdateListener(audioBufferingUpdateListener);
- ((AudioPlayer) mp).setOnInfoListener(audioInfoListener);
- } else {
- ((VideoPlayer) mp)
- .setOnCompletionListener(videoCompletionListener);
- ((VideoPlayer) mp)
- .setOnSeekCompleteListener(videoSeekCompleteListener);
- ((VideoPlayer) mp).setOnErrorListener(videoErrorListener);
- ((VideoPlayer) mp)
- .setOnBufferingUpdateListener(videoBufferingUpdateListener);
- ((VideoPlayer) mp).setOnInfoListener(videoInfoListener);
- }
- }
- return mp;
- }
-
- private final com.aocate.media.MediaPlayer.OnCompletionListener audioCompletionListener = new com.aocate.media.MediaPlayer.OnCompletionListener() {
- @Override
- public void onCompletion(com.aocate.media.MediaPlayer mp) {
- genericOnCompletion();
- }
- };
-
- private final android.media.MediaPlayer.OnCompletionListener videoCompletionListener = new android.media.MediaPlayer.OnCompletionListener() {
- @Override
- public void onCompletion(android.media.MediaPlayer mp) {
- genericOnCompletion();
- }
- };
-
- private void genericOnCompletion() {
- endPlayback();
- }
-
- private final com.aocate.media.MediaPlayer.OnBufferingUpdateListener audioBufferingUpdateListener = new com.aocate.media.MediaPlayer.OnBufferingUpdateListener() {
- @Override
- public void onBufferingUpdate(com.aocate.media.MediaPlayer mp,
- int percent) {
- genericOnBufferingUpdate(percent);
- }
- };
-
- private final android.media.MediaPlayer.OnBufferingUpdateListener videoBufferingUpdateListener = new android.media.MediaPlayer.OnBufferingUpdateListener() {
- @Override
- public void onBufferingUpdate(android.media.MediaPlayer mp, int percent) {
- genericOnBufferingUpdate(percent);
- }
- };
-
- private void genericOnBufferingUpdate(int percent) {
- callback.onBufferingUpdate(percent);
- }
-
- private final com.aocate.media.MediaPlayer.OnInfoListener audioInfoListener = new com.aocate.media.MediaPlayer.OnInfoListener() {
- @Override
- public boolean onInfo(com.aocate.media.MediaPlayer mp, int what,
- int extra) {
- return genericInfoListener(what);
- }
- };
-
- private final android.media.MediaPlayer.OnInfoListener videoInfoListener = new android.media.MediaPlayer.OnInfoListener() {
- @Override
- public boolean onInfo(android.media.MediaPlayer mp, int what, int extra) {
- return genericInfoListener(what);
- }
- };
-
- private boolean genericInfoListener(int what) {
- return callback.onMediaPlayerInfo(what);
- }
-
- private final com.aocate.media.MediaPlayer.OnErrorListener audioErrorListener = new com.aocate.media.MediaPlayer.OnErrorListener() {
- @Override
- public boolean onError(com.aocate.media.MediaPlayer mp, int what,
- int extra) {
- return genericOnError(mp, what, extra);
- }
- };
-
- private final android.media.MediaPlayer.OnErrorListener videoErrorListener = new android.media.MediaPlayer.OnErrorListener() {
- @Override
- public boolean onError(android.media.MediaPlayer mp, int what, int extra) {
- return genericOnError(mp, what, extra);
- }
- };
-
- private boolean genericOnError(Object inObj, int what, int extra) {
- return callback.onMediaPlayerError(inObj, what, extra);
- }
-
- private final com.aocate.media.MediaPlayer.OnSeekCompleteListener audioSeekCompleteListener = new com.aocate.media.MediaPlayer.OnSeekCompleteListener() {
- @Override
- public void onSeekComplete(com.aocate.media.MediaPlayer mp) {
- genericSeekCompleteListener();
- }
- };
-
- private final android.media.MediaPlayer.OnSeekCompleteListener videoSeekCompleteListener = new android.media.MediaPlayer.OnSeekCompleteListener() {
- @Override
- public void onSeekComplete(android.media.MediaPlayer mp) {
- genericSeekCompleteListener();
- }
- };
-
- private final void genericSeekCompleteListener() {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- playerLock.lock();
- if (playerStatus == PlayerStatus.SEEKING) {
- setPlayerStatus(statusBeforeSeeking, media);
- }
- playerLock.unlock();
- }
- });
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java b/app/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
deleted file mode 100644
index 1b33e8667..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
+++ /dev/null
@@ -1,384 +0,0 @@
-package de.danoeh.antennapod.core.service.playback;
-
-import android.content.Context;
-import android.util.Log;
-
-import org.apache.commons.lang3.Validate;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.feed.EventDistributor;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.util.playback.Playable;
-
-import java.util.List;
-import java.util.concurrent.*;
-
-/**
- * Manages the background tasks of PlaybackSerivce, i.e.
- * the sleep timer, the position saver, the widget updater and
- * the queue loader.
- * <p/>
- * The PlaybackServiceTaskManager(PSTM) uses a callback object (PSTMCallback)
- * to notify the PlaybackService about updates from the running tasks.
- */
-public class PlaybackServiceTaskManager {
- private static final String TAG = "PlaybackServiceTaskManager";
-
- /**
- * Update interval of position saver in milliseconds.
- */
- public static final int POSITION_SAVER_WAITING_INTERVAL = 5000;
- /**
- * Notification interval of widget updater in milliseconds.
- */
- public static final int WIDGET_UPDATER_NOTIFICATION_INTERVAL = 1500;
-
- private static final int SCHED_EX_POOL_SIZE = 2;
- private final ScheduledThreadPoolExecutor schedExecutor;
-
- private ScheduledFuture positionSaverFuture;
- private ScheduledFuture widgetUpdaterFuture;
- private ScheduledFuture sleepTimerFuture;
- private volatile Future<List<FeedItem>> queueFuture;
- private volatile Future chapterLoaderFuture;
-
- private SleepTimer sleepTimer;
-
- private final Context context;
- private final PSTMCallback callback;
-
- /**
- * Sets up a new PSTM. This method will also start the queue loader task.
- *
- * @param context
- * @param callback A PSTMCallback object for notifying the user about updates. Must not be null.
- */
- public PlaybackServiceTaskManager(Context context, PSTMCallback callback) {
- Validate.notNull(context);
- Validate.notNull(callback);
-
- this.context = context;
- this.callback = callback;
- schedExecutor = new ScheduledThreadPoolExecutor(SCHED_EX_POOL_SIZE, new ThreadFactory() {
- @Override
- public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setPriority(Thread.MIN_PRIORITY);
- return t;
- }
- });
- loadQueue();
- EventDistributor.getInstance().register(eventDistributorListener);
- }
-
- private final EventDistributor.EventListener eventDistributorListener = new EventDistributor.EventListener() {
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((EventDistributor.QUEUE_UPDATE & arg) != 0) {
- cancelQueueLoader();
- loadQueue();
- }
- }
- };
-
- private synchronized boolean isQueueLoaderActive() {
- return queueFuture != null && !queueFuture.isDone();
- }
-
- private synchronized void cancelQueueLoader() {
- if (isQueueLoaderActive()) {
- queueFuture.cancel(true);
- }
- }
-
- private synchronized void loadQueue() {
- if (!isQueueLoaderActive()) {
- queueFuture = schedExecutor.submit(new Callable<List<FeedItem>>() {
- @Override
- public List<FeedItem> call() throws Exception {
- return DBReader.getQueue(context);
- }
- });
- }
- }
-
- /**
- * Returns the queue if it is already loaded or null if it hasn't been loaded yet.
- * In order to wait until the queue has been loaded, use getQueue()
- */
- public synchronized List<FeedItem> getQueueIfLoaded() {
- if (queueFuture.isDone()) {
- try {
- return queueFuture.get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
- return null;
- }
-
- /**
- * Returns the queue or waits until the PSTM has loaded the queue from the database.
- */
- public synchronized List<FeedItem> getQueue() throws InterruptedException {
- try {
- return queueFuture.get();
- } catch (ExecutionException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Starts the position saver task. If the position saver is already active, nothing will happen.
- */
- public synchronized void startPositionSaver() {
- if (!isPositionSaverActive()) {
- Runnable positionSaver = new Runnable() {
- @Override
- public void run() {
- callback.positionSaverTick();
- }
- };
- positionSaverFuture = schedExecutor.scheduleWithFixedDelay(positionSaver, POSITION_SAVER_WAITING_INTERVAL,
- POSITION_SAVER_WAITING_INTERVAL, TimeUnit.MILLISECONDS);
-
- if (BuildConfig.DEBUG) Log.d(TAG, "Started PositionSaver");
- } else {
- if (BuildConfig.DEBUG) Log.d(TAG, "Call to startPositionSaver was ignored.");
- }
- }
-
- /**
- * Returns true if the position saver is currently running.
- */
- public synchronized boolean isPositionSaverActive() {
- return positionSaverFuture != null && !positionSaverFuture.isCancelled() && !positionSaverFuture.isDone();
- }
-
- /**
- * Cancels the position saver. If the position saver is not running, nothing will happen.
- */
- public synchronized void cancelPositionSaver() {
- if (isPositionSaverActive()) {
- positionSaverFuture.cancel(false);
- if (BuildConfig.DEBUG) Log.d(TAG, "Cancelled PositionSaver");
- }
- }
-
- /**
- * Starts the widget updater task. If the widget updater is already active, nothing will happen.
- */
- public synchronized void startWidgetUpdater() {
- if (!isWidgetUpdaterActive()) {
- Runnable widgetUpdater = new Runnable() {
- @Override
- public void run() {
- callback.onWidgetUpdaterTick();
- }
- };
- widgetUpdaterFuture = schedExecutor.scheduleWithFixedDelay(widgetUpdater, WIDGET_UPDATER_NOTIFICATION_INTERVAL,
- WIDGET_UPDATER_NOTIFICATION_INTERVAL, TimeUnit.MILLISECONDS);
-
- if (BuildConfig.DEBUG) Log.d(TAG, "Started WidgetUpdater");
- } else {
- if (BuildConfig.DEBUG) Log.d(TAG, "Call to startWidgetUpdater was ignored.");
- }
- }
-
- /**
- * Starts a new sleep timer with the given waiting time. If another sleep timer is already active, it will be
- * cancelled first.
- * After waitingTime has elapsed, onSleepTimerExpired() will be called.
- *
- * @throws java.lang.IllegalArgumentException if waitingTime <= 0
- */
- public synchronized void setSleepTimer(long waitingTime) {
- Validate.isTrue(waitingTime > 0, "Waiting time <= 0");
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Setting sleep timer to " + Long.toString(waitingTime)
- + " milliseconds");
- if (isSleepTimerActive()) {
- sleepTimerFuture.cancel(true);
- }
- sleepTimer = new SleepTimer(waitingTime);
- sleepTimerFuture = schedExecutor.schedule(sleepTimer, 0, TimeUnit.MILLISECONDS);
- }
-
- /**
- * Returns true if the sleep timer is currently active.
- */
- public synchronized boolean isSleepTimerActive() {
- return sleepTimer != null && sleepTimerFuture != null && !sleepTimerFuture.isCancelled() && !sleepTimerFuture.isDone() && sleepTimer.isWaiting;
- }
-
- /**
- * Disables the sleep timer. If the sleep timer is not active, nothing will happen.
- */
- public synchronized void disableSleepTimer() {
- if (isSleepTimerActive()) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Disabling sleep timer");
- sleepTimerFuture.cancel(true);
- }
- }
-
- /**
- * Returns the current sleep timer time or 0 if the sleep timer is not active.
- */
- public synchronized long getSleepTimerTimeLeft() {
- if (isSleepTimerActive()) {
- return sleepTimer.getWaitingTime();
- } else {
- return 0;
- }
- }
-
-
- /**
- * Returns true if the widget updater is currently running.
- */
- public synchronized boolean isWidgetUpdaterActive() {
- return widgetUpdaterFuture != null && !widgetUpdaterFuture.isCancelled() && !widgetUpdaterFuture.isDone();
- }
-
- /**
- * Cancels the widget updater. If the widget updater is not running, nothing will happen.
- */
- public synchronized void cancelWidgetUpdater() {
- if (isWidgetUpdaterActive()) {
- widgetUpdaterFuture.cancel(false);
- if (BuildConfig.DEBUG) Log.d(TAG, "Cancelled WidgetUpdater");
- }
- }
-
- private synchronized void cancelChapterLoader() {
- if (isChapterLoaderActive()) {
- chapterLoaderFuture.cancel(true);
- }
- }
-
- private synchronized boolean isChapterLoaderActive() {
- return chapterLoaderFuture != null && !chapterLoaderFuture.isDone();
- }
-
- /**
- * Starts a new thread that loads the chapter marks from a playable object. If another chapter loader is already active,
- * it will be cancelled first.
- * On completion, the callback's onChapterLoaded method will be called.
- */
- public synchronized void startChapterLoader(final Playable media) {
- Validate.notNull(media);
-
- if (isChapterLoaderActive()) {
- cancelChapterLoader();
- }
-
- Runnable chapterLoader = new Runnable() {
- @Override
- public void run() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Chapter loader started");
- if (media.getChapters() == null) {
- media.loadChapterMarks();
- if (!Thread.currentThread().isInterrupted() && media.getChapters() != null) {
- callback.onChapterLoaded(media);
- }
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Chapter loader stopped");
- }
- };
- chapterLoaderFuture = schedExecutor.submit(chapterLoader);
- }
-
-
- /**
- * Cancels all tasks. The PSTM will be in the initial state after execution of this method.
- */
- public synchronized void cancelAllTasks() {
- cancelPositionSaver();
- cancelWidgetUpdater();
- disableSleepTimer();
- cancelQueueLoader();
- cancelChapterLoader();
- }
-
- /**
- * Cancels all tasks and shuts down the internal executor service of the PSTM. The object should not be used after
- * execution of this method.
- */
- public synchronized void shutdown() {
- EventDistributor.getInstance().unregister(eventDistributorListener);
- cancelAllTasks();
- schedExecutor.shutdown();
- }
-
- /**
- * Sleeps for a given time and then pauses playback.
- */
- private class SleepTimer implements Runnable {
- private static final String TAG = "SleepTimer";
- private static final long UPDATE_INTERVALL = 1000L;
- private volatile long waitingTime;
- private volatile boolean isWaiting;
-
- public SleepTimer(long waitingTime) {
- super();
- this.waitingTime = waitingTime;
- isWaiting = true;
- }
-
- @Override
- public void run() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Starting");
- while (waitingTime > 0) {
- try {
- Thread.sleep(UPDATE_INTERVALL);
- waitingTime -= UPDATE_INTERVALL;
-
- if (waitingTime <= 0) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Waiting completed");
- postExecute();
- if (!Thread.currentThread().isInterrupted()) {
- callback.onSleepTimerExpired();
- }
-
- }
- } catch (InterruptedException e) {
- Log.d(TAG, "Thread was interrupted while waiting");
- break;
- }
- }
- postExecute();
- }
-
- protected void postExecute() {
- isWaiting = false;
- }
-
- public long getWaitingTime() {
- return waitingTime;
- }
-
- public boolean isWaiting() {
- return isWaiting;
- }
-
- }
-
- public static interface PSTMCallback {
- void positionSaverTick();
-
- void onSleepTimerExpired();
-
- void onWidgetUpdaterTick();
-
- void onChapterLoaded(Playable media);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/service/playback/PlayerStatus.java b/app/src/main/java/de/danoeh/antennapod/core/service/playback/PlayerStatus.java
deleted file mode 100644
index 1ad0c25d9..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/service/playback/PlayerStatus.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package de.danoeh.antennapod.core.service.playback;
-
-public enum PlayerStatus {
- INDETERMINATE, // player is currently changing its state, listeners should wait until the player has left this state.
- ERROR,
- PREPARING,
- PAUSED,
- PLAYING,
- STOPPED,
- PREPARED,
- SEEKING,
- INITIALIZING, // playback service is loading the Playable's metadata
- INITIALIZED // playback service was started, data source of media player was set.
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/app/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
deleted file mode 100644
index 1b93e6ea2..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
+++ /dev/null
@@ -1,908 +0,0 @@
-package de.danoeh.antennapod.core.storage;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.database.SQLException;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.feed.*;
-import de.danoeh.antennapod.core.service.download.DownloadStatus;
-import de.danoeh.antennapod.core.util.DownloadError;
-import de.danoeh.antennapod.core.util.comparator.DownloadStatusComparator;
-import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator;
-import de.danoeh.antennapod.core.util.comparator.PlaybackCompletionDateComparator;
-import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
-import de.danoeh.antennapod.core.util.flattr.FlattrThing;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-
-/**
- * Provides methods for reading data from the AntennaPod database.
- * In general, all database calls in DBReader-methods are executed on the caller's thread.
- * This means that the caller should make sure that DBReader-methods are not executed on the GUI-thread.
- * This class will use the {@link de.danoeh.antennapod.core.feed.EventDistributor} to notify listeners about changes in the database.
- */
-public final class DBReader {
- private static final String TAG = "DBReader";
-
- /**
- * Maximum size of the list returned by {@link #getPlaybackHistory(android.content.Context)}.
- */
- public static final int PLAYBACK_HISTORY_SIZE = 50;
-
- /**
- * Maximum size of the list returned by {@link #getDownloadLog(android.content.Context)}.
- */
- public static final int DOWNLOAD_LOG_SIZE = 200;
-
-
- private DBReader() {
- }
-
- /**
- * Returns a list of Feeds, sorted alphabetically by their title.
- *
- * @param context A context that is used for opening a database connection.
- * @return A list of Feeds, sorted alphabetically by their title. A Feed-object
- * of the returned list does NOT have its list of FeedItems yet. The FeedItem-list
- * can be loaded separately with {@link #getFeedItemList(android.content.Context, de.danoeh.antennapod.core.feed.Feed)}.
- */
- public static List<Feed> getFeedList(final Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting Feedlist");
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- List<Feed> result = getFeedList(adapter);
- adapter.close();
- return result;
- }
-
- private static List<Feed> getFeedList(PodDBAdapter adapter) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting Feedlist");
-
- Cursor feedlistCursor = adapter.getAllFeedsCursor();
- List<Feed> feeds = new ArrayList<Feed>(feedlistCursor.getCount());
-
- if (feedlistCursor.moveToFirst()) {
- do {
- Feed feed = extractFeedFromCursorRow(adapter, feedlistCursor);
- feeds.add(feed);
- } while (feedlistCursor.moveToNext());
- }
- feedlistCursor.close();
- return feeds;
- }
-
- /**
- * Returns a list with the download URLs of all feeds.
- *
- * @param context A context that is used for opening the database connection.
- * @return A list of Strings with the download URLs of all feeds.
- */
- public static List<String> getFeedListDownloadUrls(final Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- List<String> result = new ArrayList<String>();
- adapter.open();
- Cursor feeds = adapter.getFeedCursorDownloadUrls();
- if (feeds.moveToFirst()) {
- do {
- result.add(feeds.getString(1));
- } while (feeds.moveToNext());
- }
- feeds.close();
- adapter.close();
-
- return result;
- }
-
- /**
- * Returns a list of 'expired Feeds', i.e. Feeds that have not been updated for a certain amount of time.
- *
- * @param context A context that is used for opening a database connection.
- * @param expirationTime Time that is used for determining whether a feed is outdated or not.
- * A Feed is considered expired if 'lastUpdate < (currentTime - expirationTime)' evaluates to true.
- * @return A list of Feeds, sorted alphabetically by their title. A Feed-object
- * of the returned list does NOT have its list of FeedItems yet. The FeedItem-list
- * can be loaded separately with {@link #getFeedItemList(android.content.Context, de.danoeh.antennapod.core.feed.Feed)}.
- */
- public static List<Feed> getExpiredFeedsList(final Context context, final long expirationTime) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, String.format("getExpiredFeedsList(%d)", expirationTime));
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
-
- Cursor feedlistCursor = adapter.getExpiredFeedsCursor(expirationTime);
- List<Feed> feeds = new ArrayList<Feed>(feedlistCursor.getCount());
-
- if (feedlistCursor.moveToFirst()) {
- do {
- Feed feed = extractFeedFromCursorRow(adapter, feedlistCursor);
- feeds.add(feed);
- } while (feedlistCursor.moveToNext());
- }
- feedlistCursor.close();
- return feeds;
- }
-
- /**
- * Takes a list of FeedItems and loads their corresponding Feed-objects from the database.
- * The feedID-attribute of a FeedItem must be set to the ID of its feed or the method will
- * not find the correct feed of an item.
- *
- * @param context A context that is used for opening a database connection.
- * @param items The FeedItems whose Feed-objects should be loaded.
- */
- public static void loadFeedDataOfFeedItemlist(Context context,
- List<FeedItem> items) {
- List<Feed> feeds = getFeedList(context);
- for (FeedItem item : items) {
- for (Feed feed : feeds) {
- if (feed.getId() == item.getFeedId()) {
- item.setFeed(feed);
- break;
- }
- }
- if (item.getFeed() == null) {
- Log.w(TAG, "No match found for item with ID " + item.getId() + ". Feed ID was " + item.getFeedId());
- }
- }
- }
-
- /**
- * Loads the list of FeedItems for a certain Feed-object. This method should NOT be used if the FeedItems are not
- * used. In order to get information ABOUT the list of FeedItems, consider using {@link #getFeedStatisticsList(android.content.Context)} instead.
- *
- * @param context A context that is used for opening a database connection.
- * @param feed The Feed whose items should be loaded
- * @return A list with the FeedItems of the Feed. The Feed-attribute of the FeedItems will already be set correctly.
- * The method does NOT change the items-attribute of the feed.
- */
- public static List<FeedItem> getFeedItemList(Context context,
- final Feed feed) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting Feeditems of feed " + feed.getTitle());
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
-
- Cursor itemlistCursor = adapter.getAllItemsOfFeedCursor(feed);
- List<FeedItem> items = extractItemlistFromCursor(adapter,
- itemlistCursor);
- itemlistCursor.close();
-
- Collections.sort(items, new FeedItemPubdateComparator());
-
- adapter.close();
-
- for (FeedItem item : items) {
- item.setFeed(feed);
- }
-
- return items;
- }
-
- static List<FeedItem> extractItemlistFromCursor(Context context, Cursor itemlistCursor) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- List<FeedItem> result = extractItemlistFromCursor(adapter, itemlistCursor);
- adapter.close();
- return result;
- }
-
- private static List<FeedItem> extractItemlistFromCursor(
- PodDBAdapter adapter, Cursor itemlistCursor) {
- ArrayList<String> itemIds = new ArrayList<String>();
- List<FeedItem> items = new ArrayList<FeedItem>(
- itemlistCursor.getCount());
-
- if (itemlistCursor.moveToFirst()) {
- do {
- FeedItem item = new FeedItem();
-
- item.setId(itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_ID));
- item.setTitle(itemlistCursor
- .getString(PodDBAdapter.IDX_FI_SMALL_TITLE));
- item.setLink(itemlistCursor
- .getString(PodDBAdapter.IDX_FI_SMALL_LINK));
- item.setPubDate(new Date(itemlistCursor
- .getLong(PodDBAdapter.IDX_FI_SMALL_PUBDATE)));
- item.setPaymentLink(itemlistCursor
- .getString(PodDBAdapter.IDX_FI_SMALL_PAYMENT_LINK));
- item.setFeedId(itemlistCursor
- .getLong(PodDBAdapter.IDX_FI_SMALL_FEED));
- itemIds.add(String.valueOf(item.getId()));
-
- item.setRead((itemlistCursor
- .getInt(PodDBAdapter.IDX_FI_SMALL_READ) > 0));
- item.setItemIdentifier(itemlistCursor
- .getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER));
- item.setFlattrStatus(new FlattrStatus(itemlistCursor
- .getLong(PodDBAdapter.IDX_FI_SMALL_FLATTR_STATUS)));
-
- long imageIndex = itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_IMAGE);
- if (imageIndex != 0) {
- item.setImage(getFeedImage(adapter, imageIndex));
- }
-
- // extract chapters
- boolean hasSimpleChapters = itemlistCursor
- .getInt(PodDBAdapter.IDX_FI_SMALL_HAS_CHAPTERS) > 0;
- if (hasSimpleChapters) {
- Cursor chapterCursor = adapter
- .getSimpleChaptersOfFeedItemCursor(item);
- if (chapterCursor.moveToFirst()) {
- item.setChapters(new ArrayList<Chapter>());
- do {
- int chapterType = chapterCursor
- .getInt(PodDBAdapter.KEY_CHAPTER_TYPE_INDEX);
- Chapter chapter = null;
- long start = chapterCursor
- .getLong(PodDBAdapter.KEY_CHAPTER_START_INDEX);
- String title = chapterCursor
- .getString(PodDBAdapter.KEY_TITLE_INDEX);
- String link = chapterCursor
- .getString(PodDBAdapter.KEY_CHAPTER_LINK_INDEX);
-
- switch (chapterType) {
- case SimpleChapter.CHAPTERTYPE_SIMPLECHAPTER:
- chapter = new SimpleChapter(start, title, item,
- link);
- break;
- case ID3Chapter.CHAPTERTYPE_ID3CHAPTER:
- chapter = new ID3Chapter(start, title, item,
- link);
- break;
- case VorbisCommentChapter.CHAPTERTYPE_VORBISCOMMENT_CHAPTER:
- chapter = new VorbisCommentChapter(start,
- title, item, link);
- break;
- }
- if (chapter != null) {
- chapter.setId(chapterCursor
- .getLong(PodDBAdapter.KEY_ID_INDEX));
- item.getChapters().add(chapter);
- }
- } while (chapterCursor.moveToNext());
- }
- chapterCursor.close();
- }
- items.add(item);
- } while (itemlistCursor.moveToNext());
- }
-
- extractMediafromItemlist(adapter, items, itemIds);
- return items;
- }
-
- private static void extractMediafromItemlist(PodDBAdapter adapter,
- List<FeedItem> items, ArrayList<String> itemIds) {
-
- List<FeedItem> itemsCopy = new ArrayList<FeedItem>(items);
- Cursor cursor = adapter.getFeedMediaCursorByItemID(itemIds
- .toArray(new String[itemIds.size()]));
- if (cursor.moveToFirst()) {
- do {
- long itemId = cursor.getLong(PodDBAdapter.KEY_MEDIA_FEEDITEM_INDEX);
- // find matching feed item
- FeedItem item = getMatchingItemForMedia(itemId, itemsCopy);
- if (item != null) {
- item.setMedia(extractFeedMediaFromCursorRow(cursor));
- item.getMedia().setItem(item);
- }
- } while (cursor.moveToNext());
- cursor.close();
- }
- }
-
- private static FeedMedia extractFeedMediaFromCursorRow(final Cursor cursor) {
- long mediaId = cursor.getLong(PodDBAdapter.KEY_ID_INDEX);
- Date playbackCompletionDate = null;
- long playbackCompletionTime = cursor
- .getLong(PodDBAdapter.KEY_PLAYBACK_COMPLETION_DATE_INDEX);
- if (playbackCompletionTime > 0) {
- playbackCompletionDate = new Date(
- playbackCompletionTime);
- }
-
- return new FeedMedia(
- mediaId,
- null,
- cursor.getInt(PodDBAdapter.KEY_DURATION_INDEX),
- cursor.getInt(PodDBAdapter.KEY_POSITION_INDEX),
- cursor.getLong(PodDBAdapter.KEY_SIZE_INDEX),
- cursor.getString(PodDBAdapter.KEY_MIME_TYPE_INDEX),
- cursor.getString(PodDBAdapter.KEY_FILE_URL_INDEX),
- cursor.getString(PodDBAdapter.KEY_DOWNLOAD_URL_INDEX),
- cursor.getInt(PodDBAdapter.KEY_DOWNLOADED_INDEX) > 0,
- playbackCompletionDate,
- cursor.getInt(PodDBAdapter.KEY_PLAYED_DURATION_INDEX));
- }
-
- private static Feed extractFeedFromCursorRow(PodDBAdapter adapter,
- Cursor cursor) {
- Date lastUpdate = new Date(
- cursor.getLong(PodDBAdapter.IDX_FEED_SEL_STD_LASTUPDATE));
-
- final FeedImage image;
- long imageIndex = cursor.getLong(PodDBAdapter.IDX_FEED_SEL_STD_IMAGE);
- if (imageIndex != 0) {
- image = getFeedImage(adapter, imageIndex);
- } else {
- image = null;
- }
- Feed feed = new Feed(cursor.getLong(PodDBAdapter.IDX_FEED_SEL_STD_ID),
- lastUpdate,
- cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_TITLE),
- cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_LINK),
- cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_DESCRIPTION),
- cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_PAYMENT_LINK),
- cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_AUTHOR),
- cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_LANGUAGE),
- cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_TYPE),
- cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_FEED_IDENTIFIER),
- image,
- cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_FILE_URL),
- cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_DOWNLOAD_URL),
- cursor.getInt(PodDBAdapter.IDX_FEED_SEL_STD_DOWNLOADED) > 0,
- new FlattrStatus(cursor.getLong(PodDBAdapter.IDX_FEED_SEL_STD_FLATTR_STATUS)));
-
- if (image != null) {
- image.setOwner(feed);
- }
-
- FeedPreferences preferences = new FeedPreferences(cursor.getLong(PodDBAdapter.IDX_FEED_SEL_STD_ID),
- cursor.getInt(PodDBAdapter.IDX_FEED_SEL_PREFERENCES_AUTO_DOWNLOAD) > 0,
- cursor.getString(PodDBAdapter.IDX_FEED_SEL_PREFERENCES_USERNAME),
- cursor.getString(PodDBAdapter.IDX_FEED_SEL_PREFERENCES_PASSWORD));
-
- feed.setPreferences(preferences);
- return feed;
- }
-
- private static FeedItem getMatchingItemForMedia(long itemId,
- List<FeedItem> items) {
- for (FeedItem item : items) {
- if (item.getId() == itemId) {
- return item;
- }
- }
- return null;
- }
-
- static List<FeedItem> getQueue(Context context, PodDBAdapter adapter) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting queue");
-
- Cursor itemlistCursor = adapter.getQueueCursor();
- List<FeedItem> items = extractItemlistFromCursor(adapter,
- itemlistCursor);
- itemlistCursor.close();
- loadFeedDataOfFeedItemlist(context, items);
-
- return items;
- }
-
- /**
- * Loads the IDs of the FeedItems in the queue. This method should be preferred over
- * {@link #getQueue(android.content.Context)} if the FeedItems of the queue are not needed.
- *
- * @param context A context that is used for opening a database connection.
- * @return A list of IDs sorted by the same order as the queue. The caller can wrap the returned
- * list in a {@link de.danoeh.antennapod.core.util.QueueAccess} object for easier access to the queue's properties.
- */
- public static List<Long> getQueueIDList(Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
-
- adapter.open();
- List<Long> result = getQueueIDList(adapter);
- adapter.close();
-
- return result;
- }
-
- static List<Long> getQueueIDList(PodDBAdapter adapter) {
- adapter.open();
- Cursor queueCursor = adapter.getQueueIDCursor();
-
- List<Long> queueIds = new ArrayList<Long>(queueCursor.getCount());
- if (queueCursor.moveToFirst()) {
- do {
- queueIds.add(queueCursor.getLong(0));
- } while (queueCursor.moveToNext());
- }
- return queueIds;
- }
-
-
- /**
- * Loads a list of the FeedItems in the queue. If the FeedItems of the queue are not used directly, consider using
- * {@link #getQueueIDList(android.content.Context)} instead.
- *
- * @param context A context that is used for opening a database connection.
- * @return A list of FeedItems sorted by the same order as the queue. The caller can wrap the returned
- * list in a {@link de.danoeh.antennapod.core.util.QueueAccess} object for easier access to the queue's properties.
- */
- public static List<FeedItem> getQueue(Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting queue");
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- List<FeedItem> items = getQueue(context, adapter);
- adapter.close();
- return items;
- }
-
- /**
- * Loads a list of FeedItems whose episode has been downloaded.
- *
- * @param context A context that is used for opening a database connection.
- * @return A list of FeedItems whose episdoe has been downloaded.
- */
- public static List<FeedItem> getDownloadedItems(Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting downloaded items");
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
-
- Cursor itemlistCursor = adapter.getDownloadedItemsCursor();
- List<FeedItem> items = extractItemlistFromCursor(adapter,
- itemlistCursor);
- itemlistCursor.close();
- loadFeedDataOfFeedItemlist(context, items);
- Collections.sort(items, new FeedItemPubdateComparator());
-
- adapter.close();
- return items;
-
- }
-
- /**
- * Loads a list of FeedItems whose 'read'-attribute is set to false.
- *
- * @param context A context that is used for opening a database connection.
- * @return A list of FeedItems whose 'read'-attribute it set to false. If the FeedItems in the list are not used,
- * consider using {@link #getUnreadItemIds(android.content.Context)} instead.
- */
- public static List<FeedItem> getUnreadItemsList(Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting unread items list");
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
-
- Cursor itemlistCursor = adapter.getUnreadItemsCursor();
- List<FeedItem> items = extractItemlistFromCursor(adapter,
- itemlistCursor);
- itemlistCursor.close();
-
- loadFeedDataOfFeedItemlist(context, items);
-
- adapter.close();
-
- return items;
- }
-
- /**
- * Loads the IDs of the FeedItems whose 'read'-attribute is set to false.
- *
- * @param context A context that is used for opening a database connection.
- * @return A list of IDs of the FeedItems whose 'read'-attribute is set to false. This method should be preferred
- * over {@link #getUnreadItemsList(android.content.Context)} if the FeedItems in the UnreadItems list are not used.
- */
- public static long[] getUnreadItemIds(Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- Cursor cursor = adapter.getUnreadItemIdsCursor();
- long[] itemIds = new long[cursor.getCount()];
- int i = 0;
- if (cursor.moveToFirst()) {
- do {
- itemIds[i] = cursor.getLong(PodDBAdapter.KEY_ID_INDEX);
- i++;
- } while (cursor.moveToNext());
- }
- return itemIds;
- }
-
-
- /**
- * Loads a list of FeedItems sorted by pubDate in descending order.
- *
- * @param context A context that is used for opening a database connection.
- * @param limit The maximum number of episodes that should be loaded.
- */
- public static List<FeedItem> getRecentlyPublishedEpisodes(Context context, int limit) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting recently published items list");
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
-
- Cursor itemlistCursor = adapter.getRecentlyPublishedItemsCursor(limit);
- List<FeedItem> items = extractItemlistFromCursor(adapter,
- itemlistCursor);
- itemlistCursor.close();
-
- loadFeedDataOfFeedItemlist(context, items);
-
- adapter.close();
-
- return items;
- }
-
- /**
- * Loads the playback history from the database. A FeedItem is in the playback history if playback of the correpsonding episode
- * has been completed at least once.
- *
- * @param context A context that is used for opening a database connection.
- * @return The playback history. The FeedItems are sorted by their media's playbackCompletionDate in descending order.
- * The size of the returned list is limited by {@link #PLAYBACK_HISTORY_SIZE}.
- */
- public static List<FeedItem> getPlaybackHistory(final Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Loading playback history");
- final int PLAYBACK_HISTORY_SIZE = 50;
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
-
- Cursor mediaCursor = adapter.getCompletedMediaCursor(PLAYBACK_HISTORY_SIZE);
- String[] itemIds = new String[mediaCursor.getCount()];
- for (int i = 0; i < itemIds.length && mediaCursor.moveToPosition(i); i++) {
- itemIds[i] = Long.toString(mediaCursor.getLong(PodDBAdapter.KEY_MEDIA_FEEDITEM_INDEX));
- }
- mediaCursor.close();
- Cursor itemCursor = adapter.getFeedItemCursor(itemIds);
- List<FeedItem> items = extractItemlistFromCursor(adapter, itemCursor);
- loadFeedDataOfFeedItemlist(context, items);
- itemCursor.close();
- adapter.close();
-
- Collections.sort(items, new PlaybackCompletionDateComparator());
- return items;
- }
-
- /**
- * Loads the download log from the database.
- *
- * @param context A context that is used for opening a database connection.
- * @return A list with DownloadStatus objects that represent the download log.
- * The size of the returned list is limited by {@link #DOWNLOAD_LOG_SIZE}.
- */
- public static List<DownloadStatus> getDownloadLog(Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting DownloadLog");
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- Cursor logCursor = adapter.getDownloadLogCursor(DOWNLOAD_LOG_SIZE);
- List<DownloadStatus> downloadLog = new ArrayList<DownloadStatus>(
- logCursor.getCount());
-
- if (logCursor.moveToFirst()) {
- do {
- long id = logCursor.getLong(PodDBAdapter.KEY_ID_INDEX);
-
- long feedfileId = logCursor
- .getLong(PodDBAdapter.KEY_FEEDFILE_INDEX);
- int feedfileType = logCursor
- .getInt(PodDBAdapter.KEY_FEEDFILETYPE_INDEX);
- boolean successful = logCursor
- .getInt(PodDBAdapter.KEY_SUCCESSFUL_INDEX) > 0;
- int reason = logCursor.getInt(PodDBAdapter.KEY_REASON_INDEX);
- String reasonDetailed = logCursor
- .getString(PodDBAdapter.KEY_REASON_DETAILED_INDEX);
- String title = logCursor
- .getString(PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE_INDEX);
- Date completionDate = new Date(
- logCursor
- .getLong(PodDBAdapter.KEY_COMPLETION_DATE_INDEX)
- );
- downloadLog.add(new DownloadStatus(id, title, feedfileId,
- feedfileType, successful, DownloadError.fromCode(reason), completionDate,
- reasonDetailed));
-
- } while (logCursor.moveToNext());
- }
- logCursor.close();
- Collections.sort(downloadLog, new DownloadStatusComparator());
- return downloadLog;
- }
-
- /**
- * Loads the FeedItemStatistics objects of all Feeds in the database. This method should be preferred over
- * {@link #getFeedItemList(android.content.Context, de.danoeh.antennapod.core.feed.Feed)} if only metadata about
- * the FeedItems is needed.
- *
- * @param context A context that is used for opening a database connection.
- * @return A list of FeedItemStatistics objects sorted alphabetically by their Feed's title.
- */
- public static List<FeedItemStatistics> getFeedStatisticsList(final Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- List<FeedItemStatistics> result = new ArrayList<FeedItemStatistics>();
- Cursor cursor = adapter.getFeedStatisticsCursor();
- if (cursor.moveToFirst()) {
- do {
- result.add(new FeedItemStatistics(cursor.getLong(PodDBAdapter.IDX_FEEDSTATISTICS_FEED),
- cursor.getInt(PodDBAdapter.IDX_FEEDSTATISTICS_NUM_ITEMS),
- cursor.getInt(PodDBAdapter.IDX_FEEDSTATISTICS_NEW_ITEMS),
- cursor.getInt(PodDBAdapter.IDX_FEEDSTATISTICS_IN_PROGRESS_EPISODES),
- new Date(cursor.getLong(PodDBAdapter.IDX_FEEDSTATISTICS_LATEST_EPISODE))));
- } while (cursor.moveToNext());
- }
-
- cursor.close();
- adapter.close();
- return result;
- }
-
- /**
- * Loads a specific Feed from the database.
- *
- * @param context A context that is used for opening a database connection.
- * @param feedId The ID of the Feed
- * @return The Feed or null if the Feed could not be found. The Feeds FeedItems will also be loaded from the
- * database and the items-attribute will be set correctly.
- */
- public static Feed getFeed(final Context context, final long feedId) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- Feed result = getFeed(context, feedId, adapter);
- adapter.close();
- return result;
- }
-
- static Feed getFeed(final Context context, final long feedId, PodDBAdapter adapter) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Loading feed with id " + feedId);
- Feed feed = null;
-
- Cursor feedCursor = adapter.getFeedCursor(feedId);
- if (feedCursor.moveToFirst()) {
- feed = extractFeedFromCursorRow(adapter, feedCursor);
- feed.setItems(getFeedItemList(context, feed));
- } else {
- Log.e(TAG, "getFeed could not find feed with id " + feedId);
- }
- feedCursor.close();
- return feed;
- }
-
- static FeedItem getFeedItem(final Context context, final long itemId, PodDBAdapter adapter) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Loading feeditem with id " + itemId);
- FeedItem item = null;
-
- Cursor itemCursor = adapter.getFeedItemCursor(Long.toString(itemId));
- if (itemCursor.moveToFirst()) {
- List<FeedItem> list = extractItemlistFromCursor(adapter, itemCursor);
- if (list.size() > 0) {
- item = list.get(0);
- loadFeedDataOfFeedItemlist(context, list);
- }
- }
- return item;
-
- }
-
- /**
- * Loads a specific FeedItem from the database.
- *
- * @param context A context that is used for opening a database connection.
- * @param itemId The ID of the FeedItem
- * @return The FeedItem or null if the FeedItem could not be found. All FeedComponent-attributes of the FeedItem will
- * also be loaded from the database.
- */
- public static FeedItem getFeedItem(final Context context, final long itemId) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Loading feeditem with id " + itemId);
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- FeedItem item = getFeedItem(context, itemId, adapter);
- adapter.close();
- return item;
-
- }
-
- /**
- * Loads additional information about a FeedItem, e.g. shownotes
- *
- * @param context A context that is used for opening a database connection.
- * @param item The FeedItem
- */
- public static void loadExtraInformationOfFeedItem(final Context context, final FeedItem item) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- Cursor extraCursor = adapter.getExtraInformationOfItem(item);
- if (extraCursor.moveToFirst()) {
- String description = extraCursor
- .getString(PodDBAdapter.IDX_FI_EXTRA_DESCRIPTION);
- String contentEncoded = extraCursor
- .getString(PodDBAdapter.IDX_FI_EXTRA_CONTENT_ENCODED);
- item.setDescription(description);
- item.setContentEncoded(contentEncoded);
- }
- adapter.close();
- }
-
- /**
- * Returns the number of downloaded episodes.
- *
- * @param context A context that is used for opening a database connection.
- * @return The number of downloaded episodes.
- */
- public static int getNumberOfDownloadedEpisodes(final Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- final int result = adapter.getNumberOfDownloadedEpisodes();
- adapter.close();
- return result;
- }
-
- /**
- * Returns the number of unread items.
- *
- * @param context A context that is used for opening a database connection.
- * @return The number of unread items.
- */
- public static int getNumberOfUnreadItems(final Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- final int result = adapter.getNumberOfUnreadItems();
- adapter.close();
- return result;
- }
-
- /**
- * Searches the DB for a FeedImage of the given id.
- *
- * @param context A context that is used for opening a database connection.
- * @param imageId The id of the object
- * @return The found object
- */
- public static FeedImage getFeedImage(final Context context, final long imageId) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- FeedImage result = getFeedImage(adapter, imageId);
- adapter.close();
- return result;
- }
-
- /**
- * Searches the DB for a FeedImage of the given id.
- *
- * @param id The id of the object
- * @return The found object
- */
- static FeedImage getFeedImage(PodDBAdapter adapter, final long id) {
- Cursor cursor = adapter.getImageCursor(id);
- if ((cursor.getCount() == 0) || !cursor.moveToFirst()) {
- throw new SQLException("No FeedImage found at index: " + id);
- }
- FeedImage image = new FeedImage(id, cursor.getString(cursor
- .getColumnIndex(PodDBAdapter.KEY_TITLE)),
- cursor.getString(cursor
- .getColumnIndex(PodDBAdapter.KEY_FILE_URL)),
- cursor.getString(cursor
- .getColumnIndex(PodDBAdapter.KEY_DOWNLOAD_URL)),
- cursor.getInt(cursor
- .getColumnIndex(PodDBAdapter.KEY_DOWNLOADED)) > 0
- );
- cursor.close();
- return image;
- }
-
- /**
- * Searches the DB for a FeedMedia of the given id.
- *
- * @param context A context that is used for opening a database connection.
- * @param mediaId The id of the object
- * @return The found object
- */
- public static FeedMedia getFeedMedia(final Context context, final long mediaId) {
- PodDBAdapter adapter = new PodDBAdapter(context);
-
- adapter.open();
- Cursor mediaCursor = adapter.getSingleFeedMediaCursor(mediaId);
-
- FeedMedia media = null;
- if (mediaCursor.moveToFirst()) {
- final long itemId = mediaCursor.getLong(PodDBAdapter.KEY_MEDIA_FEEDITEM_INDEX);
- media = extractFeedMediaFromCursorRow(mediaCursor);
- FeedItem item = getFeedItem(context, itemId);
- if (media != null && item != null) {
- media.setItem(item);
- item.setMedia(media);
- }
- }
-
- mediaCursor.close();
- adapter.close();
-
- return media;
- }
-
- /**
- * Returns the flattr queue as a List of FlattrThings. The list consists of Feeds and FeedItems.
- *
- * @param context A context that is used for opening a database connection.
- * @return The flattr queue as a List.
- */
- public static List<FlattrThing> getFlattrQueue(Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- List<FlattrThing> result = new ArrayList<FlattrThing>();
-
- // load feeds
- Cursor feedCursor = adapter.getFeedsInFlattrQueueCursor();
- if (feedCursor.moveToFirst()) {
- do {
- result.add(extractFeedFromCursorRow(adapter, feedCursor));
- } while (feedCursor.moveToNext());
- }
- feedCursor.close();
-
- //load feed items
- Cursor feedItemCursor = adapter.getFeedItemsInFlattrQueueCursor();
- result.addAll(extractItemlistFromCursor(adapter, feedItemCursor));
- feedItemCursor.close();
-
- adapter.close();
- Log.d(TAG, "Returning flattrQueueIterator for queue with " + result.size() + " items.");
- return result;
- }
-
-
- /**
- * Returns true if the flattr queue is empty.
- *
- * @param context A context that is used for opening a database connection.
- */
- public static boolean getFlattrQueueEmpty(Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- boolean empty = adapter.getFlattrQueueSize() == 0;
- adapter.close();
- return empty;
- }
-
- /**
- * Returns data necessary for displaying the navigation drawer. This includes
- * the list of subscriptions, the number of items in the queue and the number of unread
- * items.
- *
- * @param context A context that is used for opening a database connection.
- */
- public static NavDrawerData getNavDrawerData(Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- List<Feed> feeds = getFeedList(adapter);
- int queueSize = adapter.getQueueSize();
- int numUnreadItems = adapter.getNumberOfUnreadItems();
- NavDrawerData result = new NavDrawerData(feeds, queueSize, numUnreadItems);
- adapter.close();
- return result;
- }
-
- public static class NavDrawerData {
- public List<Feed> feeds;
- public int queueSize;
- public int numUnreadItems;
-
- public NavDrawerData(List<Feed> feeds, int queueSize, int numUnreadItems) {
- this.feeds = feeds;
- this.queueSize = queueSize;
- this.numUnreadItems = numUnreadItems;
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/app/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
deleted file mode 100644
index 28cab29b9..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
+++ /dev/null
@@ -1,895 +0,0 @@
-package de.danoeh.antennapod.core.storage;
-
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.asynctask.FlattrClickWorker;
-import de.danoeh.antennapod.core.asynctask.FlattrStatusFetcher;
-import de.danoeh.antennapod.core.feed.*;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.service.GpodnetSyncService;
-import de.danoeh.antennapod.core.service.download.DownloadStatus;
-import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.core.util.DownloadError;
-import de.danoeh.antennapod.core.util.NetworkUtils;
-import de.danoeh.antennapod.core.util.QueueAccess;
-import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator;
-import de.danoeh.antennapod.core.util.exception.MediaFileNotFoundException;
-import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
-
-import java.util.*;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Provides methods for doing common tasks that use DBReader and DBWriter.
- */
-public final class DBTasks {
- private static final String TAG = "DBTasks";
-
- /**
- * Executor service used by the autodownloadUndownloadedEpisodes method.
- */
- private static ExecutorService autodownloadExec;
-
- static {
- autodownloadExec = Executors.newSingleThreadExecutor(new ThreadFactory() {
- @Override
- public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setPriority(Thread.MIN_PRIORITY);
- return t;
- }
- });
- }
-
- private DBTasks() {
- }
-
- /**
- * Removes the feed with the given download url. This method should NOT be executed on the GUI thread.
- *
- * @param context Used for accessing the db
- * @param downloadUrl URL of the feed.
- */
- public static void removeFeedWithDownloadUrl(Context context, String downloadUrl) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- Cursor cursor = adapter.getFeedCursorDownloadUrls();
- long feedID = 0;
- if (cursor.moveToFirst()) {
- do {
- if (cursor.getString(1).equals(downloadUrl)) {
- feedID = cursor.getLong(0);
- }
- } while (cursor.moveToNext());
- }
- cursor.close();
- adapter.close();
-
- if (feedID != 0) {
- try {
- DBWriter.deleteFeed(context, feedID).get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- } else {
- Log.w(TAG, "removeFeedWithDownloadUrl: Could not find feed with url: " + downloadUrl);
- }
- }
-
- /**
- * Starts playback of a FeedMedia object's file. This method will build an Intent based on the given parameters to
- * start the {@link PlaybackService}.
- *
- * @param context Used for sending starting Services and Activities.
- * @param media The FeedMedia object.
- * @param showPlayer If true, starts the appropriate player activity ({@link de.danoeh.antennapod.activity.AudioplayerActivity}
- * or {@link de.danoeh.antennapod.activity.VideoplayerActivity}
- * @param startWhenPrepared Parameter for the {@link PlaybackService} start intent. If true, playback will start as
- * soon as the PlaybackService has finished loading the FeedMedia object's file.
- * @param shouldStream Parameter for the {@link PlaybackService} start intent. If true, the FeedMedia object's file
- * will be streamed, otherwise the downloaded file will be used. If the downloaded file cannot be
- * found, the PlaybackService will shutdown and the database entry of the FeedMedia object will be
- * corrected.
- */
- public static void playMedia(final Context context, final FeedMedia media,
- boolean showPlayer, boolean startWhenPrepared, boolean shouldStream) {
- try {
- if (!shouldStream) {
- if (media.fileExists() == false) {
- throw new MediaFileNotFoundException(
- "No episode was found at " + media.getFile_url(),
- media);
- }
- }
- // Start playback Service
- Intent launchIntent = new Intent(context, PlaybackService.class);
- launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
- launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED,
- startWhenPrepared);
- launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM,
- shouldStream);
- launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY,
- true);
- context.startService(launchIntent);
- if (showPlayer) {
- // Launch media player
- context.startActivity(PlaybackService.getPlayerActivityIntent(
- context, media));
- }
- DBWriter.addQueueItemAt(context, media.getItem().getId(), 0, false);
- } catch (MediaFileNotFoundException e) {
- e.printStackTrace();
- if (media.isPlaying()) {
- context.sendBroadcast(new Intent(
- PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
- }
- notifyMissingFeedMediaFile(context, media);
- }
- }
-
- private static AtomicBoolean isRefreshing = new AtomicBoolean(false);
-
- /**
- * Refreshes a given list of Feeds in a separate Thread. This method might ignore subsequent calls if it is still
- * enqueuing Feeds for download from a previous call
- *
- * @param context Might be used for accessing the database
- * @param feeds List of Feeds that should be refreshed.
- */
- public static void refreshAllFeeds(final Context context,
- final List<Feed> feeds) {
- if (isRefreshing.compareAndSet(false, true)) {
- new Thread() {
- public void run() {
- if (feeds != null) {
- refreshFeeds(context, feeds);
- } else {
- refreshFeeds(context, DBReader.getFeedList(context));
- }
- isRefreshing.set(false);
-
- if (FlattrUtils.hasToken()) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Flattring all pending things.");
- new FlattrClickWorker(context).executeAsync(); // flattr pending things
-
- if (BuildConfig.DEBUG) Log.d(TAG, "Fetching flattr status.");
- new FlattrStatusFetcher(context).start();
-
- }
- GpodnetSyncService.sendSyncIntent(context);
- autodownloadUndownloadedItems(context);
- }
- }.start();
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Ignoring request to refresh all feeds: Refresh lock is locked");
- }
- }
-
- /**
- * Used by refreshExpiredFeeds to determine which feeds should be refreshed.
- * This method will use the value specified in the UserPreferences as the
- * expiration time.
- *
- * @param context Used for DB access.
- * @return A list of expired feeds. An empty list will be returned if there
- * are no expired feeds.
- */
- public static List<Feed> getExpiredFeeds(final Context context) {
- long millis = UserPreferences.getUpdateInterval();
-
- if (millis > 0) {
-
- List<Feed> feedList = DBReader.getExpiredFeedsList(context,
- millis);
- if (feedList.size() > 0) {
- refreshFeeds(context, feedList);
- }
- return feedList;
- } else {
- return new ArrayList<Feed>();
- }
- }
-
- /**
- * Refreshes expired Feeds in the list returned by the getExpiredFeedsList(Context, long) method in DBReader.
- * The expiration date parameter is determined by the update interval specified in {@link UserPreferences}.
- *
- * @param context Used for DB access.
- */
- public static void refreshExpiredFeeds(final Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Refreshing expired feeds");
-
- new Thread() {
- public void run() {
- refreshFeeds(context, getExpiredFeeds(context));
- }
- }.start();
- }
-
- private static void refreshFeeds(final Context context,
- final List<Feed> feedList) {
-
- for (Feed feed : feedList) {
- try {
- refreshFeed(context, feed);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DBWriter.addDownloadStatus(
- context,
- new DownloadStatus(feed, feed
- .getHumanReadableIdentifier(),
- DownloadError.ERROR_REQUEST_ERROR, false, e
- .getMessage()
- )
- );
- }
- }
-
- }
-
- /**
- * Updates a specific Feed.
- *
- * @param context Used for requesting the download.
- * @param feed The Feed object.
- */
- public static void refreshFeed(Context context, Feed feed)
- throws DownloadRequestException {
- Feed f;
- if (feed.getPreferences() == null) {
- f = new Feed(feed.getDownload_url(), new Date(), feed.getTitle());
- } else {
- f = new Feed(feed.getDownload_url(), new Date(), feed.getTitle(),
- feed.getPreferences().getUsername(), feed.getPreferences().getPassword());
- }
- f.setId(feed.getId());
- DownloadRequester.getInstance().downloadFeed(context, f);
- }
-
- /**
- * Notifies the database about a missing FeedImage file. This method will attempt to re-download the file.
- *
- * @param context Used for requesting the download.
- * @param image The FeedImage object.
- */
- public static void notifyInvalidImageFile(final Context context,
- final FeedImage image) {
- Log.i(TAG,
- "The DB was notified about an invalid image download. It will now try to re-download the image file");
- try {
- DownloadRequester.getInstance().downloadImage(context, image);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- Log.w(TAG, "Failed to download invalid feed image");
- }
- }
-
- /**
- * Notifies the database about a missing FeedMedia file. This method will correct the FeedMedia object's values in the
- * DB and send a FeedUpdateBroadcast.
- */
- public static void notifyMissingFeedMediaFile(final Context context,
- final FeedMedia media) {
- Log.i(TAG,
- "The feedmanager was notified about a missing episode. It will update its database now.");
- media.setDownloaded(false);
- media.setFile_url(null);
- DBWriter.setFeedMedia(context, media);
- EventDistributor.getInstance().sendFeedUpdateBroadcast();
- }
-
- /**
- * Request the download of all objects in the queue. from a separate Thread.
- *
- * @param context Used for requesting the download an accessing the database.
- */
- public static void downloadAllItemsInQueue(final Context context) {
- new Thread() {
- public void run() {
- List<FeedItem> queue = DBReader.getQueue(context);
- if (!queue.isEmpty()) {
- try {
- downloadFeedItems(context,
- queue.toArray(new FeedItem[queue.size()]));
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- }
- }
- }
- }.start();
- }
-
- /**
- * Requests the download of a list of FeedItem objects.
- *
- * @param context Used for requesting the download and accessing the DB.
- * @param items The FeedItem objects.
- */
- public static void downloadFeedItems(final Context context,
- FeedItem... items) throws DownloadRequestException {
- downloadFeedItems(true, context, items);
- }
-
- private static void downloadFeedItems(boolean performAutoCleanup,
- final Context context, final FeedItem... items)
- throws DownloadRequestException {
- final DownloadRequester requester = DownloadRequester.getInstance();
-
- if (performAutoCleanup) {
- new Thread() {
-
- @Override
- public void run() {
- performAutoCleanup(context,
- getPerformAutoCleanupArgs(context, items.length));
- }
-
- }.start();
- }
- for (FeedItem item : items) {
- if (item.getMedia() != null
- && !requester.isDownloadingFile(item.getMedia())
- && !item.getMedia().isDownloaded()) {
- if (items.length > 1) {
- try {
- requester.downloadMedia(context, item.getMedia());
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DBWriter.addDownloadStatus(context,
- new DownloadStatus(item.getMedia(), item
- .getMedia()
- .getHumanReadableIdentifier(),
- DownloadError.ERROR_REQUEST_ERROR,
- false, e.getMessage()
- )
- );
- }
- } else {
- requester.downloadMedia(context, item.getMedia());
- }
- }
- }
- }
-
- private static int getNumberOfUndownloadedEpisodes(
- final List<FeedItem> queue, final List<FeedItem> unreadItems) {
- int counter = 0;
- for (FeedItem item : queue) {
- if (item.hasMedia() && !item.getMedia().isDownloaded()
- && !item.getMedia().isPlaying()
- && item.getFeed().getPreferences().getAutoDownload()) {
- counter++;
- }
- }
- for (FeedItem item : unreadItems) {
- if (item.hasMedia() && !item.getMedia().isDownloaded()
- && item.getFeed().getPreferences().getAutoDownload()) {
- counter++;
- }
- }
- return counter;
- }
-
- /**
- * Looks for undownloaded episodes in the queue or list of unread items and request a download if
- * 1. Network is available
- * 2. There is free space in the episode cache
- * This method is executed on an internal single thread executor.
- *
- * @param context Used for accessing the DB.
- * @param mediaIds If this list is not empty, the method will only download a candidate for automatic downloading if
- * its media ID is in the mediaIds list.
- * @return A Future that can be used for waiting for the methods completion.
- */
- public static Future<?> autodownloadUndownloadedItems(final Context context, final long... mediaIds) {
- return autodownloadExec.submit(new Runnable() {
- @Override
- public void run() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Performing auto-dl of undownloaded episodes");
- if (NetworkUtils.autodownloadNetworkAvailable(context)
- && UserPreferences.isEnableAutodownload()) {
- final List<FeedItem> queue = DBReader.getQueue(context);
- final List<FeedItem> unreadItems = DBReader
- .getUnreadItemsList(context);
-
- int undownloadedEpisodes = getNumberOfUndownloadedEpisodes(queue,
- unreadItems);
- int downloadedEpisodes = DBReader
- .getNumberOfDownloadedEpisodes(context);
- int deletedEpisodes = performAutoCleanup(context,
- getPerformAutoCleanupArgs(context, undownloadedEpisodes));
- int episodeSpaceLeft = undownloadedEpisodes;
- boolean cacheIsUnlimited = UserPreferences.getEpisodeCacheSize() == UserPreferences
- .getEpisodeCacheSizeUnlimited();
-
- if (!cacheIsUnlimited
- && UserPreferences.getEpisodeCacheSize() < downloadedEpisodes
- + undownloadedEpisodes) {
- episodeSpaceLeft = UserPreferences.getEpisodeCacheSize()
- - (downloadedEpisodes - deletedEpisodes);
- }
-
- Arrays.sort(mediaIds); // sort for binary search
- final boolean ignoreMediaIds = mediaIds.length == 0;
- List<FeedItem> itemsToDownload = new ArrayList<FeedItem>();
-
- if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) {
- for (int i = 0; i < queue.size(); i++) { // ignore playing item
- FeedItem item = queue.get(i);
- long mediaId = (item.hasMedia()) ? item.getMedia().getId() : -1;
- if ((ignoreMediaIds || Arrays.binarySearch(mediaIds, mediaId) >= 0)
- && item.hasMedia()
- && !item.getMedia().isDownloaded()
- && !item.getMedia().isPlaying()
- && item.getFeed().getPreferences().getAutoDownload()) {
- itemsToDownload.add(item);
- episodeSpaceLeft--;
- undownloadedEpisodes--;
- if (episodeSpaceLeft == 0 || undownloadedEpisodes == 0) {
- break;
- }
- }
- }
- }
-
- if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) {
- for (FeedItem item : unreadItems) {
- long mediaId = (item.hasMedia()) ? item.getMedia().getId() : -1;
- if ((ignoreMediaIds || Arrays.binarySearch(mediaIds, mediaId) >= 0)
- && item.hasMedia()
- && !item.getMedia().isDownloaded()
- && item.getFeed().getPreferences().getAutoDownload()) {
- itemsToDownload.add(item);
- episodeSpaceLeft--;
- undownloadedEpisodes--;
- if (episodeSpaceLeft == 0 || undownloadedEpisodes == 0) {
- break;
- }
- }
- }
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Enqueueing " + itemsToDownload.size()
- + " items for download");
-
- try {
- downloadFeedItems(false, context,
- itemsToDownload.toArray(new FeedItem[itemsToDownload
- .size()])
- );
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- }
-
- }
- }
- });
-
- }
-
- private static int getPerformAutoCleanupArgs(Context context,
- final int episodeNumber) {
- if (episodeNumber >= 0
- && UserPreferences.getEpisodeCacheSize() != UserPreferences
- .getEpisodeCacheSizeUnlimited()) {
- int downloadedEpisodes = DBReader
- .getNumberOfDownloadedEpisodes(context);
- if (downloadedEpisodes + episodeNumber >= UserPreferences
- .getEpisodeCacheSize()) {
-
- return downloadedEpisodes + episodeNumber
- - UserPreferences.getEpisodeCacheSize();
- }
- }
- return 0;
- }
-
- /**
- * Removed downloaded episodes outside of the queue if the episode cache is full. Episodes with a smaller
- * 'playbackCompletionDate'-value will be deleted first.
- * <p/>
- * This method should NOT be executed on the GUI thread.
- *
- * @param context Used for accessing the DB.
- */
- public static void performAutoCleanup(final Context context) {
- performAutoCleanup(context, getPerformAutoCleanupArgs(context, 0));
- }
-
- private static int performAutoCleanup(final Context context,
- final int episodeNumber) {
- List<FeedItem> candidates = new ArrayList<FeedItem>();
- List<FeedItem> downloadedItems = DBReader.getDownloadedItems(context);
- QueueAccess queue = QueueAccess.IDListAccess(DBReader.getQueueIDList(context));
- List<FeedItem> delete;
- for (FeedItem item : downloadedItems) {
- if (item.hasMedia() && item.getMedia().isDownloaded()
- && !queue.contains(item.getId()) && item.isRead()) {
- candidates.add(item);
- }
-
- }
-
- Collections.sort(candidates, new Comparator<FeedItem>() {
- @Override
- public int compare(FeedItem lhs, FeedItem rhs) {
- Date l = lhs.getMedia().getPlaybackCompletionDate();
- Date r = rhs.getMedia().getPlaybackCompletionDate();
-
- if (l == null) {
- l = new Date(0);
- }
- if (r == null) {
- r = new Date(0);
- }
- return l.compareTo(r);
- }
- });
-
- if (candidates.size() > episodeNumber) {
- delete = candidates.subList(0, episodeNumber);
- } else {
- delete = candidates;
- }
-
- for (FeedItem item : delete) {
- try {
- DBWriter.deleteFeedMediaOfItem(context, item.getMedia().getId()).get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
-
- int counter = delete.size();
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, String.format(
- "Auto-delete deleted %d episodes (%d requested)", counter,
- episodeNumber));
-
- return counter;
- }
-
- /**
- * Adds all FeedItem objects whose 'read'-attribute is false to the queue in a separate thread.
- */
- public static void enqueueAllNewItems(final Context context) {
- long[] unreadItems = DBReader.getUnreadItemIds(context);
- DBWriter.addQueueItem(context, unreadItems);
- }
-
- /**
- * Returns the successor of a FeedItem in the queue.
- *
- * @param context Used for accessing the DB.
- * @param itemId ID of the FeedItem
- * @param queue Used for determining the successor of the item. If this parameter is null, the method will load
- * the queue from the database in the same thread.
- * @return Successor of the FeedItem or null if the FeedItem is not in the queue or has no successor.
- */
- public static FeedItem getQueueSuccessorOfItem(Context context,
- final long itemId, List<FeedItem> queue) {
- FeedItem result = null;
- if (queue == null) {
- queue = DBReader.getQueue(context);
- }
- if (queue != null) {
- Iterator<FeedItem> iterator = queue.iterator();
- while (iterator.hasNext()) {
- FeedItem item = iterator.next();
- if (item.getId() == itemId) {
- if (iterator.hasNext()) {
- result = iterator.next();
- }
- break;
- }
- }
- }
- return result;
- }
-
- /**
- * Loads the queue from the database and checks if the specified FeedItem is in the queue.
- * This method should NOT be executed in the GUI thread.
- *
- * @param context Used for accessing the DB.
- * @param feedItemId ID of the FeedItem
- */
- public static boolean isInQueue(Context context, final long feedItemId) {
- List<Long> queue = DBReader.getQueueIDList(context);
- return QueueAccess.IDListAccess(queue).contains(feedItemId);
- }
-
- private static Feed searchFeedByIdentifyingValueOrID(Context context, PodDBAdapter adapter,
- Feed feed) {
- if (feed.getId() != 0) {
- return DBReader.getFeed(context, feed.getId(), adapter);
- } else {
- List<Feed> feeds = DBReader.getFeedList(context);
- for (Feed f : feeds) {
- if (f.getIdentifyingValue().equals(feed.getIdentifyingValue())) {
- f.setItems(DBReader.getFeedItemList(context, f));
- return f;
- }
- }
- }
- return null;
- }
-
- /**
- * Get a FeedItem by its identifying value.
- */
- private static FeedItem searchFeedItemByIdentifyingValue(Feed feed,
- String identifier) {
- for (FeedItem item : feed.getItems()) {
- if (item.getIdentifyingValue().equals(identifier)) {
- return item;
- }
- }
- return null;
- }
-
- /**
- * Adds new Feeds to the database or updates the old versions if they already exists. If another Feed with the same
- * identifying value already exists, this method will add new FeedItems from the new Feed to the existing Feed.
- * These FeedItems will be marked as unread.
- * <p/>
- * This method can update multiple feeds at once. Submitting a feed twice in the same method call can result in undefined behavior.
- * <p/>
- * This method should NOT be executed on the GUI thread.
- *
- * @param context Used for accessing the DB.
- * @param newFeeds The new Feed objects.
- * @return The updated Feeds from the database if it already existed, or the new Feed from the parameters otherwise.
- */
- public static synchronized Feed[] updateFeed(final Context context,
- final Feed... newFeeds) {
- List<Feed> newFeedsList = new ArrayList<Feed>();
- List<Feed> updatedFeedsList = new ArrayList<Feed>();
- Feed[] resultFeeds = new Feed[newFeeds.length];
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
-
- for (int feedIdx = 0; feedIdx < newFeeds.length; feedIdx++) {
-
- final Feed newFeed = newFeeds[feedIdx];
-
- // Look up feed in the feedslist
- final Feed savedFeed = searchFeedByIdentifyingValueOrID(context, adapter,
- newFeed);
- if (savedFeed == null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Found no existing Feed with title "
- + newFeed.getTitle() + ". Adding as new one."
- );
- // Add a new Feed
- newFeedsList.add(newFeed);
- resultFeeds[feedIdx] = newFeed;
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Feed with title " + newFeed.getTitle()
- + " already exists. Syncing new with existing one.");
-
- Collections.sort(newFeed.getItems(), new FeedItemPubdateComparator());
- if (savedFeed.compareWithOther(newFeed)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Feed has updated attribute values. Updating old feed's attributes");
- savedFeed.updateFromOther(newFeed);
- }
- if (savedFeed.getPreferences().compareWithOther(newFeed.getPreferences())) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Feed has updated preferences. Updating old feed's preferences");
- savedFeed.getPreferences().updateFromOther(newFeed.getPreferences());
- }
- // Look for new or updated Items
- for (int idx = 0; idx < newFeed.getItems().size(); idx++) {
- final FeedItem item = newFeed.getItems().get(idx);
- FeedItem oldItem = searchFeedItemByIdentifyingValue(savedFeed,
- item.getIdentifyingValue());
- if (oldItem == null) {
- // item is new
- final int i = idx;
- item.setFeed(savedFeed);
- savedFeed.getItems().add(i, item);
- item.setRead(false);
- } else {
- oldItem.updateFromOther(item);
- }
- }
- // update attributes
- savedFeed.setLastUpdate(newFeed.getLastUpdate());
- savedFeed.setType(newFeed.getType());
-
- updatedFeedsList.add(savedFeed);
- resultFeeds[feedIdx] = savedFeed;
- }
- }
-
- adapter.close();
-
- try {
- DBWriter.addNewFeed(context, newFeedsList.toArray(new Feed[newFeedsList.size()])).get();
- DBWriter.setCompleteFeed(context, updatedFeedsList.toArray(new Feed[updatedFeedsList.size()])).get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
-
- EventDistributor.getInstance().sendFeedUpdateBroadcast();
-
- return resultFeeds;
- }
-
- /**
- * Searches the titles of FeedItems of a specific Feed for a given
- * string.
- *
- * @param context Used for accessing the DB.
- * @param feedID The id of the feed whose items should be searched.
- * @param query The search string.
- * @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
- */
- public static FutureTask<List<FeedItem>> searchFeedItemTitle(final Context context,
- final long feedID, final String query) {
- return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) {
- @Override
- public void execute(PodDBAdapter adapter) {
- Cursor searchResult = adapter.searchItemTitles(feedID,
- query);
- List<FeedItem> items = DBReader.extractItemlistFromCursor(context, searchResult);
- DBReader.loadFeedDataOfFeedItemlist(context, items);
- setResult(items);
- searchResult.close();
- }
- });
- }
-
- /**
- * Searches the descriptions of FeedItems of a specific Feed for a given
- * string.
- *
- * @param context Used for accessing the DB.
- * @param feedID The id of the feed whose items should be searched.
- * @param query The search string
- * @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
- */
- public static FutureTask<List<FeedItem>> searchFeedItemDescription(final Context context,
- final long feedID, final String query) {
- return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) {
- @Override
- public void execute(PodDBAdapter adapter) {
- Cursor searchResult = adapter.searchItemDescriptions(feedID,
- query);
- List<FeedItem> items = DBReader.extractItemlistFromCursor(context, searchResult);
- DBReader.loadFeedDataOfFeedItemlist(context, items);
- setResult(items);
- searchResult.close();
- }
- });
- }
-
- /**
- * Searches the contentEncoded-value of FeedItems of a specific Feed for a given
- * string.
- *
- * @param context Used for accessing the DB.
- * @param feedID The id of the feed whose items should be searched.
- * @param query The search string
- * @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
- */
- public static FutureTask<List<FeedItem>> searchFeedItemContentEncoded(final Context context,
- final long feedID, final String query) {
- return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) {
- @Override
- public void execute(PodDBAdapter adapter) {
- Cursor searchResult = adapter.searchItemContentEncoded(feedID,
- query);
- List<FeedItem> items = DBReader.extractItemlistFromCursor(context, searchResult);
- DBReader.loadFeedDataOfFeedItemlist(context, items);
- setResult(items);
- searchResult.close();
- }
- });
- }
-
- /**
- * Searches chapters of the FeedItems of a specific Feed for a given string.
- *
- * @param context Used for accessing the DB.
- * @param feedID The id of the feed whose items should be searched.
- * @param query The search string
- * @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
- */
- public static FutureTask<List<FeedItem>> searchFeedItemChapters(final Context context,
- final long feedID, final String query) {
- return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) {
- @Override
- public void execute(PodDBAdapter adapter) {
- Cursor searchResult = adapter.searchItemChapters(feedID,
- query);
- List<FeedItem> items = DBReader.extractItemlistFromCursor(context, searchResult);
- DBReader.loadFeedDataOfFeedItemlist(context, items);
- setResult(items);
- searchResult.close();
- }
- });
- }
-
- /**
- * A runnable which should be used for database queries. The onCompletion
- * method is executed on the database executor to handle Cursors correctly.
- * This class automatically creates a PodDBAdapter object and closes it when
- * it is no longer in use.
- */
- static abstract class QueryTask<T> implements Callable<T> {
- private T result;
- private Context context;
-
- public QueryTask(Context context) {
- this.context = context;
- }
-
- @Override
- public T call() throws Exception {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- execute(adapter);
- adapter.close();
- return result;
- }
-
- public abstract void execute(PodDBAdapter adapter);
-
- protected void setResult(T result) {
- this.result = result;
- }
- }
-
- /**
- * Adds the given FeedItem to the flattr queue if the user is logged in. Otherwise, a dialog
- * will be opened that lets the user go either to the login screen or the website of the flattr thing.
- *
- * @param context
- * @param item
- */
- public static void flattrItemIfLoggedIn(Context context, FeedItem item) {
- if (FlattrUtils.hasToken()) {
- item.getFlattrStatus().setFlattrQueue();
- DBWriter.setFlattredStatus(context, item, true);
- } else {
- FlattrUtils.showNoTokenDialogOrRedirect(context, item.getPaymentLink());
- }
- }
-
- /**
- * Adds the given Feed to the flattr queue if the user is logged in. Otherwise, a dialog
- * will be opened that lets the user go either to the login screen or the website of the flattr thing.
- *
- * @param context
- * @param feed
- */
- public static void flattrFeedIfLoggedIn(Context context, Feed feed) {
- if (FlattrUtils.hasToken()) {
- feed.getFlattrStatus().setFlattrQueue();
- DBWriter.setFlattredStatus(context, feed, true);
- } else {
- FlattrUtils.showNoTokenDialogOrRedirect(context, feed.getPaymentLink());
- }
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/app/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
deleted file mode 100644
index 225f74c96..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
+++ /dev/null
@@ -1,974 +0,0 @@
-package de.danoeh.antennapod.core.storage;
-
-import android.app.backup.BackupManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.preference.PreferenceManager;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.asynctask.FlattrClickWorker;
-import de.danoeh.antennapod.core.feed.*;
-import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
-import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
-import de.danoeh.antennapod.core.service.download.DownloadStatus;
-import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.core.util.QueueAccess;
-import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
-import de.danoeh.antennapod.core.util.flattr.FlattrThing;
-import de.danoeh.antennapod.core.util.flattr.SimpleFlattrThing;
-import org.shredzone.flattr4j.model.Flattr;
-
-import java.io.File;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.ThreadFactory;
-
-/**
- * Provides methods for writing data to AntennaPod's database.
- * In general, DBWriter-methods will be executed on an internal ExecutorService.
- * Some methods return a Future-object which the caller can use for waiting for the method's completion. The returned Future's
- * will NOT contain any results.
- * The caller can also use the {@link EventDistributor} in order to be notified about the method's completion asynchronously.
- * This class will use the {@link EventDistributor} to notify listeners about changes in the database.
- */
-public class DBWriter {
- private static final String TAG = "DBWriter";
-
- private static final ExecutorService dbExec;
-
- static {
- dbExec = Executors.newSingleThreadExecutor(new ThreadFactory() {
-
- @Override
- public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setPriority(Thread.MIN_PRIORITY);
- return t;
- }
- });
- }
-
- private DBWriter() {
- }
-
- /**
- * Deletes a downloaded FeedMedia file from the storage device.
- *
- * @param context A context that is used for opening a database connection.
- * @param mediaId ID of the FeedMedia object whose downloaded file should be deleted.
- */
- public static Future<?> deleteFeedMediaOfItem(final Context context,
- final long mediaId) {
- return dbExec.submit(new Runnable() {
- @Override
- public void run() {
-
- final FeedMedia media = DBReader.getFeedMedia(context, mediaId);
- if (media != null) {
- Log.i(TAG, String.format("Requested to delete FeedMedia [id=%d, title=%s, downloaded=%s",
- media.getId(), media.getEpisodeTitle(), String.valueOf(media.isDownloaded())));
- boolean result = false;
- if (media.isDownloaded()) {
- // delete downloaded media file
- File mediaFile = new File(media.getFile_url());
- if (mediaFile.exists()) {
- result = mediaFile.delete();
- }
- media.setDownloaded(false);
- media.setFile_url(null);
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setMedia(media);
- adapter.close();
-
- // If media is currently being played, change playback
- // type to 'stream' and shutdown playback service
- SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(context);
- if (PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA) {
- if (media.getId() == PlaybackPreferences
- .getCurrentlyPlayingFeedMediaId()) {
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(
- PlaybackPreferences.PREF_CURRENT_EPISODE_IS_STREAM,
- true);
- editor.commit();
- }
- if (PlaybackPreferences
- .getCurrentlyPlayingFeedMediaId() == media
- .getId()) {
- context.sendBroadcast(new Intent(
- PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
- }
- }
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Deleting File. Result: " + result);
- EventDistributor.getInstance().sendQueueUpdateBroadcast();
- EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
- }
- }
- });
- }
-
- /**
- * Deletes a Feed and all downloaded files of its components like images and downloaded episodes.
- *
- * @param context A context that is used for opening a database connection.
- * @param feedId ID of the Feed that should be deleted.
- */
- public static Future<?> deleteFeed(final Context context, final long feedId) {
- return dbExec.submit(new Runnable() {
- @Override
- public void run() {
- DownloadRequester requester = DownloadRequester.getInstance();
- SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(context
- .getApplicationContext());
- final Feed feed = DBReader.getFeed(context, feedId);
- if (feed != null) {
- if (PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA
- && PlaybackPreferences.getLastPlayedFeedId() == feed
- .getId()) {
- context.sendBroadcast(new Intent(
- PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
- SharedPreferences.Editor editor = prefs.edit();
- editor.putLong(
- PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID,
- -1);
- editor.commit();
- }
-
- // delete image file
- if (feed.getImage() != null) {
- if (feed.getImage().isDownloaded()
- && feed.getImage().getFile_url() != null) {
- File imageFile = new File(feed.getImage()
- .getFile_url());
- imageFile.delete();
- } else if (requester.isDownloadingFile(feed.getImage())) {
- requester.cancelDownload(context, feed.getImage());
- }
- }
- // delete stored media files and mark them as read
- List<FeedItem> queue = DBReader.getQueue(context);
- boolean queueWasModified = false;
- if (feed.getItems() == null) {
- DBReader.getFeedItemList(context, feed);
- }
-
- for (FeedItem item : feed.getItems()) {
- queueWasModified |= queue.remove(item);
- if (item.getMedia() != null
- && item.getMedia().isDownloaded()) {
- File mediaFile = new File(item.getMedia()
- .getFile_url());
- mediaFile.delete();
- } else if (item.getMedia() != null
- && requester.isDownloadingFile(item.getMedia())) {
- requester.cancelDownload(context, item.getMedia());
- }
-
- if (item.hasItemImage()) {
- FeedImage image = item.getImage();
- if (image.isDownloaded() && image.getFile_url() != null) {
- File imgFile = new File(image.getFile_url());
- imgFile.delete();
- } else if (requester.isDownloadingFile(image)) {
- requester.cancelDownload(context, item.getImage());
- }
- }
- }
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- if (queueWasModified) {
- adapter.setQueue(queue);
- }
- adapter.removeFeed(feed);
- adapter.close();
-
- GpodnetPreferences.addRemovedFeed(feed.getDownload_url());
- EventDistributor.getInstance().sendFeedUpdateBroadcast();
-
- BackupManager backupManager = new BackupManager(context);
- backupManager.dataChanged();
- }
- }
- });
- }
-
- /**
- * Deletes the entire playback history.
- *
- * @param context A context that is used for opening a database connection.
- */
- public static Future<?> clearPlaybackHistory(final Context context) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.clearPlaybackHistory();
- adapter.close();
- EventDistributor.getInstance()
- .sendPlaybackHistoryUpdateBroadcast();
- }
- });
- }
-
- /**
- * Adds a FeedMedia object to the playback history. A FeedMedia object is in the playback history if
- * its playback completion date is set to a non-null value. This method will set the playback completion date to the
- * current date regardless of the current value.
- *
- * @param context A context that is used for opening a database connection.
- * @param media FeedMedia that should be added to the playback history.
- */
- public static Future<?> addItemToPlaybackHistory(final Context context,
- final FeedMedia media) {
- return dbExec.submit(new Runnable() {
- @Override
- public void run() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Adding new item to playback history");
- media.setPlaybackCompletionDate(new Date());
- // reset played_duration to 0 so that it behaves correctly when the episode is played again
- media.setPlayedDuration(0);
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setFeedMediaPlaybackCompletionDate(media);
- adapter.close();
- EventDistributor.getInstance().sendPlaybackHistoryUpdateBroadcast();
-
- }
- });
- }
-
- private static void cleanupDownloadLog(final PodDBAdapter adapter) {
- final long logSize = adapter.getDownloadLogSize();
- if (logSize > DBReader.DOWNLOAD_LOG_SIZE) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Cleaning up download log");
- adapter.removeDownloadLogItems(logSize - DBReader.DOWNLOAD_LOG_SIZE);
- }
- }
-
- /**
- * Adds a Download status object to the download log.
- *
- * @param context A context that is used for opening a database connection.
- * @param status The DownloadStatus object.
- */
- public static Future<?> addDownloadStatus(final Context context,
- final DownloadStatus status) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setDownloadStatus(status);
- adapter.close();
- EventDistributor.getInstance().sendDownloadLogUpdateBroadcast();
- }
- });
-
- }
-
- /**
- * Inserts a FeedItem in the queue at the specified index. The 'read'-attribute of the FeedItem will be set to
- * true. If the FeedItem is already in the queue, the queue will not be modified.
- *
- * @param context A context that is used for opening a database connection.
- * @param itemId ID of the FeedItem that should be added to the queue.
- * @param index Destination index. Must be in range 0..queue.size()
- * @param performAutoDownload True if an auto-download process should be started after the operation
- * @throws IndexOutOfBoundsException if index < 0 || index >= queue.size()
- */
- public static Future<?> addQueueItemAt(final Context context, final long itemId,
- final int index, final boolean performAutoDownload) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- final PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- final List<FeedItem> queue = DBReader
- .getQueue(context, adapter);
- FeedItem item = null;
-
- if (queue != null) {
- boolean queueModified = false;
- boolean unreadItemsModified = false;
-
- if (!itemListContains(queue, itemId)) {
- item = DBReader.getFeedItem(context, itemId);
- if (item != null) {
- queue.add(index, item);
- queueModified = true;
- if (!item.isRead()) {
- item.setRead(true);
- unreadItemsModified = true;
- }
- }
- }
- if (queueModified) {
- adapter.setQueue(queue);
- EventDistributor.getInstance()
- .sendQueueUpdateBroadcast();
- }
- if (unreadItemsModified && item != null) {
- adapter.setSingleFeedItem(item);
- EventDistributor.getInstance()
- .sendUnreadItemsUpdateBroadcast();
- }
- }
- adapter.close();
- if (performAutoDownload) {
- DBTasks.autodownloadUndownloadedItems(context);
- }
-
- }
- });
-
- }
-
- /**
- * Appends FeedItem objects to the end of the queue. The 'read'-attribute of all items will be set to true.
- * If a FeedItem is already in the queue, the FeedItem will not change its position in the queue.
- *
- * @param context A context that is used for opening a database connection.
- * @param itemIds IDs of the FeedItem objects that should be added to the queue.
- */
- public static Future<?> addQueueItem(final Context context,
- final long... itemIds) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- if (itemIds.length > 0) {
- final PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- final List<FeedItem> queue = DBReader.getQueue(context,
- adapter);
-
- if (queue != null) {
- boolean queueModified = false;
- boolean unreadItemsModified = false;
- List<FeedItem> itemsToSave = new LinkedList<FeedItem>();
- for (int i = 0; i < itemIds.length; i++) {
- if (!itemListContains(queue, itemIds[i])) {
- final FeedItem item = DBReader.getFeedItem(
- context, itemIds[i]);
-
- if (item != null) {
- queue.add(item);
- queueModified = true;
- if (!item.isRead()) {
- item.setRead(true);
- itemsToSave.add(item);
- unreadItemsModified = true;
- }
- }
- }
- }
- if (queueModified) {
- adapter.setQueue(queue);
- EventDistributor.getInstance()
- .sendQueueUpdateBroadcast();
- }
- if (unreadItemsModified) {
- adapter.setFeedItemlist(itemsToSave);
- EventDistributor.getInstance()
- .sendUnreadItemsUpdateBroadcast();
- }
- }
- adapter.close();
- DBTasks.autodownloadUndownloadedItems(context);
- }
- }
- });
-
- }
-
- /**
- * Removes all FeedItem objects from the queue.
- *
- * @param context A context that is used for opening a database connection.
- */
- public static Future<?> clearQueue(final Context context) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.clearQueue();
- adapter.close();
-
- EventDistributor.getInstance().sendQueueUpdateBroadcast();
- }
- });
- }
-
- /**
- * Removes a FeedItem object from the queue.
- *
- * @param context A context that is used for opening a database connection.
- * @param itemId ID of the FeedItem that should be removed.
- * @param performAutoDownload true if an auto-download process should be started after the operation.
- */
- public static Future<?> removeQueueItem(final Context context,
- final long itemId, final boolean performAutoDownload) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- final PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- final List<FeedItem> queue = DBReader
- .getQueue(context, adapter);
- FeedItem item = null;
-
- if (queue != null) {
- boolean queueModified = false;
- QueueAccess queueAccess = QueueAccess.ItemListAccess(queue);
- if (queueAccess.contains(itemId)) {
- item = DBReader.getFeedItem(context, itemId);
- if (item != null) {
- queueModified = queueAccess.remove(itemId);
- }
- }
- if (queueModified) {
- adapter.setQueue(queue);
- EventDistributor.getInstance()
- .sendQueueUpdateBroadcast();
- } else {
- Log.w(TAG, "Queue was not modified by call to removeQueueItem");
- }
- } else {
- Log.e(TAG, "removeQueueItem: Could not load queue");
- }
- adapter.close();
- if (performAutoDownload) {
- DBTasks.autodownloadUndownloadedItems(context);
- }
- }
- });
-
- }
-
- /**
- * Moves the specified item to the top of the queue.
- *
- * @param context A context that is used for opening a database connection.
- * @param itemId The item to move to the top of the queue
- * @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to
- * false if the caller wants to avoid unexpected updates of the GUI.
- */
- public static Future<?> moveQueueItemToTop(final Context context, final long itemId, final boolean broadcastUpdate) {
- return dbExec.submit(new Runnable() {
- @Override
- public void run() {
- List<Long> queueIdList = DBReader.getQueueIDList(context);
- int currentLocation = 0;
- for (long id : queueIdList) {
- if (id == itemId) {
- moveQueueItemHelper(context, currentLocation, 0, broadcastUpdate);
- return;
- }
- currentLocation++;
- }
- Log.e(TAG, "moveQueueItemToTop: item not found");
- }
- });
- }
-
- /**
- * Moves the specified item to the bottom of the queue.
- *
- * @param context A context that is used for opening a database connection.
- * @param itemId The item to move to the bottom of the queue
- * @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to
- * false if the caller wants to avoid unexpected updates of the GUI.
- */
- public static Future<?> moveQueueItemToBottom(final Context context, final long itemId,
- final boolean broadcastUpdate) {
- return dbExec.submit(new Runnable() {
- @Override
- public void run() {
- List<Long> queueIdList = DBReader.getQueueIDList(context);
- int currentLocation = 0;
- for (long id : queueIdList) {
- if (id == itemId) {
- moveQueueItemHelper(context, currentLocation, queueIdList.size() - 1,
- broadcastUpdate);
- return;
- }
- currentLocation++;
- }
- Log.e(TAG, "moveQueueItemToBottom: item not found");
- }
- });
- }
-
- /**
- * Changes the position of a FeedItem in the queue.
- *
- * @param context A context that is used for opening a database connection.
- * @param from Source index. Must be in range 0..queue.size()-1.
- * @param to Destination index. Must be in range 0..queue.size()-1.
- * @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to
- * false if the caller wants to avoid unexpected updates of the GUI.
- * @throws IndexOutOfBoundsException if (to < 0 || to >= queue.size()) || (from < 0 || from >= queue.size())
- */
- public static Future<?> moveQueueItem(final Context context, final int from,
- final int to, final boolean broadcastUpdate) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- moveQueueItemHelper(context, from, to, broadcastUpdate);
- }
- });
- }
-
- /**
- * Changes the position of a FeedItem in the queue.
- * <p/>
- * This function must be run using the ExecutorService (dbExec).
- *
- * @param context A context that is used for opening a database connection.
- * @param from Source index. Must be in range 0..queue.size()-1.
- * @param to Destination index. Must be in range 0..queue.size()-1.
- * @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to
- * false if the caller wants to avoid unexpected updates of the GUI.
- * @throws IndexOutOfBoundsException if (to < 0 || to >= queue.size()) || (from < 0 || from >= queue.size())
- */
- private static void moveQueueItemHelper(final Context context, final int from,
- final int to, final boolean broadcastUpdate) {
- final PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- final List<FeedItem> queue = DBReader
- .getQueue(context, adapter);
-
- if (queue != null) {
- if (from >= 0 && from < queue.size() && to >= 0
- && to < queue.size()) {
-
- final FeedItem item = queue.remove(from);
- queue.add(to, item);
-
- adapter.setQueue(queue);
- if (broadcastUpdate) {
- EventDistributor.getInstance()
- .sendQueueUpdateBroadcast();
- }
-
- }
- } else {
- Log.e(TAG, "moveQueueItemHelper: Could not load queue");
- }
- adapter.close();
- }
-
- /**
- * Sets the 'read'-attribute of a FeedItem to the specified value.
- *
- * @param context A context that is used for opening a database connection.
- * @param item The FeedItem object
- * @param read New value of the 'read'-attribute
- * @param resetMediaPosition true if this method should also reset the position of the FeedItem's FeedMedia object.
- * If the FeedItem has no FeedMedia object, this parameter will be ignored.
- */
- public static Future<?> markItemRead(Context context, FeedItem item, boolean read, boolean resetMediaPosition) {
- long mediaId = (item.hasMedia()) ? item.getMedia().getId() : 0;
- return markItemRead(context, item.getId(), read, mediaId, resetMediaPosition);
- }
-
- /**
- * Sets the 'read'-attribute of a FeedItem to the specified value.
- *
- * @param context A context that is used for opening a database connection.
- * @param itemId ID of the FeedItem
- * @param read New value of the 'read'-attribute
- */
- public static Future<?> markItemRead(final Context context, final long itemId,
- final boolean read) {
- return markItemRead(context, itemId, read, 0, false);
- }
-
- private static Future<?> markItemRead(final Context context, final long itemId,
- final boolean read, final long mediaId,
- final boolean resetMediaPosition) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- final PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setFeedItemRead(read, itemId, mediaId,
- resetMediaPosition);
- adapter.close();
-
- EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
- }
- });
- }
-
- /**
- * Sets the 'read'-attribute of all FeedItems of a specific Feed to true.
- *
- * @param context A context that is used for opening a database connection.
- * @param feedId ID of the Feed.
- */
- public static Future<?> markFeedRead(final Context context, final long feedId) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- final PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- Cursor itemCursor = adapter.getAllItemsOfFeedCursor(feedId);
- long[] itemIds = new long[itemCursor.getCount()];
- itemCursor.moveToFirst();
- for (int i = 0; i < itemIds.length; i++) {
- itemIds[i] = itemCursor.getLong(PodDBAdapter.KEY_ID_INDEX);
- itemCursor.moveToNext();
- }
- itemCursor.close();
- adapter.setFeedItemRead(true, itemIds);
- adapter.close();
-
- EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
- }
- });
-
- }
-
- /**
- * Sets the 'read'-attribute of all FeedItems to true.
- *
- * @param context A context that is used for opening a database connection.
- */
- public static Future<?> markAllItemsRead(final Context context) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- final PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- Cursor itemCursor = adapter.getUnreadItemsCursor();
- long[] itemIds = new long[itemCursor.getCount()];
- itemCursor.moveToFirst();
- for (int i = 0; i < itemIds.length; i++) {
- itemIds[i] = itemCursor.getLong(PodDBAdapter.KEY_ID_INDEX);
- itemCursor.moveToNext();
- }
- itemCursor.close();
- adapter.setFeedItemRead(true, itemIds);
- adapter.close();
-
- EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
- }
- });
-
- }
-
- static Future<?> addNewFeed(final Context context, final Feed... feeds) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- final PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setCompleteFeed(feeds);
- adapter.close();
-
- for (Feed feed : feeds) {
- GpodnetPreferences.addAddedFeed(feed.getDownload_url());
- }
-
- BackupManager backupManager = new BackupManager(context);
- backupManager.dataChanged();
- }
- });
- }
-
- static Future<?> setCompleteFeed(final Context context, final Feed... feeds) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setCompleteFeed(feeds);
- adapter.close();
-
- }
- });
-
- }
-
- /**
- * Saves a FeedMedia object in the database. This method will save all attributes of the FeedMedia object. The
- * contents of FeedComponent-attributes (e.g. the FeedMedia's 'item'-attribute) will not be saved.
- *
- * @param context A context that is used for opening a database connection.
- * @param media The FeedMedia object.
- */
- public static Future<?> setFeedMedia(final Context context,
- final FeedMedia media) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setMedia(media);
- adapter.close();
- }
- });
- }
-
- /**
- * Saves the 'position' and 'duration' attributes of a FeedMedia object
- *
- * @param context A context that is used for opening a database connection.
- * @param media The FeedMedia object.
- */
- public static Future<?> setFeedMediaPlaybackInformation(final Context context, final FeedMedia media) {
- return dbExec.submit(new Runnable() {
- @Override
- public void run() {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setFeedMediaPlaybackInformation(media);
- adapter.close();
- }
- });
- }
-
- /**
- * Saves a FeedItem object in the database. This method will save all attributes of the FeedItem object including
- * the content of FeedComponent-attributes.
- *
- * @param context A context that is used for opening a database connection.
- * @param item The FeedItem object.
- */
- public static Future<?> setFeedItem(final Context context,
- final FeedItem item) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setSingleFeedItem(item);
- adapter.close();
- }
- });
- }
-
- /**
- * Saves a FeedImage object in the database. This method will save all attributes of the FeedImage object. The
- * contents of FeedComponent-attributes (e.g. the FeedImages's 'feed'-attribute) will not be saved.
- *
- * @param context A context that is used for opening a database connection.
- * @param image The FeedImage object.
- */
- public static Future<?> setFeedImage(final Context context,
- final FeedImage image) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setImage(image);
- adapter.close();
- }
- });
- }
-
- /**
- * Updates download URLs of feeds from a given Map. The key of the Map is the original URL of the feed
- * and the value is the updated URL
- */
- public static Future<?> updateFeedDownloadURLs(final Context context, final Map<String, String> urls) {
- return dbExec.submit(new Runnable() {
- @Override
- public void run() {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- for (String key : urls.keySet()) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Replacing URL " + key + " with url " + urls.get(key));
-
- adapter.setFeedDownloadUrl(key, urls.get(key));
- }
- adapter.close();
- }
- });
- }
-
- /**
- * Saves a FeedPreferences object in the database. The Feed ID of the FeedPreferences-object MUST NOT be 0.
- *
- * @param context Used for opening a database connection.
- * @param preferences The FeedPreferences object.
- */
- public static Future<?> setFeedPreferences(final Context context, final FeedPreferences preferences) {
- return dbExec.submit(new Runnable() {
- @Override
- public void run() {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setFeedPreferences(preferences);
- adapter.close();
- EventDistributor.getInstance().sendFeedUpdateBroadcast();
- }
- });
- }
-
- private static boolean itemListContains(List<FeedItem> items, long itemId) {
- for (FeedItem item : items) {
- if (item.getId() == itemId) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Saves the FlattrStatus of a FeedItem object in the database.
- *
- * @param startFlattrClickWorker true if FlattrClickWorker should be started after the FlattrStatus has been saved
- */
- public static Future<?> setFeedItemFlattrStatus(final Context context,
- final FeedItem item,
- final boolean startFlattrClickWorker) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setFeedItemFlattrStatus(item);
- adapter.close();
- if (startFlattrClickWorker) {
- new FlattrClickWorker(context).executeAsync();
- }
- }
- });
- }
-
- /**
- * Saves the FlattrStatus of a Feed object in the database.
- *
- * @param startFlattrClickWorker true if FlattrClickWorker should be started after the FlattrStatus has been saved
- */
- private static Future<?> setFeedFlattrStatus(final Context context,
- final Feed feed,
- final boolean startFlattrClickWorker) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setFeedFlattrStatus(feed);
- adapter.close();
- if (startFlattrClickWorker) {
- new FlattrClickWorker(context).executeAsync();
- }
- }
- });
- }
-
- /**
- * format an url for querying the database
- * (postfix a / and apply percent-encoding)
- */
- private static String formatURIForQuery(String uri) {
- try {
- return URLEncoder.encode(uri.endsWith("/") ? uri.substring(0, uri.length() - 1) : uri, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- Log.e(TAG, e.getMessage());
- return "";
- }
- }
-
-
- /**
- * Set flattr status of the passed thing (either a FeedItem or a Feed)
- *
- * @param context
- * @param thing
- * @param startFlattrClickWorker true if FlattrClickWorker should be started after the FlattrStatus has been saved
- * @return
- */
- public static Future<?> setFlattredStatus(Context context, FlattrThing thing, boolean startFlattrClickWorker) {
- // must propagate this to back db
- if (thing instanceof FeedItem)
- return setFeedItemFlattrStatus(context, (FeedItem) thing, startFlattrClickWorker);
- else if (thing instanceof Feed)
- return setFeedFlattrStatus(context, (Feed) thing, startFlattrClickWorker);
- else if (thing instanceof SimpleFlattrThing) {
- } // SimpleFlattrThings are generated on the fly and do not have DB backing
- else
- Log.e(TAG, "flattrQueue processing - thing is neither FeedItem nor Feed nor SimpleFlattrThing");
-
- return null;
- }
-
- /**
- * Reset flattr status to unflattrd for all items
- */
- public static Future<?> clearAllFlattrStatus(final Context context) {
- Log.d(TAG, "clearAllFlattrStatus()");
- return dbExec.submit(new Runnable() {
- @Override
- public void run() {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.clearAllFlattrStatus();
- adapter.close();
- }
- });
- }
-
- /**
- * Set flattr status of the feeds/feeditems in flattrList to flattred at the given timestamp,
- * where the information has been retrieved from the flattr API
- */
- public static Future<?> setFlattredStatus(final Context context, final List<Flattr> flattrList) {
- Log.d(TAG, "setFlattredStatus to status retrieved from flattr api running with " + flattrList.size() + " items");
- // clear flattr status in db
- clearAllFlattrStatus(context);
-
- // submit list with flattred things having normalized URLs to db
- return dbExec.submit(new Runnable() {
- @Override
- public void run() {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- for (Flattr flattr : flattrList) {
- adapter.setItemFlattrStatus(formatURIForQuery(flattr.getThing().getUrl()), new FlattrStatus(flattr.getCreated().getTime()));
- }
- adapter.close();
- }
- });
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequestException.java b/app/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequestException.java
deleted file mode 100644
index c85559e20..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequestException.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package de.danoeh.antennapod.core.storage;
-
-/**
- * Thrown by the DownloadRequester if a download request contains invalid data
- * or something went wrong while processing the request.
- */
-public class DownloadRequestException extends Exception {
-
- public DownloadRequestException() {
- super();
- }
-
- public DownloadRequestException(String detailMessage, Throwable throwable) {
- super(detailMessage, throwable);
- }
-
- public DownloadRequestException(String detailMessage) {
- super(detailMessage);
- }
-
- public DownloadRequestException(Throwable throwable) {
- super(throwable);
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java b/app/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java
deleted file mode 100644
index c313055a5..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java
+++ /dev/null
@@ -1,366 +0,0 @@
-package de.danoeh.antennapod.core.storage;
-
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-import android.webkit.URLUtil;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.feed.*;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.service.download.DownloadRequest;
-import de.danoeh.antennapod.core.service.download.DownloadService;
-import de.danoeh.antennapod.core.util.FileNameGenerator;
-import de.danoeh.antennapod.core.util.URLChecker;
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.Validate;
-
-import java.io.File;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-
-/**
- * Sends download requests to the DownloadService. This class should always be used for starting downloads,
- * otherwise they won't work correctly.
- */
-public class DownloadRequester {
- private static final String TAG = "DownloadRequester";
-
- public static final String IMAGE_DOWNLOADPATH = "images/";
- public static final String FEED_DOWNLOADPATH = "cache/";
- public static final String MEDIA_DOWNLOADPATH = "media/";
-
- private static DownloadRequester downloader;
-
- Map<String, DownloadRequest> downloads;
-
- private DownloadRequester() {
- downloads = new ConcurrentHashMap<String, DownloadRequest>();
- }
-
- public static synchronized DownloadRequester getInstance() {
- if (downloader == null) {
- downloader = new DownloadRequester();
- }
- return downloader;
- }
-
- /**
- * Starts a new download with the given DownloadRequest. This method should only
- * be used from outside classes if the DownloadRequest was created by the DownloadService to
- * ensure that the data is valid. Use downloadFeed(), downloadImage() or downloadMedia() instead.
- *
- * @param context Context object for starting the DownloadService
- * @param request The DownloadRequest. If another DownloadRequest with the same source URL is already stored, this method
- * call will return false.
- * @return True if the download request was accepted, false otherwise.
- */
- public boolean download(Context context, DownloadRequest request) {
- Validate.notNull(context);
- Validate.notNull(request);
-
- if (downloads.containsKey(request.getSource())) {
- if (BuildConfig.DEBUG) Log.i(TAG, "DownloadRequest is already stored.");
- return false;
- }
- downloads.put(request.getSource(), request);
-
- Intent launchIntent = new Intent(context, DownloadService.class);
- launchIntent.putExtra(DownloadService.EXTRA_REQUEST, request);
- context.startService(launchIntent);
- EventDistributor.getInstance().sendDownloadQueuedBroadcast();
- return true;
- }
-
- private void download(Context context, FeedFile item, File dest,
- boolean overwriteIfExists, String username, String password, boolean deleteOnFailure) {
- if (!isDownloadingFile(item)) {
- if (!isFilenameAvailable(dest.toString()) || (deleteOnFailure && dest.exists())) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Filename already used.");
- if (isFilenameAvailable(dest.toString()) && overwriteIfExists) {
- boolean result = dest.delete();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Deleting file. Result: " + result);
- } else {
- // find different name
- File newDest = null;
- for (int i = 1; i < Integer.MAX_VALUE; i++) {
- String newName = FilenameUtils.getBaseName(dest
- .getName())
- + "-"
- + i
- + FilenameUtils.EXTENSION_SEPARATOR
- + FilenameUtils.getExtension(dest.getName());
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Testing filename " + newName);
- newDest = new File(dest.getParent(), newName);
- if (!newDest.exists()
- && isFilenameAvailable(newDest.toString())) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "File doesn't exist yet. Using "
- + newName);
- break;
- }
- }
- if (newDest != null) {
- dest = newDest;
- }
- }
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Requesting download of url " + item.getDownload_url());
- item.setDownload_url(URLChecker.prepareURL(item.getDownload_url()));
-
- DownloadRequest request = new DownloadRequest(dest.toString(),
- URLChecker.prepareURL(item.getDownload_url()), item.getHumanReadableIdentifier(),
- item.getId(), item.getTypeAsInt(), username, password, deleteOnFailure);
-
- download(context, request);
- } else {
- Log.e(TAG, "URL " + item.getDownload_url()
- + " is already being downloaded");
- }
- }
-
- /**
- * Returns true if a filename is available and false if it has already been
- * taken by another requested download.
- */
- private boolean isFilenameAvailable(String path) {
- for (String key : downloads.keySet()) {
- DownloadRequest r = downloads.get(key);
- if (StringUtils.equals(r.getDestination(), path)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, path
- + " is already used by another requested download");
- return false;
- }
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, path + " is available as a download destination");
- return true;
- }
-
- public void downloadFeed(Context context, Feed feed)
- throws DownloadRequestException {
- if (feedFileValid(feed)) {
- String username = (feed.getPreferences() != null) ? feed.getPreferences().getUsername() : null;
- String password = (feed.getPreferences() != null) ? feed.getPreferences().getPassword() : null;
-
- download(context, feed, new File(getFeedfilePath(context),
- getFeedfileName(feed)), true, username, password, true);
- }
- }
-
- public void downloadImage(Context context, FeedImage image)
- throws DownloadRequestException {
- if (feedFileValid(image)) {
- download(context, image, new File(getImagefilePath(context),
- getImagefileName(image)), false, null, null, false);
- }
- }
-
- public void downloadMedia(Context context, FeedMedia feedmedia)
- throws DownloadRequestException {
- if (feedFileValid(feedmedia)) {
- Feed feed = feedmedia.getItem().getFeed();
- String username;
- String password;
- if (feed != null && feed.getPreferences() != null) {
- username = feed.getPreferences().getUsername();
- password = feed.getPreferences().getPassword();
- } else {
- username = null;
- password = null;
- }
-
- File dest;
- if (feedmedia.getFile_url() != null) {
- dest = new File(feedmedia.getFile_url());
- } else {
- dest = new File(getMediafilePath(context, feedmedia),
- getMediafilename(feedmedia));
- }
- download(context, feedmedia,
- dest, false, username, password, false
- );
- }
- }
-
- /**
- * Throws a DownloadRequestException if the feedfile or the download url of
- * the feedfile is null.
- *
- * @throws DownloadRequestException
- */
- private boolean feedFileValid(FeedFile f) throws DownloadRequestException {
- if (f == null) {
- throw new DownloadRequestException("Feedfile was null");
- } else if (f.getDownload_url() == null) {
- throw new DownloadRequestException("File has no download URL");
- } else {
- return true;
- }
- }
-
- /**
- * Cancels a running download.
- */
- public void cancelDownload(final Context context, final FeedFile f) {
- cancelDownload(context, f.getDownload_url());
- }
-
- /**
- * Cancels a running download.
- */
- public void cancelDownload(final Context context, final String downloadUrl) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Cancelling download with url " + downloadUrl);
- Intent cancelIntent = new Intent(DownloadService.ACTION_CANCEL_DOWNLOAD);
- cancelIntent.putExtra(DownloadService.EXTRA_DOWNLOAD_URL, downloadUrl);
- context.sendBroadcast(cancelIntent);
- }
-
- /**
- * Cancels all running downloads
- */
- public void cancelAllDownloads(Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Cancelling all running downloads");
- context.sendBroadcast(new Intent(
- DownloadService.ACTION_CANCEL_ALL_DOWNLOADS));
- }
-
- /**
- * Returns true if there is at least one Feed in the downloads queue.
- */
- public boolean isDownloadingFeeds() {
- for (DownloadRequest r : downloads.values()) {
- if (r.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Checks if feedfile is in the downloads list
- */
- public boolean isDownloadingFile(FeedFile item) {
- if (item.getDownload_url() != null) {
- return downloads.containsKey(item.getDownload_url());
- }
- return false;
- }
-
- public DownloadRequest getDownload(String downloadUrl) {
- return downloads.get(downloadUrl);
- }
-
- /**
- * Checks if feedfile with the given download url is in the downloads list
- */
- public boolean isDownloadingFile(String downloadUrl) {
- return downloads.get(downloadUrl) != null;
- }
-
- public boolean hasNoDownloads() {
- return downloads.isEmpty();
- }
-
- /**
- * Remove an object from the downloads-list of the requester.
- */
- public void removeDownload(DownloadRequest r) {
- if (downloads.remove(r.getSource()) == null) {
- Log.e(TAG,
- "Could not remove object with url " + r.getSource());
- }
- }
-
- /**
- * Get the number of uncompleted Downloads
- */
- public int getNumberOfDownloads() {
- return downloads.size();
- }
-
- public String getFeedfilePath(Context context)
- throws DownloadRequestException {
- return getExternalFilesDirOrThrowException(context, FEED_DOWNLOADPATH)
- .toString() + "/";
- }
-
- public String getFeedfileName(Feed feed) {
- String filename = feed.getDownload_url();
- if (feed.getTitle() != null && !feed.getTitle().isEmpty()) {
- filename = feed.getTitle();
- }
- return "feed-" + FileNameGenerator.generateFileName(filename);
- }
-
- public String getImagefilePath(Context context)
- throws DownloadRequestException {
- return getExternalFilesDirOrThrowException(context, IMAGE_DOWNLOADPATH)
- .toString() + "/";
- }
-
- public String getImagefileName(FeedImage image) {
- String filename = image.getDownload_url();
- if (image.getOwner() != null && image.getOwner().getHumanReadableIdentifier() != null) {
- filename = image.getOwner().getHumanReadableIdentifier();
- }
- return "image-" + FileNameGenerator.generateFileName(filename);
- }
-
- public String getMediafilePath(Context context, FeedMedia media)
- throws DownloadRequestException {
- File externalStorage = getExternalFilesDirOrThrowException(
- context,
- MEDIA_DOWNLOADPATH
- + FileNameGenerator.generateFileName(media.getItem()
- .getFeed().getTitle()) + "/"
- );
- return externalStorage.toString();
- }
-
- private File getExternalFilesDirOrThrowException(Context context,
- String type) throws DownloadRequestException {
- File result = UserPreferences.getDataFolder(context, type);
- if (result == null) {
- throw new DownloadRequestException(
- "Failed to access external storage");
- }
- return result;
- }
-
- public String getMediafilename(FeedMedia media) {
- String filename;
- String titleBaseFilename = "";
-
- // Try to generate the filename by the item title
- if (media.getItem() != null && media.getItem().getTitle() != null) {
- String title = media.getItem().getTitle();
- // Delete reserved characters
- titleBaseFilename = title.replaceAll("[\\\\/%\\?\\*:|<>\"\\p{Cntrl}]", "");
- titleBaseFilename = titleBaseFilename.trim();
- }
-
- String URLBaseFilename = URLUtil.guessFileName(media.getDownload_url(),
- null, media.getMime_type());
- ;
-
- if (titleBaseFilename != "") {
- // Append extension
- filename = titleBaseFilename + FilenameUtils.EXTENSION_SEPARATOR +
- FilenameUtils.getExtension(URLBaseFilename);
- } else {
- // Fall back on URL file name
- filename = URLBaseFilename;
- }
- return filename;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/storage/FeedItemStatistics.java b/app/src/main/java/de/danoeh/antennapod/core/storage/FeedItemStatistics.java
deleted file mode 100644
index f6a59836b..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/storage/FeedItemStatistics.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package de.danoeh.antennapod.core.storage;
-
-import java.util.Date;
-
-/**
- * Contains information about a feed's items.
- */
-public class FeedItemStatistics {
- private long feedID;
- private int numberOfItems;
- private int numberOfNewItems;
- private int numberOfInProgressItems;
- private Date lastUpdate;
- private static final Date UNKNOWN_DATE = new Date(0);
-
-
- /**
- * Creates new FeedItemStatistics object.
- *
- * @param feedID ID of the feed.
- * @param numberOfItems Number of items that this feed has.
- * @param numberOfNewItems Number of unread items this feed has.
- * @param numberOfInProgressItems Number of items that the user has started listening to.
- * @param lastUpdate pubDate of the latest episode. A lastUpdate value of 0 will be interpreted as DATE_UNKOWN if
- * numberOfItems is 0.
- */
- public FeedItemStatistics(long feedID, int numberOfItems, int numberOfNewItems, int numberOfInProgressItems, Date lastUpdate) {
- this.feedID = feedID;
- this.numberOfItems = numberOfItems;
- this.numberOfNewItems = numberOfNewItems;
- this.numberOfInProgressItems = numberOfInProgressItems;
- if (numberOfItems > 0) {
- this.lastUpdate = (lastUpdate != null) ? (Date) lastUpdate.clone() : null;
- } else {
- this.lastUpdate = UNKNOWN_DATE;
- }
- }
-
- public long getFeedID() {
- return feedID;
- }
-
- public int getNumberOfItems() {
- return numberOfItems;
- }
-
- public int getNumberOfNewItems() {
- return numberOfNewItems;
- }
-
- public int getNumberOfInProgressItems() {
- return numberOfInProgressItems;
- }
-
- /**
- * Returns the pubDate of the latest item in the feed. Users of this method
- * should check if this value is unkown or not by calling lastUpdateKnown() first.
- */
- public Date getLastUpdate() {
- return (lastUpdate != null) ? (Date) lastUpdate.clone() : null;
- }
-
- /**
- * Returns true if the lastUpdate value is known. The lastUpdate value is unkown if the
- * feed has no items.
- */
- public boolean lastUpdateKnown() {
- return lastUpdate != UNKNOWN_DATE;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java b/app/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java
deleted file mode 100644
index 41b379471..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package de.danoeh.antennapod.core.storage;
-
-import android.content.Context;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.feed.SearchResult;
-import de.danoeh.antennapod.core.util.comparator.SearchResultValueComparator;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
-
-/**
- * Performs search on Feeds and FeedItems
- */
-public class FeedSearcher {
- private static final String TAG = "FeedSearcher";
-
-
- /**
- * Performs a search in all feeds or one specific feed.
- */
- public static List<SearchResult> performSearch(final Context context,
- final String query, final long selectedFeed) {
- final int values[] = {0, 0, 1, 2};
- final String[] subtitles = {context.getString(R.string.found_in_shownotes_label),
- context.getString(R.string.found_in_shownotes_label),
- context.getString(R.string.found_in_chapters_label),
- context.getString(R.string.found_in_title_label)};
-
- List<SearchResult> result = new ArrayList<SearchResult>();
-
- FutureTask<List<FeedItem>>[] tasks = new FutureTask[4];
- (tasks[0] = DBTasks.searchFeedItemContentEncoded(context, selectedFeed, query)).run();
- (tasks[1] = DBTasks.searchFeedItemDescription(context, selectedFeed, query)).run();
- (tasks[2] = DBTasks.searchFeedItemChapters(context, selectedFeed, query)).run();
- (tasks[3] = DBTasks.searchFeedItemTitle(context, selectedFeed, query)).run();
- try {
- for (int i = 0; i < tasks.length; i++) {
- FutureTask task = tasks[i];
- List<FeedItem> items = (List<FeedItem>) task.get();
- for (FeedItem item : items) {
- result.add(new SearchResult(item, values[i], subtitles[i]));
- }
-
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- Collections.sort(result, new SearchResultValueComparator());
- return result;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/app/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
deleted file mode 100644
index eb6592510..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
+++ /dev/null
@@ -1,1391 +0,0 @@
-package de.danoeh.antennapod.core.storage;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.database.MergeCursor;
-import android.database.SQLException;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteDatabase.CursorFactory;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.util.Log;
-
-import org.apache.commons.lang3.Validate;
-
-import java.util.Arrays;
-import java.util.List;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.feed.Chapter;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedComponent;
-import de.danoeh.antennapod.core.feed.FeedImage;
-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.download.DownloadStatus;
-import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
-
-// TODO Remove media column from feeditem table
-
-/**
- * Implements methods for accessing the database
- */
-public class PodDBAdapter {
- private static final String TAG = "PodDBAdapter";
- private static final int DATABASE_VERSION = 12;
- public static final String DATABASE_NAME = "Antennapod.db";
-
- /**
- * Maximum number of arguments for IN-operator.
- */
- public static final int IN_OPERATOR_MAXIMUM = 800;
-
- /**
- * Maximum number of entries per search request.
- */
- public static final int SEARCH_LIMIT = 30;
-
- // ----------- Column indices
- // ----------- General indices
- public static final int KEY_ID_INDEX = 0;
- public static final int KEY_TITLE_INDEX = 1;
- public static final int KEY_FILE_URL_INDEX = 2;
- public static final int KEY_DOWNLOAD_URL_INDEX = 3;
- public static final int KEY_DOWNLOADED_INDEX = 4;
- public static final int KEY_LINK_INDEX = 5;
- public static final int KEY_DESCRIPTION_INDEX = 6;
- public static final int KEY_PAYMENT_LINK_INDEX = 7;
- // ----------- Feed indices
- public static final int KEY_LAST_UPDATE_INDEX = 8;
- public static final int KEY_LANGUAGE_INDEX = 9;
- public static final int KEY_AUTHOR_INDEX = 10;
- public static final int KEY_IMAGE_INDEX = 11;
- public static final int KEY_TYPE_INDEX = 12;
- public static final int KEY_FEED_IDENTIFIER_INDEX = 13;
- public static final int KEY_FEED_FLATTR_STATUS_INDEX = 14;
- public static final int KEY_FEED_USERNAME_INDEX = 15;
- public static final int KEY_FEED_PASSWORD_INDEX = 16;
- // ----------- FeedItem indices
- public static final int KEY_CONTENT_ENCODED_INDEX = 2;
- public static final int KEY_PUBDATE_INDEX = 3;
- public static final int KEY_READ_INDEX = 4;
- public static final int KEY_MEDIA_INDEX = 8;
- public static final int KEY_FEED_INDEX = 9;
- public static final int KEY_HAS_SIMPLECHAPTERS_INDEX = 10;
- public static final int KEY_ITEM_IDENTIFIER_INDEX = 11;
- public static final int KEY_ITEM_FLATTR_STATUS_INDEX = 12;
- // ---------- FeedMedia indices
- public static final int KEY_DURATION_INDEX = 1;
- public static final int KEY_POSITION_INDEX = 5;
- public static final int KEY_SIZE_INDEX = 6;
- public static final int KEY_MIME_TYPE_INDEX = 7;
- public static final int KEY_PLAYBACK_COMPLETION_DATE_INDEX = 8;
- public static final int KEY_MEDIA_FEEDITEM_INDEX = 9;
- public static final int KEY_PLAYED_DURATION_INDEX = 10;
- // --------- Download log indices
- public static final int KEY_FEEDFILE_INDEX = 1;
- public static final int KEY_FEEDFILETYPE_INDEX = 2;
- public static final int KEY_REASON_INDEX = 3;
- public static final int KEY_SUCCESSFUL_INDEX = 4;
- public static final int KEY_COMPLETION_DATE_INDEX = 5;
- public static final int KEY_REASON_DETAILED_INDEX = 6;
- public static final int KEY_DOWNLOADSTATUS_TITLE_INDEX = 7;
- // --------- Queue indices
- public static final int KEY_FEEDITEM_INDEX = 1;
- public static final int KEY_QUEUE_FEED_INDEX = 2;
- // --------- Chapters indices
- public static final int KEY_CHAPTER_START_INDEX = 2;
- public static final int KEY_CHAPTER_FEEDITEM_INDEX = 3;
- public static final int KEY_CHAPTER_LINK_INDEX = 4;
- public static final int KEY_CHAPTER_TYPE_INDEX = 5;
-
- // Key-constants
- public static final String KEY_ID = "id";
- public static final String KEY_TITLE = "title";
- public static final String KEY_NAME = "name";
- public static final String KEY_LINK = "link";
- public static final String KEY_DESCRIPTION = "description";
- public static final String KEY_FILE_URL = "file_url";
- public static final String KEY_DOWNLOAD_URL = "download_url";
- public static final String KEY_PUBDATE = "pubDate";
- public static final String KEY_READ = "read";
- public static final String KEY_DURATION = "duration";
- public static final String KEY_POSITION = "position";
- public static final String KEY_SIZE = "filesize";
- public static final String KEY_MIME_TYPE = "mime_type";
- public static final String KEY_IMAGE = "image";
- public static final String KEY_FEED = "feed";
- public static final String KEY_MEDIA = "media";
- public static final String KEY_DOWNLOADED = "downloaded";
- public static final String KEY_LASTUPDATE = "last_update";
- public static final String KEY_FEEDFILE = "feedfile";
- public static final String KEY_REASON = "reason";
- public static final String KEY_SUCCESSFUL = "successful";
- public static final String KEY_FEEDFILETYPE = "feedfile_type";
- public static final String KEY_COMPLETION_DATE = "completion_date";
- public static final String KEY_FEEDITEM = "feeditem";
- public static final String KEY_CONTENT_ENCODED = "content_encoded";
- public static final String KEY_PAYMENT_LINK = "payment_link";
- public static final String KEY_START = "start";
- public static final String KEY_LANGUAGE = "language";
- public static final String KEY_AUTHOR = "author";
- public static final String KEY_HAS_CHAPTERS = "has_simple_chapters";
- public static final String KEY_TYPE = "type";
- public static final String KEY_ITEM_IDENTIFIER = "item_identifier";
- public static final String KEY_FLATTR_STATUS = "flattr_status";
- public static final String KEY_FEED_IDENTIFIER = "feed_identifier";
- public static final String KEY_REASON_DETAILED = "reason_detailed";
- public static final String KEY_DOWNLOADSTATUS_TITLE = "title";
- public static final String KEY_CHAPTER_TYPE = "type";
- public static final String KEY_PLAYBACK_COMPLETION_DATE = "playback_completion_date";
- public static final String KEY_AUTO_DOWNLOAD = "auto_download";
- public static final String KEY_PLAYED_DURATION = "played_duration";
- public static final String KEY_USERNAME = "username";
- public static final String KEY_PASSWORD = "password";
-
- // Table names
- public static final String TABLE_NAME_FEEDS = "Feeds";
- public static final String TABLE_NAME_FEED_ITEMS = "FeedItems";
- public static final String TABLE_NAME_FEED_IMAGES = "FeedImages";
- public static final String TABLE_NAME_FEED_MEDIA = "FeedMedia";
- public static final String TABLE_NAME_DOWNLOAD_LOG = "DownloadLog";
- public static final String TABLE_NAME_QUEUE = "Queue";
- public static final String TABLE_NAME_SIMPLECHAPTERS = "SimpleChapters";
-
- // SQL Statements for creating new tables
- private static final String TABLE_PRIMARY_KEY = KEY_ID
- + " INTEGER PRIMARY KEY AUTOINCREMENT ,";
-
- private static final String CREATE_TABLE_FEEDS = "CREATE TABLE "
- + TABLE_NAME_FEEDS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
- + " TEXT," + KEY_FILE_URL + " TEXT," + KEY_DOWNLOAD_URL + " TEXT,"
- + KEY_DOWNLOADED + " INTEGER," + KEY_LINK + " TEXT,"
- + KEY_DESCRIPTION + " TEXT," + KEY_PAYMENT_LINK + " TEXT,"
- + KEY_LASTUPDATE + " TEXT," + KEY_LANGUAGE + " TEXT," + KEY_AUTHOR
- + " TEXT," + KEY_IMAGE + " INTEGER," + KEY_TYPE + " TEXT,"
- + KEY_FEED_IDENTIFIER + " TEXT," + KEY_AUTO_DOWNLOAD + " INTEGER DEFAULT 1,"
- + KEY_FLATTR_STATUS + " INTEGER,"
- + KEY_USERNAME + " TEXT,"
- + KEY_PASSWORD + " TEXT)";
-
- private static final String CREATE_TABLE_FEED_ITEMS = "CREATE TABLE "
- + TABLE_NAME_FEED_ITEMS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
- + " TEXT," + KEY_CONTENT_ENCODED + " TEXT," + KEY_PUBDATE
- + " INTEGER," + KEY_READ + " INTEGER," + KEY_LINK + " TEXT,"
- + KEY_DESCRIPTION + " TEXT," + KEY_PAYMENT_LINK + " TEXT,"
- + KEY_MEDIA + " INTEGER," + KEY_FEED + " INTEGER,"
- + KEY_HAS_CHAPTERS + " INTEGER," + KEY_ITEM_IDENTIFIER + " TEXT,"
- + KEY_FLATTR_STATUS + " INTEGER,"
- + KEY_IMAGE + " INTEGER)";
-
- private static final String CREATE_TABLE_FEED_IMAGES = "CREATE TABLE "
- + TABLE_NAME_FEED_IMAGES + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
- + " TEXT," + KEY_FILE_URL + " TEXT," + KEY_DOWNLOAD_URL + " TEXT,"
- + KEY_DOWNLOADED + " INTEGER)";
-
- private static final String CREATE_TABLE_FEED_MEDIA = "CREATE TABLE "
- + TABLE_NAME_FEED_MEDIA + " (" + TABLE_PRIMARY_KEY + KEY_DURATION
- + " INTEGER," + KEY_FILE_URL + " TEXT," + KEY_DOWNLOAD_URL
- + " TEXT," + KEY_DOWNLOADED + " INTEGER," + KEY_POSITION
- + " INTEGER," + KEY_SIZE + " INTEGER," + KEY_MIME_TYPE + " TEXT,"
- + KEY_PLAYBACK_COMPLETION_DATE + " INTEGER,"
- + KEY_FEEDITEM + " INTEGER,"
- + KEY_PLAYED_DURATION + " INTEGER)";
-
- private static final String CREATE_TABLE_DOWNLOAD_LOG = "CREATE TABLE "
- + TABLE_NAME_DOWNLOAD_LOG + " (" + TABLE_PRIMARY_KEY + KEY_FEEDFILE
- + " INTEGER," + KEY_FEEDFILETYPE + " INTEGER," + KEY_REASON
- + " INTEGER," + KEY_SUCCESSFUL + " INTEGER," + KEY_COMPLETION_DATE
- + " INTEGER," + KEY_REASON_DETAILED + " TEXT,"
- + KEY_DOWNLOADSTATUS_TITLE + " TEXT)";
-
- private static final String CREATE_TABLE_QUEUE = "CREATE TABLE "
- + TABLE_NAME_QUEUE + "(" + KEY_ID + " INTEGER PRIMARY KEY,"
- + KEY_FEEDITEM + " INTEGER," + KEY_FEED + " INTEGER)";
-
- private static final String CREATE_TABLE_SIMPLECHAPTERS = "CREATE TABLE "
- + TABLE_NAME_SIMPLECHAPTERS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
- + " TEXT," + KEY_START + " INTEGER," + KEY_FEEDITEM + " INTEGER,"
- + KEY_LINK + " TEXT," + KEY_CHAPTER_TYPE + " INTEGER)";
-
- private SQLiteDatabase db;
- private final Context context;
- private PodDBHelper helper;
-
- /**
- * Select all columns from the feed-table
- */
- private static final String[] FEED_SEL_STD = {
- TABLE_NAME_FEEDS + "." + KEY_ID,
- TABLE_NAME_FEEDS + "." + KEY_TITLE,
- TABLE_NAME_FEEDS + "." + KEY_FILE_URL,
- TABLE_NAME_FEEDS + "." + KEY_DOWNLOAD_URL,
- TABLE_NAME_FEEDS + "." + KEY_DOWNLOADED,
- TABLE_NAME_FEEDS + "." + KEY_LINK,
- TABLE_NAME_FEEDS + "." + KEY_DESCRIPTION,
- TABLE_NAME_FEEDS + "." + KEY_PAYMENT_LINK,
- TABLE_NAME_FEEDS + "." + KEY_LASTUPDATE,
- TABLE_NAME_FEEDS + "." + KEY_LANGUAGE,
- TABLE_NAME_FEEDS + "." + KEY_AUTHOR,
- TABLE_NAME_FEEDS + "." + KEY_IMAGE,
- TABLE_NAME_FEEDS + "." + KEY_TYPE,
- TABLE_NAME_FEEDS + "." + KEY_FEED_IDENTIFIER,
- TABLE_NAME_FEEDS + "." + KEY_AUTO_DOWNLOAD,
- TABLE_NAME_FEEDS + "." + KEY_FLATTR_STATUS,
- TABLE_NAME_FEEDS + "." + KEY_USERNAME,
- TABLE_NAME_FEEDS + "." + KEY_PASSWORD
- };
-
- // column indices for FEED_SEL_STD
- public static final int IDX_FEED_SEL_STD_ID = 0;
- public static final int IDX_FEED_SEL_STD_TITLE = 1;
- public static final int IDX_FEED_SEL_STD_FILE_URL = 2;
- public static final int IDX_FEED_SEL_STD_DOWNLOAD_URL = 3;
- public static final int IDX_FEED_SEL_STD_DOWNLOADED = 4;
- public static final int IDX_FEED_SEL_STD_LINK = 5;
- public static final int IDX_FEED_SEL_STD_DESCRIPTION = 6;
- public static final int IDX_FEED_SEL_STD_PAYMENT_LINK = 7;
- public static final int IDX_FEED_SEL_STD_LASTUPDATE = 8;
- public static final int IDX_FEED_SEL_STD_LANGUAGE = 9;
- public static final int IDX_FEED_SEL_STD_AUTHOR = 10;
- public static final int IDX_FEED_SEL_STD_IMAGE = 11;
- public static final int IDX_FEED_SEL_STD_TYPE = 12;
- public static final int IDX_FEED_SEL_STD_FEED_IDENTIFIER = 13;
- public static final int IDX_FEED_SEL_PREFERENCES_AUTO_DOWNLOAD = 14;
- public static final int IDX_FEED_SEL_STD_FLATTR_STATUS = 15;
- public static final int IDX_FEED_SEL_PREFERENCES_USERNAME = 16;
- public static final int IDX_FEED_SEL_PREFERENCES_PASSWORD = 17;
-
-
- /**
- * Select all columns from the feeditems-table except description and
- * content-encoded.
- */
- private static final String[] FEEDITEM_SEL_FI_SMALL = {
- TABLE_NAME_FEED_ITEMS + "." + KEY_ID,
- TABLE_NAME_FEED_ITEMS + "." + KEY_TITLE,
- TABLE_NAME_FEED_ITEMS + "." + KEY_PUBDATE,
- TABLE_NAME_FEED_ITEMS + "." + KEY_READ,
- TABLE_NAME_FEED_ITEMS + "." + KEY_LINK,
- TABLE_NAME_FEED_ITEMS + "." + KEY_PAYMENT_LINK, KEY_MEDIA,
- TABLE_NAME_FEED_ITEMS + "." + KEY_FEED,
- TABLE_NAME_FEED_ITEMS + "." + KEY_HAS_CHAPTERS,
- TABLE_NAME_FEED_ITEMS + "." + KEY_ITEM_IDENTIFIER,
- TABLE_NAME_FEED_ITEMS + "." + KEY_FLATTR_STATUS,
- TABLE_NAME_FEED_ITEMS + "." + KEY_IMAGE};
-
- /**
- * Contains FEEDITEM_SEL_FI_SMALL as comma-separated list. Useful for raw queries.
- */
- private static final String SEL_FI_SMALL_STR;
-
- static {
- String selFiSmall = Arrays.toString(FEEDITEM_SEL_FI_SMALL);
- SEL_FI_SMALL_STR = selFiSmall.substring(1, selFiSmall.length() - 1);
- }
-
- // column indices for FEEDITEM_SEL_FI_SMALL
-
- public static final int IDX_FI_SMALL_ID = 0;
- public static final int IDX_FI_SMALL_TITLE = 1;
- public static final int IDX_FI_SMALL_PUBDATE = 2;
- public static final int IDX_FI_SMALL_READ = 3;
- public static final int IDX_FI_SMALL_LINK = 4;
- public static final int IDX_FI_SMALL_PAYMENT_LINK = 5;
- public static final int IDX_FI_SMALL_MEDIA = 6;
- public static final int IDX_FI_SMALL_FEED = 7;
- public static final int IDX_FI_SMALL_HAS_CHAPTERS = 8;
- public static final int IDX_FI_SMALL_ITEM_IDENTIFIER = 9;
- public static final int IDX_FI_SMALL_FLATTR_STATUS = 10;
- public static final int IDX_FI_SMALL_IMAGE = 11;
-
- /**
- * Select id, description and content-encoded column from feeditems.
- */
- private static final String[] SEL_FI_EXTRA = {KEY_ID, KEY_DESCRIPTION,
- KEY_CONTENT_ENCODED, KEY_FEED};
-
- // column indices for SEL_FI_EXTRA
-
- public static final int IDX_FI_EXTRA_ID = 0;
- public static final int IDX_FI_EXTRA_DESCRIPTION = 1;
- public static final int IDX_FI_EXTRA_CONTENT_ENCODED = 2;
- public static final int IDX_FI_EXTRA_FEED = 3;
-
- static PodDBHelper dbHelperSingleton;
-
- private static synchronized PodDBHelper getDbHelperSingleton(Context appContext) {
- if (dbHelperSingleton == null) {
- dbHelperSingleton = new PodDBHelper(appContext, DATABASE_NAME, null, DATABASE_VERSION);
- }
- return dbHelperSingleton;
- }
-
- public PodDBAdapter(Context c) {
- this.context = c;
- helper = getDbHelperSingleton(c.getApplicationContext());
- }
-
- public PodDBAdapter open() {
- if (db == null || !db.isOpen() || db.isReadOnly()) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Opening DB");
- try {
- db = helper.getWritableDatabase();
- } catch (SQLException ex) {
- ex.printStackTrace();
- db = helper.getReadableDatabase();
- }
- }
- return this;
- }
-
- public void close() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Closing DB");
- //db.close();
- }
-
- public static boolean deleteDatabase(Context context) {
- Log.w(TAG, "Deleting database");
- dbHelperSingleton.close();
- dbHelperSingleton = null;
- return context.deleteDatabase(DATABASE_NAME);
- }
-
- /**
- * Inserts or updates a feed entry
- *
- * @return the id of the entry
- */
- public long setFeed(Feed feed) {
- ContentValues values = new ContentValues();
- values.put(KEY_TITLE, feed.getTitle());
- values.put(KEY_LINK, feed.getLink());
- values.put(KEY_DESCRIPTION, feed.getDescription());
- values.put(KEY_PAYMENT_LINK, feed.getPaymentLink());
- values.put(KEY_AUTHOR, feed.getAuthor());
- values.put(KEY_LANGUAGE, feed.getLanguage());
- if (feed.getImage() != null) {
- if (feed.getImage().getId() == 0) {
- setImage(feed.getImage());
- }
- values.put(KEY_IMAGE, feed.getImage().getId());
- }
-
- values.put(KEY_FILE_URL, feed.getFile_url());
- values.put(KEY_DOWNLOAD_URL, feed.getDownload_url());
- values.put(KEY_DOWNLOADED, feed.isDownloaded());
- values.put(KEY_LASTUPDATE, feed.getLastUpdate().getTime());
- values.put(KEY_TYPE, feed.getType());
- values.put(KEY_FEED_IDENTIFIER, feed.getFeedIdentifier());
-
- Log.d(TAG, "Setting feed with flattr status " + feed.getTitle() + ": " + feed.getFlattrStatus().toLong());
-
- values.put(KEY_FLATTR_STATUS, feed.getFlattrStatus().toLong());
- if (feed.getId() == 0) {
- // Create new entry
- if (BuildConfig.DEBUG)
- Log.d(this.toString(), "Inserting new Feed into db");
- feed.setId(db.insert(TABLE_NAME_FEEDS, null, values));
- } else {
- if (BuildConfig.DEBUG)
- Log.d(this.toString(), "Updating existing Feed in db");
- db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?",
- new String[]{String.valueOf(feed.getId())});
-
- }
- return feed.getId();
- }
-
- public void setFeedPreferences(FeedPreferences prefs) {
- if (prefs.getFeedID() == 0) {
- throw new IllegalArgumentException("Feed ID of preference must not be null");
- }
- ContentValues values = new ContentValues();
- values.put(KEY_AUTO_DOWNLOAD, prefs.getAutoDownload());
- values.put(KEY_USERNAME, prefs.getUsername());
- values.put(KEY_PASSWORD, prefs.getPassword());
- db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(prefs.getFeedID())});
- }
-
- /**
- * Inserts or updates an image entry
- *
- * @return the id of the entry
- */
- public long setImage(FeedImage image) {
- db.beginTransaction();
- ContentValues values = new ContentValues();
- values.put(KEY_TITLE, image.getTitle());
- values.put(KEY_DOWNLOAD_URL, image.getDownload_url());
- values.put(KEY_DOWNLOADED, image.isDownloaded());
- values.put(KEY_FILE_URL, image.getFile_url());
- if (image.getId() == 0) {
- image.setId(db.insert(TABLE_NAME_FEED_IMAGES, null, values));
- } else {
- db.update(TABLE_NAME_FEED_IMAGES, values, KEY_ID + "=?",
- new String[]{String.valueOf(image.getId())});
- }
-
- final FeedComponent owner = image.getOwner();
- if (owner != null && owner.getId() != 0) {
- values.clear();
- values.put(KEY_IMAGE, image.getId());
- if (owner instanceof Feed) {
- db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(image.getOwner().getId())});
- }
- }
- db.setTransactionSuccessful();
- db.endTransaction();
- return image.getId();
- }
-
- /**
- * Inserts or updates an image entry
- *
- * @return the id of the entry
- */
- public long setMedia(FeedMedia media) {
- ContentValues values = new ContentValues();
- values.put(KEY_DURATION, media.getDuration());
- values.put(KEY_POSITION, media.getPosition());
- values.put(KEY_SIZE, media.getSize());
- values.put(KEY_MIME_TYPE, media.getMime_type());
- values.put(KEY_DOWNLOAD_URL, media.getDownload_url());
- values.put(KEY_DOWNLOADED, media.isDownloaded());
- values.put(KEY_FILE_URL, media.getFile_url());
-
- if (media.getPlaybackCompletionDate() != null) {
- values.put(KEY_PLAYBACK_COMPLETION_DATE, media
- .getPlaybackCompletionDate().getTime());
- } else {
- values.put(KEY_PLAYBACK_COMPLETION_DATE, 0);
- }
- if (media.getItem() != null) {
- values.put(KEY_FEEDITEM, media.getItem().getId());
- }
- if (media.getId() == 0) {
- media.setId(db.insert(TABLE_NAME_FEED_MEDIA, null, values));
- } else {
- db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?",
- new String[]{String.valueOf(media.getId())});
- }
- return media.getId();
- }
-
- public void setFeedMediaPlaybackInformation(FeedMedia media) {
- if (media.getId() != 0) {
- ContentValues values = new ContentValues();
- values.put(KEY_POSITION, media.getPosition());
- values.put(KEY_DURATION, media.getDuration());
- values.put(KEY_PLAYED_DURATION, media.getPlayedDuration());
- db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?",
- new String[]{String.valueOf(media.getId())});
- } else {
- Log.e(TAG, "setFeedMediaPlaybackInformation: ID of media was 0");
- }
- }
-
- public void setFeedMediaPlaybackCompletionDate(FeedMedia media) {
- if (media.getId() != 0) {
- ContentValues values = new ContentValues();
- values.put(KEY_PLAYBACK_COMPLETION_DATE, media.getPlaybackCompletionDate().getTime());
- values.put(KEY_PLAYED_DURATION, media.getPlayedDuration());
- db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?",
- new String[]{String.valueOf(media.getId())});
- } else {
- Log.e(TAG, "setFeedMediaPlaybackCompletionDate: ID of media was 0");
- }
- }
-
- /**
- * Insert all FeedItems of a feed and the feed object itself in a single
- * transaction
- */
- public void setCompleteFeed(Feed... feeds) {
- db.beginTransaction();
- for (Feed feed : feeds) {
- setFeed(feed);
- if (feed.getItems() != null) {
- for (FeedItem item : feed.getItems()) {
- setFeedItem(item, false);
- }
- }
- if (feed.getPreferences() != null) {
- setFeedPreferences(feed.getPreferences());
- }
- }
- db.setTransactionSuccessful();
- db.endTransaction();
- }
-
- /**
- * Update the flattr status of a feed
- */
- public void setFeedFlattrStatus(Feed feed) {
- ContentValues values = new ContentValues();
- values.put(KEY_FLATTR_STATUS, feed.getFlattrStatus().toLong());
- db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(feed.getId())});
- }
-
- /**
- * Get all feeds in the flattr queue.
- */
- public Cursor getFeedsInFlattrQueueCursor() {
- return db.query(TABLE_NAME_FEEDS, FEED_SEL_STD, KEY_FLATTR_STATUS + "=?",
- new String[]{String.valueOf(FlattrStatus.STATUS_QUEUE)}, null, null, null);
- }
-
- /**
- * Get all feed items in the flattr queue.
- */
- public Cursor getFeedItemsInFlattrQueueCursor() {
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FLATTR_STATUS + "=?",
- new String[]{String.valueOf(FlattrStatus.STATUS_QUEUE)}, null, null, null);
- }
-
- /**
- * Counts feeds and feed items in the flattr queue
- */
- public int getFlattrQueueSize() {
- int res = 0;
- Cursor c = db.rawQuery(String.format("SELECT count(*) FROM %s WHERE %s=%s",
- TABLE_NAME_FEEDS, KEY_FLATTR_STATUS, String.valueOf(FlattrStatus.STATUS_QUEUE)), null);
- if (c.moveToFirst()) {
- res = c.getInt(0);
- c.close();
- } else {
- Log.e(TAG, "Unable to determine size of flattr queue: Could not count number of feeds");
- }
- c = db.rawQuery(String.format("SELECT count(*) FROM %s WHERE %s=%s",
- TABLE_NAME_FEED_ITEMS, KEY_FLATTR_STATUS, String.valueOf(FlattrStatus.STATUS_QUEUE)), null);
- if (c.moveToFirst()) {
- res += c.getInt(0);
- c.close();
- } else {
- Log.e(TAG, "Unable to determine size of flattr queue: Could not count number of feed items");
- }
-
- return res;
- }
-
- /**
- * Updates the download URL of a Feed.
- */
- public void setFeedDownloadUrl(String original, String updated) {
- ContentValues values = new ContentValues();
- values.put(KEY_DOWNLOAD_URL, updated);
- db.update(TABLE_NAME_FEEDS, values, KEY_DOWNLOAD_URL + "=?", new String[]{original});
- }
-
- public void setFeedItemlist(List<FeedItem> items) {
- db.beginTransaction();
- for (FeedItem item : items) {
- setFeedItem(item, true);
- }
- db.setTransactionSuccessful();
- db.endTransaction();
- }
-
- public long setSingleFeedItem(FeedItem item) {
- db.beginTransaction();
- long result = setFeedItem(item, true);
- db.setTransactionSuccessful();
- db.endTransaction();
- return result;
- }
-
- /**
- * Update the flattr status of a FeedItem
- */
- public void setFeedItemFlattrStatus(FeedItem feedItem) {
- ContentValues values = new ContentValues();
- values.put(KEY_FLATTR_STATUS, feedItem.getFlattrStatus().toLong());
- db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?", new String[]{String.valueOf(feedItem.getId())});
- }
-
- /**
- * Update the flattr status of a feed or feed item specified by its payment link
- * and the new flattr status to use
- */
- public void setItemFlattrStatus(String url, FlattrStatus status) {
- //Log.d(TAG, "setItemFlattrStatus(" + url + ") = " + status.toString());
- ContentValues values = new ContentValues();
- values.put(KEY_FLATTR_STATUS, status.toLong());
-
- // regexps in sqlite would be neat!
- String[] query_urls = new String[]{
- "*" + url + "&*",
- "*" + url + "%2F&*",
- "*" + url + "",
- "*" + url + "%2F"
- };
-
- if (db.update(TABLE_NAME_FEEDS, values,
- KEY_PAYMENT_LINK + " GLOB ?"
- + " OR " + KEY_PAYMENT_LINK + " GLOB ?"
- + " OR " + KEY_PAYMENT_LINK + " GLOB ?"
- + " OR " + KEY_PAYMENT_LINK + " GLOB ?", query_urls
- ) > 0) {
- Log.i(TAG, "setItemFlattrStatus found match for " + url + " = " + status.toLong() + " in Feeds table");
- return;
- }
- if (db.update(TABLE_NAME_FEED_ITEMS, values,
- KEY_PAYMENT_LINK + " GLOB ?"
- + " OR " + KEY_PAYMENT_LINK + " GLOB ?"
- + " OR " + KEY_PAYMENT_LINK + " GLOB ?"
- + " OR " + KEY_PAYMENT_LINK + " GLOB ?", query_urls
- ) > 0) {
- Log.i(TAG, "setItemFlattrStatus found match for " + url + " = " + status.toLong() + " in FeedsItems table");
- }
- }
-
- /**
- * Reset flattr status to unflattrd for all items
- */
- public void clearAllFlattrStatus() {
- ContentValues values = new ContentValues();
- values.put(KEY_FLATTR_STATUS, 0);
- db.update(TABLE_NAME_FEEDS, values, null, null);
- db.update(TABLE_NAME_FEED_ITEMS, values, null, null);
- }
-
- /**
- * Inserts or updates a feeditem entry
- *
- * @param item The FeedItem
- * @param saveFeed true if the Feed of the item should also be saved. This should be set to
- * false if the method is executed on a list of FeedItems of the same Feed.
- * @return the id of the entry
- */
- private long setFeedItem(FeedItem item, boolean saveFeed) {
- ContentValues values = new ContentValues();
- values.put(KEY_TITLE, item.getTitle());
- values.put(KEY_LINK, item.getLink());
- if (item.getDescription() != null) {
- values.put(KEY_DESCRIPTION, item.getDescription());
- }
- if (item.getContentEncoded() != null) {
- values.put(KEY_CONTENT_ENCODED, item.getContentEncoded());
- }
- values.put(KEY_PUBDATE, item.getPubDate().getTime());
- values.put(KEY_PAYMENT_LINK, item.getPaymentLink());
- if (saveFeed && item.getFeed() != null) {
- setFeed(item.getFeed());
- }
- values.put(KEY_FEED, item.getFeed().getId());
- values.put(KEY_READ, item.isRead());
- values.put(KEY_HAS_CHAPTERS, item.getChapters() != null);
- values.put(KEY_ITEM_IDENTIFIER, item.getItemIdentifier());
- values.put(KEY_FLATTR_STATUS, item.getFlattrStatus().toLong());
- if (item.hasItemImage()) {
- if (item.getImage().getId() == 0) {
- setImage(item.getImage());
- }
- values.put(KEY_IMAGE, item.getImage().getId());
- }
-
- if (item.getId() == 0) {
- item.setId(db.insert(TABLE_NAME_FEED_ITEMS, null, values));
- } else {
- db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?",
- new String[]{String.valueOf(item.getId())});
- }
- if (item.getMedia() != null) {
- setMedia(item.getMedia());
- }
- if (item.getChapters() != null) {
- setChapters(item);
- }
- return item.getId();
- }
-
- public void setFeedItemRead(boolean read, long itemId, long mediaId,
- boolean resetMediaPosition) {
- db.beginTransaction();
- ContentValues values = new ContentValues();
-
- values.put(KEY_READ, read);
- db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?", new String[]{String.valueOf(itemId)});
-
- if (resetMediaPosition) {
- values.clear();
- values.put(KEY_POSITION, 0);
- db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?", new String[]{String.valueOf(mediaId)});
- }
-
- db.setTransactionSuccessful();
- db.endTransaction();
- }
-
- public void setFeedItemRead(boolean read, long... itemIds) {
- db.beginTransaction();
- ContentValues values = new ContentValues();
- for (long id : itemIds) {
- values.clear();
- values.put(KEY_READ, read);
- db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?", new String[]{String.valueOf(id)});
- }
- db.setTransactionSuccessful();
- db.endTransaction();
- }
-
- public void setChapters(FeedItem item) {
- ContentValues values = new ContentValues();
- for (Chapter chapter : item.getChapters()) {
- values.put(KEY_TITLE, chapter.getTitle());
- values.put(KEY_START, chapter.getStart());
- values.put(KEY_FEEDITEM, item.getId());
- values.put(KEY_LINK, chapter.getLink());
- values.put(KEY_CHAPTER_TYPE, chapter.getChapterType());
- if (chapter.getId() == 0) {
- chapter.setId(db
- .insert(TABLE_NAME_SIMPLECHAPTERS, null, values));
- } else {
- db.update(TABLE_NAME_SIMPLECHAPTERS, values, KEY_ID + "=?",
- new String[]{String.valueOf(chapter.getId())});
- }
- }
- }
-
- /**
- * Inserts or updates a download status.
- */
- public long setDownloadStatus(DownloadStatus status) {
- ContentValues values = new ContentValues();
- values.put(KEY_FEEDFILE, status.getFeedfileId());
- values.put(KEY_FEEDFILETYPE, status.getFeedfileType());
- values.put(KEY_REASON, status.getReason().getCode());
- values.put(KEY_SUCCESSFUL, status.isSuccessful());
- values.put(KEY_COMPLETION_DATE, status.getCompletionDate().getTime());
- values.put(KEY_REASON_DETAILED, status.getReasonDetailed());
- values.put(KEY_DOWNLOADSTATUS_TITLE, status.getTitle());
- if (status.getId() == 0) {
- status.setId(db.insert(TABLE_NAME_DOWNLOAD_LOG, null, values));
- } else {
- db.update(TABLE_NAME_DOWNLOAD_LOG, values, KEY_ID + "=?",
- new String[]{String.valueOf(status.getId())});
- }
- return status.getId();
- }
-
- public long getDownloadLogSize() {
- final String query = String.format("SELECT COUNT(%s) FROM %s", KEY_ID, TABLE_NAME_DOWNLOAD_LOG);
- Cursor result = db.rawQuery(query, null);
- long count = 0;
- if (result.moveToFirst()) {
- count = result.getLong(0);
- }
- result.close();
- return count;
- }
-
- public void removeDownloadLogItems(long count) {
- if (count > 0) {
- final String sql = String.format("DELETE FROM %s WHERE %s in (SELECT %s from %s ORDER BY %s ASC LIMIT %d)",
- TABLE_NAME_DOWNLOAD_LOG, KEY_ID, KEY_ID, TABLE_NAME_DOWNLOAD_LOG, KEY_COMPLETION_DATE, count);
- db.execSQL(sql, null);
- }
- }
-
- public void setQueue(List<FeedItem> queue) {
- ContentValues values = new ContentValues();
- db.beginTransaction();
- db.delete(TABLE_NAME_QUEUE, null, null);
- for (int i = 0; i < queue.size(); i++) {
- FeedItem item = queue.get(i);
- values.put(KEY_ID, i);
- values.put(KEY_FEEDITEM, item.getId());
- values.put(KEY_FEED, item.getFeed().getId());
- db.insertWithOnConflict(TABLE_NAME_QUEUE, null, values,
- SQLiteDatabase.CONFLICT_REPLACE);
- }
- db.setTransactionSuccessful();
- db.endTransaction();
- }
-
- public void clearQueue() {
- db.delete(TABLE_NAME_QUEUE, null, null);
- }
-
- public void removeFeedMedia(FeedMedia media) {
- db.delete(TABLE_NAME_FEED_MEDIA, KEY_ID + "=?",
- new String[]{String.valueOf(media.getId())});
- }
-
- public void removeChaptersOfItem(FeedItem item) {
- db.delete(TABLE_NAME_SIMPLECHAPTERS, KEY_FEEDITEM + "=?",
- new String[]{String.valueOf(item.getId())});
- }
-
- public void removeFeedImage(FeedImage image) {
- db.delete(TABLE_NAME_FEED_IMAGES, KEY_ID + "=?",
- new String[]{String.valueOf(image.getId())});
- }
-
- /**
- * Remove a FeedItem and its FeedMedia entry.
- */
- public void removeFeedItem(FeedItem item) {
- if (item.getMedia() != null) {
- removeFeedMedia(item.getMedia());
- }
- if (item.getChapters() != null) {
- removeChaptersOfItem(item);
- }
- if (item.hasItemImage()) {
- removeFeedImage(item.getImage());
- }
- db.delete(TABLE_NAME_FEED_ITEMS, KEY_ID + "=?",
- new String[]{String.valueOf(item.getId())});
- }
-
- /**
- * Remove a feed with all its FeedItems and Media entries.
- */
- public void removeFeed(Feed feed) {
- db.beginTransaction();
- if (feed.getImage() != null) {
- removeFeedImage(feed.getImage());
- }
- if (feed.getItems() != null) {
- for (FeedItem item : feed.getItems()) {
- removeFeedItem(item);
- }
- }
-
- db.delete(TABLE_NAME_FEEDS, KEY_ID + "=?",
- new String[]{String.valueOf(feed.getId())});
- db.setTransactionSuccessful();
- db.endTransaction();
- }
-
- public void removeDownloadStatus(DownloadStatus remove) {
- db.delete(TABLE_NAME_DOWNLOAD_LOG, KEY_ID + "=?",
- new String[]{String.valueOf(remove.getId())});
- }
-
- public void clearPlaybackHistory() {
- ContentValues values = new ContentValues();
- values.put(KEY_PLAYBACK_COMPLETION_DATE, 0);
- db.update(TABLE_NAME_FEED_MEDIA, values, null, null);
- }
-
- /**
- * Get all Feeds from the Feed Table.
- *
- * @return The cursor of the query
- */
- public final Cursor getAllFeedsCursor() {
- Cursor c = db.query(TABLE_NAME_FEEDS, FEED_SEL_STD, null, null, null, null,
- KEY_TITLE + " COLLATE NOCASE ASC");
- return c;
- }
-
- public final Cursor getFeedCursorDownloadUrls() {
- return db.query(TABLE_NAME_FEEDS, new String[]{KEY_ID, KEY_DOWNLOAD_URL}, null, null, null, null, null);
- }
-
- public final Cursor getExpiredFeedsCursor(long expirationTime) {
- Cursor c = db.query(TABLE_NAME_FEEDS, FEED_SEL_STD, KEY_LASTUPDATE + " < " + String.valueOf(System.currentTimeMillis() - expirationTime),
- null, null, null,
- null);
- return c;
- }
-
- /**
- * Returns a cursor with all FeedItems of a Feed. Uses FEEDITEM_SEL_FI_SMALL
- *
- * @param feed The feed you want to get the FeedItems from.
- * @return The cursor of the query
- */
- public final Cursor getAllItemsOfFeedCursor(final Feed feed) {
- return getAllItemsOfFeedCursor(feed.getId());
- }
-
- public final Cursor getAllItemsOfFeedCursor(final long feedId) {
- Cursor c = db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED
- + "=?", new String[]{String.valueOf(feedId)}, null, null,
- null
- );
- return c;
- }
-
- /**
- * Return a cursor with the SEL_FI_EXTRA selection of a single feeditem.
- */
- public final Cursor getExtraInformationOfItem(final FeedItem item) {
- Cursor c = db
- .query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA, KEY_ID + "=?",
- new String[]{String.valueOf(item.getId())}, null,
- null, null);
- return c;
- }
-
- /**
- * Returns a cursor for a DB query in the FeedMedia table for a given ID.
- *
- * @param item The item you want to get the FeedMedia from
- * @return The cursor of the query
- */
- public final Cursor getFeedMediaOfItemCursor(final FeedItem item) {
- Cursor c = db.query(TABLE_NAME_FEED_MEDIA, null, KEY_ID + "=?",
- new String[]{String.valueOf(item.getMedia().getId())}, null,
- null, null);
- return c;
- }
-
- /**
- * Returns a cursor for a DB query in the FeedImages table for a given ID.
- *
- * @param id ID of the FeedImage
- * @return The cursor of the query
- */
- public final Cursor getImageCursor(final long id) {
- Cursor c = db.query(TABLE_NAME_FEED_IMAGES, null, KEY_ID + "=?",
- new String[]{String.valueOf(id)}, null, null, null);
- return c;
- }
-
- public final Cursor getSimpleChaptersOfFeedItemCursor(final FeedItem item) {
- Cursor c = db.query(TABLE_NAME_SIMPLECHAPTERS, null, KEY_FEEDITEM
- + "=?", new String[]{String.valueOf(item.getId())}, null,
- null, null
- );
- return c;
- }
-
- public final Cursor getDownloadLogCursor(final int limit) {
- Cursor c = db.query(TABLE_NAME_DOWNLOAD_LOG, null, null, null, null,
- null, KEY_COMPLETION_DATE + " DESC LIMIT " + limit);
- return c;
- }
-
- /**
- * Returns a cursor which contains all feed items in the queue. The returned
- * cursor uses the FEEDITEM_SEL_FI_SMALL selection.
- */
- public final Cursor getQueueCursor() {
- Object[] args = (Object[]) new String[]{
- SEL_FI_SMALL_STR + "," + TABLE_NAME_QUEUE + "." + KEY_ID,
- TABLE_NAME_FEED_ITEMS, TABLE_NAME_QUEUE,
- TABLE_NAME_FEED_ITEMS + "." + KEY_ID,
- TABLE_NAME_QUEUE + "." + KEY_FEEDITEM,
- TABLE_NAME_QUEUE + "." + KEY_ID};
- String query = String.format(
- "SELECT %s FROM %s INNER JOIN %s ON %s=%s ORDER BY %s", args);
- Cursor c = db.rawQuery(query, null);
- /*
- * Cursor c = db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL,
- * "INNER JOIN ? ON ?=?", new String[] { TABLE_NAME_QUEUE,
- * TABLE_NAME_FEED_ITEMS + "." + KEY_ID, TABLE_NAME_QUEUE + "." +
- * KEY_FEEDITEM }, null, null, TABLE_NAME_QUEUE + "." + KEY_FEEDITEM);
- */
- return c;
- }
-
- public Cursor getQueueIDCursor() {
- Cursor c = db.query(TABLE_NAME_QUEUE, new String[]{KEY_FEEDITEM}, null, null, null, null, KEY_ID + " ASC", null);
- return c;
- }
-
- /**
- * Returns a cursor which contains all feed items in the unread items list.
- * The returned cursor uses the FEEDITEM_SEL_FI_SMALL selection.
- */
- public final Cursor getUnreadItemsCursor() {
- Cursor c = db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_READ
- + "=0", null, null, null, KEY_PUBDATE + " DESC");
- return c;
- }
-
- public final Cursor getUnreadItemIdsCursor() {
- Cursor c = db.query(TABLE_NAME_FEED_ITEMS, new String[]{KEY_ID},
- KEY_READ + "=0", null, null, null, KEY_PUBDATE + " DESC");
- return c;
-
- }
-
- public final Cursor getRecentlyPublishedItemsCursor(int limit) {
- Cursor c = db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, null, null, null, null, KEY_PUBDATE + " DESC LIMIT " + limit);
- return c;
- }
-
- public Cursor getDownloadedItemsCursor() {
- final String query = "SELECT " + SEL_FI_SMALL_STR + " FROM " + TABLE_NAME_FEED_ITEMS
- + " INNER JOIN " + TABLE_NAME_FEED_MEDIA + " ON "
- + TABLE_NAME_FEED_ITEMS + "." + KEY_ID + "="
- + TABLE_NAME_FEED_MEDIA + "." + KEY_FEEDITEM + " WHERE "
- + TABLE_NAME_FEED_MEDIA + "." + KEY_DOWNLOADED + ">0";
- Cursor c = db.rawQuery(query, null);
- return c;
- }
-
- /**
- * Returns a cursor which contains feed media objects with a playback
- * completion date in ascending order.
- *
- * @param limit The maximum row count of the returned cursor. Must be an
- * integer >= 0.
- * @throws IllegalArgumentException if limit < 0
- */
- public final Cursor getCompletedMediaCursor(int limit) {
- Validate.isTrue(limit >= 0, "Limit must be >= 0");
-
- Cursor c = db.query(TABLE_NAME_FEED_MEDIA, null,
- KEY_PLAYBACK_COMPLETION_DATE + " > 0 LIMIT " + limit, null, null,
- null, null);
- return c;
- }
-
- public final Cursor getSingleFeedMediaCursor(long id) {
- return db.query(TABLE_NAME_FEED_MEDIA, null, KEY_ID + "=?", new String[]{String.valueOf(id)}, null, null, null);
- }
-
- public final Cursor getFeedMediaCursorByItemID(String... mediaIds) {
- int length = mediaIds.length;
- if (length > IN_OPERATOR_MAXIMUM) {
- Log.w(TAG, "Length of id array is larger than "
- + IN_OPERATOR_MAXIMUM + ". Creating multiple cursors");
- int numCursors = (int) (((double) length) / (IN_OPERATOR_MAXIMUM)) + 1;
- Cursor[] cursors = new Cursor[numCursors];
- for (int i = 0; i < numCursors; i++) {
- int neededLength = 0;
- String[] parts = null;
- final int elementsLeft = length - i * IN_OPERATOR_MAXIMUM;
-
- if (elementsLeft >= IN_OPERATOR_MAXIMUM) {
- neededLength = IN_OPERATOR_MAXIMUM;
- parts = Arrays.copyOfRange(mediaIds, i
- * IN_OPERATOR_MAXIMUM, (i + 1)
- * IN_OPERATOR_MAXIMUM);
- } else {
- neededLength = elementsLeft;
- parts = Arrays.copyOfRange(mediaIds, i
- * IN_OPERATOR_MAXIMUM, (i * IN_OPERATOR_MAXIMUM)
- + neededLength);
- }
-
- cursors[i] = db.rawQuery("SELECT * FROM "
- + TABLE_NAME_FEED_MEDIA + " WHERE " + KEY_FEEDITEM + " IN "
- + buildInOperator(neededLength), parts);
- }
- return new MergeCursor(cursors);
- } else {
- return db.query(TABLE_NAME_FEED_MEDIA, null, KEY_FEEDITEM + " IN "
- + buildInOperator(length), mediaIds, null, null, null);
- }
- }
-
- /**
- * Builds an IN-operator argument depending on the number of items.
- */
- private String buildInOperator(int size) {
- if (size == 1) {
- return "(?)";
- }
- StringBuffer buffer = new StringBuffer("(");
- for (int i = 0; i < size - 1; i++) {
- buffer.append("?,");
- }
- buffer.append("?)");
- return buffer.toString();
- }
-
- public final Cursor getFeedCursor(final long id) {
- Cursor c = db.query(TABLE_NAME_FEEDS, FEED_SEL_STD, KEY_ID + "=" + id, null,
- null, null, null);
- return c;
- }
-
- public final Cursor getFeedItemCursor(final String... ids) {
- if (ids.length > IN_OPERATOR_MAXIMUM) {
- throw new IllegalArgumentException(
- "number of IDs must not be larger than "
- + IN_OPERATOR_MAXIMUM
- );
- }
-
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_ID + " IN "
- + buildInOperator(ids.length), ids, null, null, null);
-
- }
-
- public int getQueueSize() {
- final String query = String.format("SELECT COUNT(%s) FROM %s", KEY_ID, TABLE_NAME_QUEUE);
- Cursor c = db.rawQuery(query, null);
- int result = 0;
- if (c.moveToFirst()) {
- result = c.getInt(0);
- }
- c.close();
- return result;
- }
-
- public final int getNumberOfUnreadItems() {
- final String query = "SELECT COUNT(DISTINCT " + KEY_ID + ") AS count FROM " + TABLE_NAME_FEED_ITEMS +
- " WHERE " + KEY_READ + " = 0";
- Cursor c = db.rawQuery(query, null);
- int result = 0;
- if (c.moveToFirst()) {
- result = c.getInt(0);
- }
- c.close();
- return result;
- }
-
- public final int getNumberOfDownloadedEpisodes() {
- final String query = "SELECT COUNT(DISTINCT " + KEY_ID + ") AS count FROM " + TABLE_NAME_FEED_MEDIA +
- " WHERE " + KEY_DOWNLOADED + " > 0";
-
- Cursor c = db.rawQuery(query, null);
- int result = 0;
- if (c.moveToFirst()) {
- result = c.getInt(0);
- }
- c.close();
- return result;
- }
-
- /**
- * Uses DatabaseUtils to escape a search query and removes ' at the
- * beginning and the end of the string returned by the escape method.
- */
- private String prepareSearchQuery(String query) {
- StringBuilder builder = new StringBuilder();
- DatabaseUtils.appendEscapedSQLString(builder, query);
- builder.deleteCharAt(0);
- builder.deleteCharAt(builder.length() - 1);
- return builder.toString();
- }
-
- /**
- * Searches for the given query in the description of all items or the items
- * of a specified feed.
- *
- * @return A cursor with all search results in SEL_FI_EXTRA selection.
- */
- public Cursor searchItemDescriptions(long feedID, String query) {
- if (feedID != 0) {
- // search items in specific feed
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED
- + "=? AND " + KEY_DESCRIPTION + " LIKE '%"
- + prepareSearchQuery(query) + "%'",
- new String[]{String.valueOf(feedID)}, null, null,
- null
- );
- } else {
- // search through all items
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL,
- KEY_DESCRIPTION + " LIKE '%" + prepareSearchQuery(query)
- + "%'", null, null, null, null
- );
- }
- }
-
- /**
- * Searches for the given query in the content-encoded field of all items or
- * the items of a specified feed.
- *
- * @return A cursor with all search results in SEL_FI_EXTRA selection.
- */
- public Cursor searchItemContentEncoded(long feedID, String query) {
- if (feedID != 0) {
- // search items in specific feed
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED
- + "=? AND " + KEY_CONTENT_ENCODED + " LIKE '%"
- + prepareSearchQuery(query) + "%'",
- new String[]{String.valueOf(feedID)}, null, null,
- null
- );
- } else {
- // search through all items
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL,
- KEY_CONTENT_ENCODED + " LIKE '%"
- + prepareSearchQuery(query) + "%'", null, null,
- null, null
- );
- }
- }
-
- public Cursor searchItemTitles(long feedID, String query) {
- if (feedID != 0) {
- // search items in specific feed
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED
- + "=? AND " + KEY_TITLE + " LIKE '%"
- + prepareSearchQuery(query) + "%'",
- new String[]{String.valueOf(feedID)}, null, null,
- null
- );
- } else {
- // search through all items
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL,
- KEY_TITLE + " LIKE '%"
- + prepareSearchQuery(query) + "%'", null, null,
- null, null
- );
- }
- }
-
- public Cursor searchItemChapters(long feedID, String searchQuery) {
- final String query;
- if (feedID != 0) {
- query = "SELECT " + SEL_FI_SMALL_STR + " FROM " + TABLE_NAME_FEED_ITEMS + " INNER JOIN " +
- TABLE_NAME_SIMPLECHAPTERS + " ON " + TABLE_NAME_SIMPLECHAPTERS + "." + KEY_FEEDITEM + "=" +
- TABLE_NAME_FEED_ITEMS + "." + KEY_ID + " WHERE " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" +
- feedID + " AND " + TABLE_NAME_SIMPLECHAPTERS + "." + KEY_TITLE + " LIKE '%"
- + prepareSearchQuery(searchQuery) + "%'";
- } else {
- query = "SELECT " + SEL_FI_SMALL_STR + " FROM " + TABLE_NAME_FEED_ITEMS + " INNER JOIN " +
- TABLE_NAME_SIMPLECHAPTERS + " ON " + TABLE_NAME_SIMPLECHAPTERS + "." + KEY_FEEDITEM + "=" +
- TABLE_NAME_FEED_ITEMS + "." + KEY_ID + " WHERE " + TABLE_NAME_SIMPLECHAPTERS + "." + KEY_TITLE + " LIKE '%"
- + prepareSearchQuery(searchQuery) + "%'";
- }
- return db.rawQuery(query, null);
- }
-
-
- public static final int IDX_FEEDSTATISTICS_FEED = 0;
- public static final int IDX_FEEDSTATISTICS_NUM_ITEMS = 1;
- public static final int IDX_FEEDSTATISTICS_NEW_ITEMS = 2;
- public static final int IDX_FEEDSTATISTICS_LATEST_EPISODE = 3;
- public static final int IDX_FEEDSTATISTICS_IN_PROGRESS_EPISODES = 4;
-
- /**
- * Select number of items, new items, the date of the latest episode and the number of episodes in progress. The result
- * is sorted by the title of the feed.
- */
- private static final String FEED_STATISTICS_QUERY = "SELECT Feeds.id, num_items, new_items, latest_episode, in_progress FROM " +
- " Feeds LEFT JOIN " +
- "(SELECT feed,count(*) AS num_items," +
- " COUNT(CASE WHEN read=0 THEN 1 END) AS new_items," +
- " MAX(pubDate) AS latest_episode," +
- " COUNT(CASE WHEN position>0 THEN 1 END) AS in_progress," +
- " COUNT(CASE WHEN downloaded=1 THEN 1 END) AS episodes_downloaded " +
- " FROM FeedItems LEFT JOIN FeedMedia ON FeedItems.id=FeedMedia.feeditem GROUP BY FeedItems.feed)" +
- " ON Feeds.id = feed ORDER BY Feeds.title COLLATE NOCASE ASC;";
-
- public Cursor getFeedStatisticsCursor() {
- return db.rawQuery(FEED_STATISTICS_QUERY, null);
- }
-
- /**
- * Helper class for opening the Antennapod database.
- */
- private static class PodDBHelper extends SQLiteOpenHelper {
- /**
- * Constructor.
- *
- * @param context Context to use
- * @param name Name of the database
- * @param factory to use for creating cursor objects
- * @param version number of the database
- */
- public PodDBHelper(final Context context, final String name,
- final CursorFactory factory, final int version) {
- super(context, name, factory, version);
- }
-
- @Override
- public void onCreate(final SQLiteDatabase db) {
- db.execSQL(CREATE_TABLE_FEEDS);
- db.execSQL(CREATE_TABLE_FEED_ITEMS);
- db.execSQL(CREATE_TABLE_FEED_IMAGES);
- db.execSQL(CREATE_TABLE_FEED_MEDIA);
- db.execSQL(CREATE_TABLE_DOWNLOAD_LOG);
- db.execSQL(CREATE_TABLE_QUEUE);
- db.execSQL(CREATE_TABLE_SIMPLECHAPTERS);
- }
-
- @Override
- public void onUpgrade(final SQLiteDatabase db, final int oldVersion,
- final int newVersion) { // TODO onUpgrade
- Log.w("DBAdapter", "Upgrading from version " + oldVersion + " to "
- + newVersion + ".");
- if (oldVersion <= 1) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS + " ADD COLUMN "
- + KEY_TYPE + " TEXT");
- }
- if (oldVersion <= 2) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_SIMPLECHAPTERS
- + " ADD COLUMN " + KEY_LINK + " TEXT");
- }
- if (oldVersion <= 3) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_ITEMS
- + " ADD COLUMN " + KEY_ITEM_IDENTIFIER + " TEXT");
- }
- if (oldVersion <= 4) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS + " ADD COLUMN "
- + KEY_FEED_IDENTIFIER + " TEXT");
- }
- if (oldVersion <= 5) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_DOWNLOAD_LOG
- + " ADD COLUMN " + KEY_REASON_DETAILED + " TEXT");
- db.execSQL("ALTER TABLE " + TABLE_NAME_DOWNLOAD_LOG
- + " ADD COLUMN " + KEY_DOWNLOADSTATUS_TITLE + " TEXT");
- }
- if (oldVersion <= 6) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_SIMPLECHAPTERS
- + " ADD COLUMN " + KEY_CHAPTER_TYPE + " INTEGER");
- }
- if (oldVersion <= 7) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_MEDIA
- + " ADD COLUMN " + KEY_PLAYBACK_COMPLETION_DATE
- + " INTEGER");
- }
- if (oldVersion <= 8) {
- final int KEY_ID_POSITION = 0;
- final int KEY_MEDIA_POSITION = 1;
-
- // Add feeditem column to feedmedia table
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_MEDIA
- + " ADD COLUMN " + KEY_FEEDITEM
- + " INTEGER");
- Cursor feeditemCursor = db.query(TABLE_NAME_FEED_ITEMS, new String[]{KEY_ID, KEY_MEDIA}, "? > 0", new String[]{KEY_MEDIA}, null, null, null);
- if (feeditemCursor.moveToFirst()) {
- db.beginTransaction();
- ContentValues contentValues = new ContentValues();
- do {
- long mediaId = feeditemCursor.getLong(KEY_MEDIA_POSITION);
- contentValues.put(KEY_FEEDITEM, feeditemCursor.getLong(KEY_ID_POSITION));
- db.update(TABLE_NAME_FEED_MEDIA, contentValues, KEY_ID + "=?", new String[]{String.valueOf(mediaId)});
- contentValues.clear();
- } while (feeditemCursor.moveToNext());
- db.setTransactionSuccessful();
- db.endTransaction();
- }
- feeditemCursor.close();
- }
- if (oldVersion <= 9) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS
- + " ADD COLUMN " + KEY_AUTO_DOWNLOAD
- + " INTEGER DEFAULT 1");
- }
- if (oldVersion <= 10) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS
- + " ADD COLUMN " + KEY_FLATTR_STATUS
- + " INTEGER");
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_ITEMS
- + " ADD COLUMN " + KEY_FLATTR_STATUS
- + " INTEGER");
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_MEDIA
- + " ADD COLUMN " + KEY_PLAYED_DURATION
- + " INTEGER");
- }
- if (oldVersion <= 11) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS
- + " ADD COLUMN " + KEY_USERNAME
- + " TEXT");
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS
- + " ADD COLUMN " + KEY_PASSWORD
- + " TEXT");
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_ITEMS
- + " ADD COLUMN " + KEY_IMAGE
- + " INTEGER");
- }
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/FeedHandler.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/FeedHandler.java
deleted file mode 100644
index 9efc5888f..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/FeedHandler.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package de.danoeh.antennapod.core.syndication.handler;
-
-import de.danoeh.antennapod.core.feed.Feed;
-import org.apache.commons.io.input.XmlStreamReader;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-import java.io.File;
-import java.io.IOException;
-import java.io.Reader;
-
-public class FeedHandler {
-
- public FeedHandlerResult parseFeed(Feed feed) throws SAXException, IOException,
- ParserConfigurationException, UnsupportedFeedtypeException {
- TypeGetter tg = new TypeGetter();
- TypeGetter.Type type = tg.getType(feed);
- SyndHandler handler = new SyndHandler(feed, type);
-
- SAXParserFactory factory = SAXParserFactory.newInstance();
- factory.setNamespaceAware(true);
- SAXParser saxParser = factory.newSAXParser();
- File file = new File(feed.getFile_url());
- Reader inputStreamReader = new XmlStreamReader(file);
- InputSource inputSource = new InputSource(inputStreamReader);
-
- saxParser.parse(inputSource, handler);
- inputStreamReader.close();
- return new FeedHandlerResult(handler.state.feed, handler.state.alternateUrls);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/FeedHandlerResult.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/FeedHandlerResult.java
deleted file mode 100644
index 45d1413bf..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/FeedHandlerResult.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package de.danoeh.antennapod.core.syndication.handler;
-
-import de.danoeh.antennapod.core.feed.Feed;
-
-import java.util.Map;
-
-/**
- * Container for results returned by the Feed parser
- */
-public class FeedHandlerResult {
-
- public Feed feed;
- public Map<String, String> alternateFeedUrls;
-
- public FeedHandlerResult(Feed feed, Map<String, String> alternateFeedUrls) {
- this.feed = feed;
- this.alternateFeedUrls = alternateFeedUrls;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java
deleted file mode 100644
index 4fe8e1aff..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package de.danoeh.antennapod.core.syndication.handler;
-
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.syndication.namespace.Namespace;
-import de.danoeh.antennapod.core.syndication.namespace.SyndElement;
-
-import java.util.*;
-
-/**
- * Contains all relevant information to describe the current state of a
- * SyndHandler.
- */
-public class HandlerState {
-
- /**
- * Feed that the Handler is currently processing.
- */
- protected Feed feed;
- /**
- * Contains links to related feeds, e.g. feeds with enclosures in other formats. The key of the map is the
- * URL of the feed, the value is the title
- */
- protected Map<String, String> alternateUrls;
- protected ArrayList<FeedItem> items;
- protected FeedItem currentItem;
- protected Stack<SyndElement> tagstack;
- /**
- * Namespaces that have been defined so far.
- */
- protected HashMap<String, Namespace> namespaces;
- protected Stack<Namespace> defaultNamespaces;
- /**
- * Buffer for saving characters.
- */
- protected StringBuffer contentBuf;
-
- public HandlerState(Feed feed) {
- this.feed = feed;
- alternateUrls = new LinkedHashMap<String, String>();
- items = new ArrayList<FeedItem>();
- tagstack = new Stack<SyndElement>();
- namespaces = new HashMap<String, Namespace>();
- defaultNamespaces = new Stack<Namespace>();
- }
-
- public Feed getFeed() {
- return feed;
- }
-
- public ArrayList<FeedItem> getItems() {
- return items;
- }
-
- public FeedItem getCurrentItem() {
- return currentItem;
- }
-
- public Stack<SyndElement> getTagstack() {
- return tagstack;
- }
-
- public void setFeed(Feed feed) {
- this.feed = feed;
- }
-
- public void setCurrentItem(FeedItem currentItem) {
- this.currentItem = currentItem;
- }
-
- /**
- * Returns the SyndElement that comes after the top element of the tagstack.
- */
- public SyndElement getSecondTag() {
- SyndElement top = tagstack.pop();
- SyndElement second = tagstack.peek();
- tagstack.push(top);
- return second;
- }
-
- public SyndElement getThirdTag() {
- SyndElement top = tagstack.pop();
- SyndElement second = tagstack.pop();
- SyndElement third = tagstack.peek();
- tagstack.push(second);
- tagstack.push(top);
- return third;
- }
-
- public StringBuffer getContentBuf() {
- return contentBuf;
- }
-
- public void addAlternateFeedUrl(String title, String url) {
- alternateUrls.put(url, title);
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/SyndHandler.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/SyndHandler.java
deleted file mode 100644
index 573c873eb..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/SyndHandler.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package de.danoeh.antennapod.core.syndication.handler;
-
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.syndication.namespace.*;
-import de.danoeh.antennapod.core.syndication.namespace.atom.NSAtom;
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-/** Superclass for all SAX Handlers which process Syndication formats */
-public class SyndHandler extends DefaultHandler {
- private static final String TAG = "SyndHandler";
- private static final String DEFAULT_PREFIX = "";
- protected HandlerState state;
-
- public SyndHandler(Feed feed, TypeGetter.Type type) {
- state = new HandlerState(feed);
- if (type == TypeGetter.Type.RSS20 || type == TypeGetter.Type.RSS091) {
- state.defaultNamespaces.push(new NSRSS20());
- }
- }
-
- @Override
- public void startElement(String uri, String localName, String qName,
- Attributes attributes) throws SAXException {
- state.contentBuf = new StringBuffer();
- Namespace handler = getHandlingNamespace(uri, qName);
- if (handler != null) {
- SyndElement element = handler.handleElementStart(localName, state,
- attributes);
- state.tagstack.push(element);
-
- }
- }
-
- @Override
- public void characters(char[] ch, int start, int length)
- throws SAXException {
- if (!state.tagstack.empty()) {
- if (state.getTagstack().size() >= 2) {
- if (state.contentBuf != null) {
- state.contentBuf.append(ch, start, length);
- }
- }
- }
- }
-
- @Override
- public void endElement(String uri, String localName, String qName)
- throws SAXException {
- Namespace handler = getHandlingNamespace(uri, qName);
- if (handler != null) {
- handler.handleElementEnd(localName, state);
- state.tagstack.pop();
-
- }
- state.contentBuf = null;
-
- }
-
- @Override
- public void endPrefixMapping(String prefix) throws SAXException {
- if (state.defaultNamespaces.size() > 1 && prefix.equals(DEFAULT_PREFIX)) {
- state.defaultNamespaces.pop();
- }
- }
-
- @Override
- public void startPrefixMapping(String prefix, String uri)
- throws SAXException {
- // Find the right namespace
- if (!state.namespaces.containsKey(uri)) {
- if (uri.equals(NSAtom.NSURI)) {
- if (prefix.equals(DEFAULT_PREFIX)) {
- state.defaultNamespaces.push(new NSAtom());
- } else if (prefix.equals(NSAtom.NSTAG)) {
- state.namespaces.put(uri, new NSAtom());
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Recognized Atom namespace");
- }
- } else if (uri.equals(NSContent.NSURI)
- && prefix.equals(NSContent.NSTAG)) {
- state.namespaces.put(uri, new NSContent());
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Recognized Content namespace");
- } else if (uri.equals(NSITunes.NSURI)
- && prefix.equals(NSITunes.NSTAG)) {
- state.namespaces.put(uri, new NSITunes());
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Recognized ITunes namespace");
- } else if (uri.equals(NSSimpleChapters.NSURI)
- && prefix.matches(NSSimpleChapters.NSTAG)) {
- state.namespaces.put(uri, new NSSimpleChapters());
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Recognized SimpleChapters namespace");
- } else if (uri.equals(NSMedia.NSURI)
- && prefix.equals(NSMedia.NSTAG)) {
- state.namespaces.put(uri, new NSMedia());
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Recognized media namespace");
- }
- }
- }
-
- private Namespace getHandlingNamespace(String uri, String qName) {
- Namespace handler = state.namespaces.get(uri);
- if (handler == null && !state.defaultNamespaces.empty()
- && !qName.contains(":")) {
- handler = state.defaultNamespaces.peek();
- }
- return handler;
- }
-
- @Override
- public void endDocument() throws SAXException {
- super.endDocument();
- state.getFeed().setItems(state.getItems());
- }
-
- public HandlerState getState() {
- return state;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/TypeGetter.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/TypeGetter.java
deleted file mode 100644
index e1ebd63a5..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/TypeGetter.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package de.danoeh.antennapod.core.syndication.handler;
-
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.feed.Feed;
-import org.apache.commons.io.input.XmlStreamReader;
-import org.jsoup.Jsoup;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.Reader;
-
-/** Gets the type of a specific feed by reading the root element. */
-public class TypeGetter {
- private static final String TAG = "TypeGetter";
-
- public enum Type {
- RSS20, RSS091, ATOM, INVALID
- }
-
- private static final String ATOM_ROOT = "feed";
- private static final String RSS_ROOT = "rss";
-
- public Type getType(Feed feed) throws UnsupportedFeedtypeException {
- XmlPullParserFactory factory;
- if (feed.getFile_url() != null) {
- try {
- factory = XmlPullParserFactory.newInstance();
- factory.setNamespaceAware(true);
- XmlPullParser xpp = factory.newPullParser();
- xpp.setInput(createReader(feed));
- int eventType = xpp.getEventType();
-
- while (eventType != XmlPullParser.END_DOCUMENT) {
- if (eventType == XmlPullParser.START_TAG) {
- String tag = xpp.getName();
- if (tag.equals(ATOM_ROOT)) {
- feed.setType(Feed.TYPE_ATOM1);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Recognized type Atom");
- return Type.ATOM;
- } else if (tag.equals(RSS_ROOT)) {
- String strVersion = xpp.getAttributeValue(null,
- "version");
- if (strVersion != null) {
-
- if (strVersion.equals("2.0")) {
- feed.setType(Feed.TYPE_RSS2);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Recognized type RSS 2.0");
- return Type.RSS20;
- } else if (strVersion.equals("0.91")
- || strVersion.equals("0.92")) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Recognized type RSS 0.91/0.92");
- return Type.RSS091;
- }
- }
- throw new UnsupportedFeedtypeException(Type.INVALID);
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Type is invalid");
- throw new UnsupportedFeedtypeException(Type.INVALID, tag);
- }
- } else {
- eventType = xpp.next();
- }
- }
-
- } catch (XmlPullParserException e) {
- e.printStackTrace();
- // XML document might actually be a HTML document -> try to parse as HTML
- String rootElement = null;
- try {
- if (Jsoup.parse(new File(feed.getFile_url()), null) != null) {
- rootElement = "html";
- }
- } catch (IOException e1) {
- e1.printStackTrace();
- } finally {
- throw new UnsupportedFeedtypeException(Type.INVALID, rootElement);
- }
-
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Type is invalid");
- throw new UnsupportedFeedtypeException(Type.INVALID);
- }
-
- private Reader createReader(Feed feed) {
- Reader reader;
- try {
- reader = new XmlStreamReader(new File(feed.getFile_url()));
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- return null;
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- }
- return reader;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java
deleted file mode 100644
index 3da9251d9..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package de.danoeh.antennapod.core.syndication.handler;
-
-import de.danoeh.antennapod.core.syndication.handler.TypeGetter.Type;
-
-public class UnsupportedFeedtypeException extends Exception {
- private static final long serialVersionUID = 9105878964928170669L;
- private TypeGetter.Type type;
- private String rootElement;
-
- public UnsupportedFeedtypeException(Type type) {
- super();
- this.type = type;
- }
-
- public UnsupportedFeedtypeException(Type type, String rootElement) {
- this.type = type;
- this.rootElement = rootElement;
- }
-
- public TypeGetter.Type getType() {
- return type;
- }
-
- public String getRootElement() {
- return rootElement;
- }
-
- @Override
- public String getMessage() {
- if (type == TypeGetter.Type.INVALID) {
- return "Invalid type";
- } else {
- return "Type " + type + " not supported";
- }
- }
-
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSContent.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSContent.java
deleted file mode 100644
index 71bf69ffa..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSContent.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package de.danoeh.antennapod.core.syndication.namespace;
-
-import de.danoeh.antennapod.core.syndication.handler.HandlerState;
-import org.xml.sax.Attributes;
-
-public class NSContent extends Namespace {
- public static final String NSTAG = "content";
- public static final String NSURI = "http://purl.org/rss/1.0/modules/content/";
-
- private static final String ENCODED = "encoded";
-
- @Override
- public SyndElement handleElementStart(String localName, HandlerState state,
- Attributes attributes) {
- return new SyndElement(localName, this);
- }
-
- @Override
- public void handleElementEnd(String localName, HandlerState state) {
- if (localName.equals(ENCODED)) {
- state.getCurrentItem().setContentEncoded(state.getContentBuf().toString());
- }
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java
deleted file mode 100644
index fb794d7e0..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package de.danoeh.antennapod.core.syndication.namespace;
-
-import de.danoeh.antennapod.core.feed.FeedImage;
-import de.danoeh.antennapod.core.syndication.handler.HandlerState;
-import org.xml.sax.Attributes;
-
-public class NSITunes extends Namespace {
- public static final String NSTAG = "itunes";
- public static final String NSURI = "http://www.itunes.com/dtds/podcast-1.0.dtd";
-
- private static final String IMAGE = "image";
- private static final String IMAGE_TITLE = "image";
- private static final String IMAGE_HREF = "href";
-
- private static final String AUTHOR = "author";
-
-
- @Override
- public SyndElement handleElementStart(String localName, HandlerState state,
- Attributes attributes) {
- if (localName.equals(IMAGE)) {
- FeedImage image = new FeedImage();
- image.setTitle(IMAGE_TITLE);
- image.setDownload_url(attributes.getValue(IMAGE_HREF));
-
- if (state.getCurrentItem() != null) {
- // this is an items image
- image.setTitle(state.getCurrentItem().getTitle() + IMAGE_TITLE);
- state.getCurrentItem().setImage(image);
-
- } else {
- // this is the feed image
- if (state.getFeed().getImage() == null) {
- state.getFeed().setImage(image);
- }
- }
-
- }
-
- return new SyndElement(localName, this);
- }
-
- @Override
- public void handleElementEnd(String localName, HandlerState state) {
- if (localName.equals(AUTHOR)) {
- state.getFeed().setAuthor(state.getContentBuf().toString());
- }
-
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java
deleted file mode 100644
index 15c377f79..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package de.danoeh.antennapod.core.syndication.namespace;
-
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.syndication.handler.HandlerState;
-import de.danoeh.antennapod.core.syndication.util.SyndTypeUtils;
-import org.xml.sax.Attributes;
-
-import java.util.concurrent.TimeUnit;
-
-/** Processes tags from the http://search.yahoo.com/mrss/ namespace. */
-public class NSMedia extends Namespace {
- private static final String TAG = "NSMedia";
-
- public static final String NSTAG = "media";
- public static final String NSURI = "http://search.yahoo.com/mrss/";
-
- private static final String CONTENT = "content";
- private static final String DOWNLOAD_URL = "url";
- private static final String SIZE = "fileSize";
- private static final String MIME_TYPE = "type";
- private static final String DURATION = "duration";
-
- @Override
- public SyndElement handleElementStart(String localName, HandlerState state,
- Attributes attributes) {
- if (localName.equals(CONTENT)) {
- String url = attributes.getValue(DOWNLOAD_URL);
- String type = attributes.getValue(MIME_TYPE);
- if (state.getCurrentItem().getMedia() == null
- && url != null
- && (SyndTypeUtils.enclosureTypeValid(type) || ((type = SyndTypeUtils
- .getValidMimeTypeFromUrl(url)) != null))) {
-
- long size = 0;
- try {
- size = Long.parseLong(attributes.getValue(SIZE));
- } catch (NumberFormatException e) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Length attribute could not be parsed.");
- }
-
- int duration = 0;
- try {
- String durationStr = attributes.getValue(DURATION);
- if (durationStr != null) {
- duration = (int) TimeUnit.MILLISECONDS.convert(
- Long.parseLong(durationStr), TimeUnit.SECONDS);
- }
- } catch (NumberFormatException e) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Duration attribute could not be parsed");
- }
-
- state.getCurrentItem().setMedia(
- new FeedMedia(state.getCurrentItem(), url, size, type));
- }
- }
- return new SyndElement(localName, this);
- }
-
- @Override
- public void handleElementEnd(String localName, HandlerState state) {
-
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java
deleted file mode 100644
index fd8f6176b..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package de.danoeh.antennapod.core.syndication.namespace;
-
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.feed.FeedImage;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.syndication.handler.HandlerState;
-import de.danoeh.antennapod.core.syndication.util.SyndDateUtils;
-import de.danoeh.antennapod.core.syndication.util.SyndTypeUtils;
-import org.xml.sax.Attributes;
-
-/**
- * SAX-Parser for reading RSS-Feeds
- *
- * @author daniel
- *
- */
-public class NSRSS20 extends Namespace {
- private static final String TAG = "NSRSS20";
- public static final String NSTAG = "rss";
- public static final String NSURI = "";
-
- public final static String CHANNEL = "channel";
- public final static String ITEM = "item";
- public final static String GUID = "guid";
- public final static String TITLE = "title";
- public final static String LINK = "link";
- public final static String DESCR = "description";
- public final static String PUBDATE = "pubDate";
- public final static String ENCLOSURE = "enclosure";
- public final static String IMAGE = "image";
- public final static String URL = "url";
- public final static String LANGUAGE = "language";
-
- public final static String ENC_URL = "url";
- public final static String ENC_LEN = "length";
- public final static String ENC_TYPE = "type";
-
- @Override
- public SyndElement handleElementStart(String localName, HandlerState state,
- Attributes attributes) {
- if (localName.equals(ITEM)) {
- state.setCurrentItem(new FeedItem());
- state.getItems().add(state.getCurrentItem());
- state.getCurrentItem().setFeed(state.getFeed());
-
- } else if (localName.equals(ENCLOSURE)) {
- String type = attributes.getValue(ENC_TYPE);
- String url = attributes.getValue(ENC_URL);
- if (state.getCurrentItem().getMedia() == null
- && (SyndTypeUtils.enclosureTypeValid(type) || ((type = SyndTypeUtils
- .getValidMimeTypeFromUrl(url)) != null))) {
-
- long size = 0;
- try {
- size = Long.parseLong(attributes.getValue(ENC_LEN));
- } catch (NumberFormatException e) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Length attribute could not be parsed.");
- }
- state.getCurrentItem().setMedia(
- new FeedMedia(state.getCurrentItem(), url, size, type));
- }
-
- } else if (localName.equals(IMAGE)) {
- if (state.getTagstack().size() >= 1) {
- String parent = state.getTagstack().peek().getName();
- if (parent.equals(CHANNEL)) {
- state.getFeed().setImage(new FeedImage());
- }
- }
- }
- return new SyndElement(localName, this);
- }
-
- @Override
- public void handleElementEnd(String localName, HandlerState state) {
- if (localName.equals(ITEM)) {
- if (state.getCurrentItem() != null) {
- // the title tag is optional in RSS 2.0. The description is used
- // as a
- // title if the item has no title-tag.
- if (state.getCurrentItem().getTitle() == null) {
- state.getCurrentItem().setTitle(
- state.getCurrentItem().getDescription());
- }
- }
- state.setCurrentItem(null);
- } else if (state.getTagstack().size() >= 2
- && state.getContentBuf() != null) {
- String content = state.getContentBuf().toString();
- SyndElement topElement = state.getTagstack().peek();
- String top = topElement.getName();
- SyndElement secondElement = state.getSecondTag();
- String second = secondElement.getName();
- String third = null;
- if (state.getTagstack().size() >= 3) {
- third = state.getThirdTag().getName();
- }
-
- if (top.equals(GUID) && second.equals(ITEM)) {
- // some feed creators include an empty or non-standard guid-element in their feed, which should be ignored
- if (!content.isEmpty()) {
- state.getCurrentItem().setItemIdentifier(content);
- }
- } else if (top.equals(TITLE)) {
- if (second.equals(ITEM)) {
- state.getCurrentItem().setTitle(content);
- } else if (second.equals(CHANNEL)) {
- state.getFeed().setTitle(content);
- } else if (second.equals(IMAGE) && third != null
- && third.equals(CHANNEL)) {
- state.getFeed().getImage().setTitle(content);
- }
- } else if (top.equals(LINK)) {
- if (second.equals(CHANNEL)) {
- state.getFeed().setLink(content);
- } else if (second.equals(ITEM)) {
- state.getCurrentItem().setLink(content);
- }
- } else if (top.equals(PUBDATE) && second.equals(ITEM)) {
- state.getCurrentItem().setPubDate(
- SyndDateUtils.parseRFC822Date(content));
- } else if (top.equals(URL) && second.equals(IMAGE) && third != null
- && third.equals(CHANNEL)) {
- state.getFeed().getImage().setDownload_url(content);
- } else if (localName.equals(DESCR)) {
- if (second.equals(CHANNEL)) {
- state.getFeed().setDescription(content);
- } else if (second.equals(ITEM)) {
- state.getCurrentItem().setDescription(content);
- }
-
- } else if (localName.equals(LANGUAGE)) {
- state.getFeed().setLanguage(content.toLowerCase());
- }
- }
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java
deleted file mode 100644
index 2b4a2767d..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package de.danoeh.antennapod.core.syndication.namespace;
-
-import de.danoeh.antennapod.core.feed.Chapter;
-import de.danoeh.antennapod.core.feed.SimpleChapter;
-import de.danoeh.antennapod.core.syndication.handler.HandlerState;
-import de.danoeh.antennapod.core.syndication.util.SyndDateUtils;
-import org.xml.sax.Attributes;
-
-import java.util.ArrayList;
-
-public class NSSimpleChapters extends Namespace {
- public static final String NSTAG = "psc|sc";
- public static final String NSURI = "http://podlove.org/simple-chapters";
-
- public static final String CHAPTERS = "chapters";
- public static final String CHAPTER = "chapter";
- public static final String START = "start";
- public static final String TITLE = "title";
- public static final String HREF = "href";
-
- @Override
- public SyndElement handleElementStart(String localName, HandlerState state,
- Attributes attributes) {
- if (localName.equals(CHAPTERS)) {
- state.getCurrentItem().setChapters(new ArrayList<Chapter>());
- } else if (localName.equals(CHAPTER)) {
- state.getCurrentItem()
- .getChapters()
- .add(new SimpleChapter(SyndDateUtils
- .parseTimeString(attributes.getValue(START)),
- attributes.getValue(TITLE), state.getCurrentItem(),
- attributes.getValue(HREF)));
- }
-
- return new SyndElement(localName, this);
- }
-
- @Override
- public void handleElementEnd(String localName, HandlerState state) {
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/Namespace.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/Namespace.java
deleted file mode 100644
index cf118d202..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/Namespace.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package de.danoeh.antennapod.core.syndication.namespace;
-
-import de.danoeh.antennapod.core.syndication.handler.HandlerState;
-import org.xml.sax.Attributes;
-
-
-public abstract class Namespace {
- public static final String NSTAG = null;
- public static final String NSURI = null;
-
- /** Called by a Feedhandler when in startElement and it detects a namespace element
- * @return The SyndElement to push onto the stack
- * */
- public abstract SyndElement handleElementStart(String localName, HandlerState state, Attributes attributes);
-
- /** Called by a Feedhandler when in endElement and it detects a namespace element
- * @return true if namespace handled the element, false if it ignored it
- * */
- public abstract void handleElementEnd(String localName, HandlerState state);
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/SyndElement.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/SyndElement.java
deleted file mode 100644
index 8adcd2086..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/SyndElement.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package de.danoeh.antennapod.core.syndication.namespace;
-
-/** Defines a XML Element that is pushed on the tagstack */
-public class SyndElement {
- protected String name;
- protected Namespace namespace;
-
- public SyndElement(String name, Namespace namespace) {
- this.name = name;
- this.namespace = namespace;
- }
-
- public Namespace getNamespace() {
- return namespace;
- }
-
- public String getName() {
- return name;
- }
-
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java
deleted file mode 100644
index 43fe0edb7..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package de.danoeh.antennapod.core.syndication.namespace.atom;
-
-import de.danoeh.antennapod.core.syndication.namespace.Namespace;
-import de.danoeh.antennapod.core.syndication.namespace.SyndElement;
-import org.apache.commons.lang3.StringEscapeUtils;
-
-/** Represents Atom Element which contains text (content, title, summary). */
-public class AtomText extends SyndElement {
- public static final String TYPE_TEXT = "text";
- public static final String TYPE_HTML = "html";
- public static final String TYPE_XHTML = "xhtml";
-
- private String type;
- private String content;
-
- public AtomText(String name, Namespace namespace, String type) {
- super(name, namespace);
- this.type = type;
- }
-
- /** Processes the content according to the type and returns it. */
- public String getProcessedContent() {
- if (type == null) {
- return content;
- } else if (type.equals(TYPE_HTML)) {
- return StringEscapeUtils.unescapeHtml4(content);
- } else if (type.equals(TYPE_XHTML)) {
- return content;
- } else { // Handle as text by default
- return content;
- }
- }
-
- public String getContent() {
- return content;
- }
-
- public void setContent(String content) {
- this.content = content;
- }
-
- public String getType() {
- return type;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java
deleted file mode 100644
index 1547dc222..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java
+++ /dev/null
@@ -1,194 +0,0 @@
-package de.danoeh.antennapod.core.syndication.namespace.atom;
-
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.feed.FeedImage;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.syndication.handler.HandlerState;
-import de.danoeh.antennapod.core.syndication.namespace.NSRSS20;
-import de.danoeh.antennapod.core.syndication.namespace.Namespace;
-import de.danoeh.antennapod.core.syndication.namespace.SyndElement;
-import de.danoeh.antennapod.core.syndication.util.SyndDateUtils;
-import de.danoeh.antennapod.core.syndication.util.SyndTypeUtils;
-import org.xml.sax.Attributes;
-
-public class NSAtom extends Namespace {
- private static final String TAG = "NSAtom";
- public static final String NSTAG = "atom";
- public static final String NSURI = "http://www.w3.org/2005/Atom";
-
- private static final String FEED = "feed";
- private static final String ID = "id";
- private static final String TITLE = "title";
- private static final String ENTRY = "entry";
- private static final String LINK = "link";
- private static final String UPDATED = "updated";
- private static final String AUTHOR = "author";
- private static final String CONTENT = "content";
- private static final String IMAGE = "logo";
- private static final String SUBTITLE = "subtitle";
- private static final String PUBLISHED = "published";
-
- private static final String TEXT_TYPE = "type";
- // Link
- private static final String LINK_HREF = "href";
- private static final String LINK_REL = "rel";
- private static final String LINK_TYPE = "type";
- private static final String LINK_TITLE = "title";
- private static final String LINK_LENGTH = "length";
- // rel-values
- private static final String LINK_REL_ALTERNATE = "alternate";
- private static final String LINK_REL_ENCLOSURE = "enclosure";
- private static final String LINK_REL_PAYMENT = "payment";
- private static final String LINK_REL_RELATED = "related";
- private static final String LINK_REL_SELF = "self";
- // type-values
- private static final String LINK_TYPE_ATOM = "application/atom+xml";
- private static final String LINK_TYPE_HTML = "text/html";
- private static final String LINK_TYPE_XHTML = "application/xml+xhtml";
-
- private static final String LINK_TYPE_RSS = "application/rss+xml";
-
- /**
- * Regexp to test whether an Element is a Text Element.
- */
- private static final String isText = TITLE + "|" + CONTENT + "|" + "|"
- + SUBTITLE;
-
- public static final String isFeed = FEED + "|" + NSRSS20.CHANNEL;
- public static final String isFeedItem = ENTRY + "|" + NSRSS20.ITEM;
-
- @Override
- public SyndElement handleElementStart(String localName, HandlerState state,
- Attributes attributes) {
- if (localName.equals(ENTRY)) {
- state.setCurrentItem(new FeedItem());
- state.getItems().add(state.getCurrentItem());
- state.getCurrentItem().setFeed(state.getFeed());
- } else if (localName.matches(isText)) {
- String type = attributes.getValue(TEXT_TYPE);
- return new AtomText(localName, this, type);
- } else if (localName.equals(LINK)) {
- String href = attributes.getValue(LINK_HREF);
- String rel = attributes.getValue(LINK_REL);
- SyndElement parent = state.getTagstack().peek();
- if (parent.getName().matches(isFeedItem)) {
- if (rel == null || rel.equals(LINK_REL_ALTERNATE)) {
- state.getCurrentItem().setLink(href);
- } else if (rel.equals(LINK_REL_ENCLOSURE)) {
- String strSize = attributes.getValue(LINK_LENGTH);
- long size = 0;
- try {
- if (strSize != null) {
- size = Long.parseLong(strSize);
- }
- } catch (NumberFormatException e) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Length attribute could not be parsed.");
- }
- String type = attributes.getValue(LINK_TYPE);
- if (SyndTypeUtils.enclosureTypeValid(type)
- || (type = SyndTypeUtils
- .getValidMimeTypeFromUrl(href)) != null) {
- state.getCurrentItem().setMedia(
- new FeedMedia(state.getCurrentItem(), href,
- size, type)
- );
- }
- } else if (rel.equals(LINK_REL_PAYMENT)) {
- state.getCurrentItem().setPaymentLink(href);
- }
- } else if (parent.getName().matches(isFeed)) {
- if (rel == null || rel.equals(LINK_REL_ALTERNATE)) {
- String type = attributes.getValue(LINK_TYPE);
- /*
- * Use as link if a) no type-attribute is given and
- * feed-object has no link yet b) type of link is
- * LINK_TYPE_HTML or LINK_TYPE_XHTML
- */
- if ((type == null && state.getFeed().getLink() == null)
- || (type != null && (type.equals(LINK_TYPE_HTML) || type.equals(LINK_TYPE_XHTML)))) {
- state.getFeed().setLink(href);
- } else if (type != null && (type.equals(LINK_TYPE_ATOM) || type.equals(LINK_TYPE_RSS))) {
- // treat as podlove alternate feed
- String title = attributes.getValue(LINK_TITLE);
- if (title == null) {
- title = href;
- }
- state.addAlternateFeedUrl(title, href);
- }
- } else if (rel.equals(LINK_REL_PAYMENT)) {
- state.getFeed().setPaymentLink(href);
- }
- }
- }
- return new SyndElement(localName, this);
- }
-
- @Override
- public void handleElementEnd(String localName, HandlerState state) {
- if (localName.equals(ENTRY)) {
- state.setCurrentItem(null);
- }
-
- if (state.getTagstack().size() >= 2) {
- AtomText textElement = null;
- String content;
- if (state.getContentBuf() != null) {
- content = state.getContentBuf().toString();
- } else {
- content = "";
- }
- SyndElement topElement = state.getTagstack().peek();
- String top = topElement.getName();
- SyndElement secondElement = state.getSecondTag();
- String second = secondElement.getName();
-
- if (top.matches(isText)) {
- textElement = (AtomText) topElement;
- textElement.setContent(content);
- }
-
- if (top.equals(ID)) {
- if (second.equals(FEED)) {
- state.getFeed().setFeedIdentifier(content);
- } else if (second.equals(ENTRY)) {
- state.getCurrentItem().setItemIdentifier(content);
- }
- } else if (top.equals(TITLE)) {
-
- if (second.equals(FEED)) {
- state.getFeed().setTitle(textElement.getProcessedContent());
- } else if (second.equals(ENTRY)) {
- state.getCurrentItem().setTitle(
- textElement.getProcessedContent());
- }
- } else if (top.equals(SUBTITLE)) {
- if (second.equals(FEED)) {
- state.getFeed().setDescription(
- textElement.getProcessedContent());
- }
- } else if (top.equals(CONTENT)) {
- if (second.equals(ENTRY)) {
- state.getCurrentItem().setDescription(
- textElement.getProcessedContent());
- }
- } else if (top.equals(UPDATED)) {
- if (second.equals(ENTRY)
- && state.getCurrentItem().getPubDate() == null) {
- state.getCurrentItem().setPubDate(
- SyndDateUtils.parseRFC3339Date(content));
- }
- } else if (top.equals(PUBLISHED)) {
- if (second.equals(ENTRY)) {
- state.getCurrentItem().setPubDate(
- SyndDateUtils.parseRFC3339Date(content));
- }
- } else if (top.equals(IMAGE)) {
- state.getFeed().setImage(new FeedImage(content, null));
- }
-
- }
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndDateUtils.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndDateUtils.java
deleted file mode 100644
index 977d92304..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndDateUtils.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package de.danoeh.antennapod.core.syndication.util;
-
-import android.util.Log;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-
-/** Parses several date formats. */
-public class SyndDateUtils {
- private static final String TAG = "DateUtils";
-
- private static final String[] RFC822DATES = { "dd MMM yy HH:mm:ss Z", };
-
- /** RFC 3339 date format for UTC dates. */
- public static final String RFC3339UTC = "yyyy-MM-dd'T'HH:mm:ss'Z'";
-
- /** RFC 3339 date format for localtime dates with offset. */
- public static final String RFC3339LOCAL = "yyyy-MM-dd'T'HH:mm:ssZ";
-
- private static ThreadLocal<SimpleDateFormat> RFC822Formatter = new ThreadLocal<SimpleDateFormat>() {
- @Override
- protected SimpleDateFormat initialValue() {
- return new SimpleDateFormat(RFC822DATES[0], Locale.US);
- }
-
- };
-
- private static ThreadLocal<SimpleDateFormat> RFC3339Formatter = new ThreadLocal<SimpleDateFormat>() {
- @Override
- protected SimpleDateFormat initialValue() {
- return new SimpleDateFormat(RFC3339UTC, Locale.US);
- }
-
- };
-
- public static Date parseRFC822Date(String date) {
- Date result = null;
- if (date.contains("PDT")) {
- date = date.replace("PDT", "PST8PDT");
- }
- if (date.contains(",")) {
- // Remove day of the week
- date = date.substring(date.indexOf(",") + 1).trim();
- }
- SimpleDateFormat format = RFC822Formatter.get();
- for (int i = 0; i < RFC822DATES.length; i++) {
- try {
- format.applyPattern(RFC822DATES[i]);
- result = format.parse(date);
- break;
- } catch (ParseException e) {
- e.printStackTrace();
- }
- }
- if (result == null) {
- Log.e(TAG, "Unable to parse feed date correctly");
- }
-
- return result;
- }
-
- public static Date parseRFC3339Date(String date) {
- Date result = null;
- SimpleDateFormat format = RFC3339Formatter.get();
- boolean isLocal = date.endsWith("Z");
- if (date.contains(".")) {
- // remove secfrac
- int fracIndex = date.indexOf(".");
- String first = date.substring(0, fracIndex);
- String second = null;
- if (isLocal) {
- second = date.substring(date.length() - 1);
- } else {
- if (date.contains("+")) {
- second = date.substring(date.indexOf("+"));
- } else {
- second = date.substring(date.indexOf("-"));
- }
- }
-
- date = first + second;
- }
- if (isLocal) {
- try {
- result = format.parse(date);
- } catch (ParseException e) {
- e.printStackTrace();
- }
- } else {
- format.applyPattern(RFC3339LOCAL);
- // remove last colon
- StringBuffer buf = new StringBuffer(date.length() - 1);
- int colonIdx = date.lastIndexOf(':');
- for (int x = 0; x < date.length(); x++) {
- if (x != colonIdx)
- buf.append(date.charAt(x));
- }
- String bufStr = buf.toString();
- try {
- result = format.parse(bufStr);
- } catch (ParseException e) {
- e.printStackTrace();
- Log.e(TAG, "Unable to parse date");
- } finally {
- format.applyPattern(RFC3339UTC);
- }
-
- }
-
- return result;
-
- }
-
- /**
- * Takes a string of the form [HH:]MM:SS[.mmm] and converts it to
- * milliseconds.
- */
- public static long parseTimeString(final String time) {
- String[] parts = time.split(":");
- long result = 0;
- int idx = 0;
- if (parts.length == 3) {
- // string has hours
- result += Integer.valueOf(parts[idx]) * 3600000L;
- idx++;
- }
- result += Integer.valueOf(parts[idx]) * 60000L;
- idx++;
- result += (Float.valueOf(parts[idx])) * 1000L;
- return result;
- }
-
- public static String formatRFC822Date(Date date) {
- SimpleDateFormat format = RFC822Formatter.get();
- return format.format(date);
- }
-
- public static String formatRFC3339Local(Date date) {
- SimpleDateFormat format = RFC3339Formatter.get();
- format.applyPattern(RFC3339LOCAL);
- String result = format.format(date);
- format.applyPattern(RFC3339UTC);
- return result;
- }
-
- public static String formatRFC3339UTC(Date date) {
- SimpleDateFormat format = RFC3339Formatter.get();
- format.applyPattern(RFC3339UTC);
- return format.format(date);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndTypeUtils.java b/app/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndTypeUtils.java
deleted file mode 100644
index 8d1d8ffde..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndTypeUtils.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package de.danoeh.antennapod.core.syndication.util;
-
-import android.webkit.MimeTypeMap;
-import org.apache.commons.io.FilenameUtils;
-
-/** Utility class for handling MIME-Types of enclosures */
-public class SyndTypeUtils {
-
- private final static String VALID_MIMETYPE = "audio/.*" + "|" + "video/.*"
- + "|" + "application/ogg";
-
- private SyndTypeUtils() {
-
- }
-
- public static boolean enclosureTypeValid(String type) {
- if (type == null) {
- return false;
- } else {
- return type.matches(VALID_MIMETYPE);
- }
- }
-
- /**
- * Should be used if mime-type of enclosure tag is not supported. This
- * method will check if the mime-type of the file extension is supported. If
- * the type is not supported, this method will return null.
- */
- public static String getValidMimeTypeFromUrl(String url) {
- if (url != null) {
- String extension = FilenameUtils.getExtension(url);
- if (extension != null) {
- String type = MimeTypeMap.getSingleton()
- .getMimeTypeFromExtension(extension);
- if (type != null && enclosureTypeValid(type)) {
- return type;
- }
- }
- }
- return null;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java b/app/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java
deleted file mode 100644
index d6046026f..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java
+++ /dev/null
@@ -1,261 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.feed.Chapter;
-import de.danoeh.antennapod.core.util.comparator.ChapterStartTimeComparator;
-import de.danoeh.antennapod.core.util.id3reader.ChapterReader;
-import de.danoeh.antennapod.core.util.id3reader.ID3ReaderException;
-import de.danoeh.antennapod.core.util.playback.Playable;
-import de.danoeh.antennapod.core.util.vorbiscommentreader.VorbisCommentChapterReader;
-import de.danoeh.antennapod.core.util.vorbiscommentreader.VorbisCommentReaderException;
-import org.apache.commons.io.IOUtils;
-
-import java.io.*;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Collections;
-import java.util.List;
-
-/** Utility class for getting chapter data from media files. */
-public class ChapterUtils {
- private static final String TAG = "ChapterUtils";
-
- private ChapterUtils() {
- }
-
- /**
- * Uses the download URL of a media object of a feeditem to read its ID3
- * chapters.
- */
- public static void readID3ChaptersFromPlayableStreamUrl(Playable p) {
- if (p != null && p.getStreamUrl() != null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Reading id3 chapters from item " + p.getEpisodeTitle());
- InputStream in = null;
- try {
- URL url = new URL(p.getStreamUrl());
- ChapterReader reader = new ChapterReader();
-
- in = url.openStream();
- reader.readInputStream(in);
- List<Chapter> chapters = reader.getChapters();
-
- if (chapters != null) {
- Collections
- .sort(chapters, new ChapterStartTimeComparator());
- processChapters(chapters, p);
- if (chaptersValid(chapters)) {
- p.setChapters(chapters);
- Log.i(TAG, "Chapters loaded");
- } else {
- Log.e(TAG, "Chapter data was invalid");
- }
- } else {
- Log.i(TAG, "ChapterReader could not find any ID3 chapters");
- }
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } catch (ID3ReaderException e) {
- e.printStackTrace();
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- } else {
- Log.e(TAG,
- "Unable to read ID3 chapters: media or download URL was null");
- }
- }
-
- /**
- * Uses the file URL of a media object of a feeditem to read its ID3
- * chapters.
- */
- public static void readID3ChaptersFromPlayableFileUrl(Playable p) {
- if (p != null && p.localFileAvailable() && p.getLocalMediaUrl() != null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Reading id3 chapters from item " + p.getEpisodeTitle());
- File source = new File(p.getLocalMediaUrl());
- if (source.exists()) {
- ChapterReader reader = new ChapterReader();
- InputStream in = null;
-
- try {
- in = new BufferedInputStream(new FileInputStream(source));
- reader.readInputStream(in);
- List<Chapter> chapters = reader.getChapters();
-
- if (chapters != null) {
- Collections.sort(chapters,
- new ChapterStartTimeComparator());
- processChapters(chapters, p);
- if (chaptersValid(chapters)) {
- p.setChapters(chapters);
- Log.i(TAG, "Chapters loaded");
- } else {
- Log.e(TAG, "Chapter data was invalid");
- }
- } else {
- Log.i(TAG,
- "ChapterReader could not find any ID3 chapters");
- }
- } catch (IOException e) {
- e.printStackTrace();
- } catch (ID3ReaderException e) {
- e.printStackTrace();
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- } else {
- Log.e(TAG, "Unable to read id3 chapters: Source doesn't exist");
- }
- }
- }
-
- public static void readOggChaptersFromPlayableStreamUrl(Playable media) {
- if (media != null && media.streamAvailable()) {
- InputStream input = null;
- try {
- URL url = new URL(media.getStreamUrl());
- input = url.openStream();
- if (input != null) {
- readOggChaptersFromInputStream(media, input);
- }
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- IOUtils.closeQuietly(input);
- }
- }
- }
-
- public static void readOggChaptersFromPlayableFileUrl(Playable media) {
- if (media != null && media.getLocalMediaUrl() != null) {
- File source = new File(media.getLocalMediaUrl());
- if (source.exists()) {
- InputStream input = null;
- try {
- input = new BufferedInputStream(new FileInputStream(source));
- readOggChaptersFromInputStream(media, input);
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } finally {
- IOUtils.closeQuietly(input);
- }
- }
- }
- }
-
- private static void readOggChaptersFromInputStream(Playable p,
- InputStream input) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Trying to read chapters from item with title "
- + p.getEpisodeTitle());
- try {
- VorbisCommentChapterReader reader = new VorbisCommentChapterReader();
- reader.readInputStream(input);
- List<Chapter> chapters = reader.getChapters();
- if (chapters != null) {
- Collections.sort(chapters, new ChapterStartTimeComparator());
- processChapters(chapters, p);
- if (chaptersValid(chapters)) {
- p.setChapters(chapters);
- Log.i(TAG, "Chapters loaded");
- } else {
- Log.e(TAG, "Chapter data was invalid");
- }
- } else {
- Log.i(TAG,
- "ChapterReader could not find any Ogg vorbis chapters");
- }
- } catch (VorbisCommentReaderException e) {
- e.printStackTrace();
- }
- }
-
- /** Makes sure that chapter does a title and an item attribute. */
- private static void processChapters(List<Chapter> chapters, Playable p) {
- for (int i = 0; i < chapters.size(); i++) {
- Chapter c = chapters.get(i);
- if (c.getTitle() == null) {
- c.setTitle(Integer.toString(i));
- }
- }
- }
-
- private static boolean chaptersValid(List<Chapter> chapters) {
- if (chapters.isEmpty()) {
- return false;
- }
- for (Chapter c : chapters) {
- if (c.getTitle() == null) {
- return false;
- }
- if (c.getStart() < 0) {
- return false;
- }
- }
- return true;
- }
-
- /** Calls getCurrentChapter with current position. */
- public static Chapter getCurrentChapter(Playable media) {
- if (media.getChapters() != null) {
- List<Chapter> chapters = media.getChapters();
- Chapter current = null;
- if (chapters != null) {
- current = chapters.get(0);
- for (Chapter sc : chapters) {
- if (sc.getStart() > media.getPosition()) {
- break;
- } else {
- current = sc;
- }
- }
- }
- return current;
- } else {
- return null;
- }
- }
-
- public static void loadChaptersFromStreamUrl(Playable media) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Starting chapterLoader thread");
- ChapterUtils.readID3ChaptersFromPlayableStreamUrl(media);
- if (media.getChapters() == null) {
- ChapterUtils.readOggChaptersFromPlayableStreamUrl(media);
- }
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "ChapterLoaderThread has finished");
- }
-
- public static void loadChaptersFromFileUrl(Playable media) {
- if (media.localFileAvailable()) {
- ChapterUtils.readID3ChaptersFromPlayableFileUrl(media);
- if (media.getChapters() == null) {
- ChapterUtils.readOggChaptersFromPlayableFileUrl(media);
- }
- } else {
- Log.e(TAG, "Could not load chapters from file url: local file not available");
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/Converter.java b/app/src/main/java/de/danoeh/antennapod/core/util/Converter.java
deleted file mode 100644
index a0b514bd6..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/Converter.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import android.util.Log;
-
-/** Provides methods for converting various units. */
-public final class Converter {
- /** Class shall not be instantiated. */
- private Converter() {
- }
-
- /** Logging tag. */
- private static final String TAG = "Converter";
-
-
- /** Indicates that the value is in the Byte range.*/
- private static final int B_RANGE = 0;
- /** Indicates that the value is in the Kilobyte range.*/
- private static final int KB_RANGE = 1;
- /** Indicates that the value is in the Megabyte range.*/
- private static final int MB_RANGE = 2;
- /** Indicates that the value is in the Gigabyte range.*/
- private static final int GB_RANGE = 3;
- /** Determines the length of the number for best readability.*/
- private static final int NUM_LENGTH = 1024;
-
-
- private static final int HOURS_MIL = 3600000;
- private static final int MINUTES_MIL = 60000;
- private static final int SECONDS_MIL = 1000;
-
- /** Takes a byte-value and converts it into a more readable
- * String.
- * @param input The value to convert
- * @return The converted String with a unit
- * */
- public static String byteToString(final long input) {
- int i = 0;
- int result = 0;
-
- for (i = 0; i < GB_RANGE + 1; i++) {
- result = (int) (input / Math.pow(1024, i));
- if (result < NUM_LENGTH) {
- break;
- }
- }
-
- switch (i) {
- case B_RANGE:
- return result + " B";
- case KB_RANGE:
- return result + " KB";
- case MB_RANGE:
- return result + " MB";
- case GB_RANGE:
- return result + " GB";
- default:
- Log.e(TAG, "Error happened in byteToString");
- return "ERROR";
- }
- }
-
- /** Converts milliseconds to a string containing hours, minutes and seconds */
- public static String getDurationStringLong(int duration) {
- int h = duration / HOURS_MIL;
- int rest = duration - h * HOURS_MIL;
- int m = rest / MINUTES_MIL;
- rest -= m * MINUTES_MIL;
- int s = rest / SECONDS_MIL;
-
- return String.format("%02d:%02d:%02d", h, m, s);
- }
-
- /** Converts milliseconds to a string containing hours and minutes */
- public static String getDurationStringShort(int duration) {
- int h = duration / HOURS_MIL;
- int rest = duration - h * HOURS_MIL;
- int m = rest / MINUTES_MIL;
-
- return String.format("%02d:%02d", h, m);
- }
-
- /** Converts long duration string (HH:MM:SS) to milliseconds. */
- public static int durationStringLongToMs(String input) {
- String[] parts = input.split(":");
- if (parts.length != 3) {
- return 0;
- }
- return Integer.valueOf(parts[0]) * 3600 * 1000 +
- Integer.valueOf(parts[1]) * 60 * 1000 +
- Integer.valueOf(parts[2]) * 1000;
- }
-
- /** Converts short duration string (HH:MM) to milliseconds. */
- public static int durationStringShortToMs(String input) {
- String[] parts = input.split(":");
- if (parts.length != 2) {
- return 0;
- }
- return Integer.valueOf(parts[0]) * 3600 * 1000 +
- Integer.valueOf(parts[1]) * 1000 * 60;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/DownloadError.java b/app/src/main/java/de/danoeh/antennapod/core/util/DownloadError.java
deleted file mode 100644
index 447e7d256..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/DownloadError.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import android.content.Context;
-import de.danoeh.antennapod.R;
-
-/** Utility class for Download Errors. */
-public enum DownloadError {
- SUCCESS(0, R.string.download_successful),
- ERROR_PARSER_EXCEPTION(1, R.string.download_error_parser_exception),
- ERROR_UNSUPPORTED_TYPE(2, R.string.download_error_unsupported_type),
- ERROR_CONNECTION_ERROR(3, R.string.download_error_connection_error),
- ERROR_MALFORMED_URL(4, R.string.download_error_error_unknown),
- ERROR_IO_ERROR(5, R.string.download_error_io_error),
- ERROR_FILE_EXISTS(6, R.string.download_error_error_unknown),
- ERROR_DOWNLOAD_CANCELLED(7, R.string.download_error_error_unknown),
- ERROR_DEVICE_NOT_FOUND(8, R.string.download_error_device_not_found),
- ERROR_HTTP_DATA_ERROR(9, R.string.download_error_http_data_error),
- ERROR_NOT_ENOUGH_SPACE(10, R.string.download_error_insufficient_space),
- ERROR_UNKNOWN_HOST(11, R.string.download_error_unknown_host),
- ERROR_REQUEST_ERROR(12, R.string.download_error_request_error),
- ERROR_DB_ACCESS_ERROR(13, R.string.download_error_db_access),
- ERROR_UNAUTHORIZED(14, R.string.download_error_unauthorized);
-
- private final int code;
- private final int resId;
-
- private DownloadError(int code, int resId) {
- this.code = code;
- this.resId = resId;
- }
-
- /** Return DownloadError from its associated code. */
- public static DownloadError fromCode(int code) {
- for (DownloadError reason : values()) {
- if (reason.getCode() == code) {
- return reason;
- }
- }
- throw new IllegalArgumentException("unknown code: " + code);
- }
-
- /** Get machine-readable code. */
- public int getCode() {
- return code;
- }
-
- /** Get a human-readable string. */
- public String getErrorString(Context context) {
- return context.getString(resId);
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/DuckType.java b/app/src/main/java/de/danoeh/antennapod/core/util/DuckType.java
deleted file mode 100644
index 5d2803b84..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/DuckType.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/* Adapted from: http://thinking-in-code.blogspot.com/2008/11/duck-typing-in-java-using-dynamic.html */
-
-package de.danoeh.antennapod.core.util;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
-import de.danoeh.antennapod.BuildConfig;
-
-/**
- * Allows "duck typing" or dynamic invocation based on method signature rather
- * than type hierarchy. In other words, rather than checking whether something
- * IS-a duck, check whether it WALKS-like-a duck or QUACKS-like a duck.
- *
- * To use first use the coerce static method to indicate the object you want to
- * do Duck Typing for, then specify an interface to the to method which you want
- * to coerce the type to, e.g:
- *
- * public interface Foo { void aMethod(); } class Bar { ... public void
- * aMethod() { ... } ... } Bar bar = ...; Foo foo =
- * DuckType.coerce(bar).to(Foo.class); foo.aMethod();
- *
- *
- */
-public class DuckType {
-
- private final Object objectToCoerce;
-
- private DuckType(Object objectToCoerce) {
- this.objectToCoerce = objectToCoerce;
- }
-
- private class CoercedProxy implements InvocationHandler {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- Method delegateMethod = findMethodBySignature(method);
- assert delegateMethod != null;
- return delegateMethod.invoke(DuckType.this.objectToCoerce, args);
- }
- }
-
- /**
- * Specify the duck typed object to coerce.
- *
- * @param object
- * the object to coerce
- * @return
- */
- public static DuckType coerce(Object object) {
- return new DuckType(object);
- }
-
- /**
- * Coerce the Duck Typed object to the given interface providing it
- * implements all the necessary methods.
- *
- * @param
- * @param iface
- * @return an instance of the given interface that wraps the duck typed
- * class
- * @throws ClassCastException
- * if the object being coerced does not implement all the
- * methods in the given interface.
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public <T> T to(Class iface) {
- if (BuildConfig.DEBUG && !iface.isInterface()) throw new AssertionError("cannot coerce object to a class, must be an interface");
- if (isA(iface)) {
- return (T) iface.cast(objectToCoerce);
- }
- if (quacksLikeA(iface)) {
- return generateProxy(iface);
- }
- throw new ClassCastException("Could not coerce object of type " + objectToCoerce.getClass() + " to " + iface);
- }
-
- @SuppressWarnings("rawtypes")
- private boolean isA(Class iface) {
- return objectToCoerce.getClass().isInstance(iface);
- }
-
- /**
- * Determine whether the duck typed object can be used with the given
- * interface.
- *
- * @param Type
- * of the interface to check.
- * @param iface
- * Interface class to check
- * @return true if the object will support all the methods in the interface,
- * false otherwise.
- */
- @SuppressWarnings("rawtypes")
- public boolean quacksLikeA(Class iface) {
- for (Method method : iface.getMethods()) {
- if (findMethodBySignature(method) == null) {
- return false;
- }
- }
- return true;
- }
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- private <T> T generateProxy(Class iface) {
- return (T) Proxy.newProxyInstance(iface.getClassLoader(), new Class[] { iface }, new CoercedProxy());
- }
-
- private Method findMethodBySignature(Method method) {
- try {
- return objectToCoerce.getClass().getMethod(method.getName(), method.getParameterTypes());
- } catch (NoSuchMethodException e) {
- return null;
- }
- }
-
-} \ No newline at end of file
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/EpisodeFilter.java b/app/src/main/java/de/danoeh/antennapod/core/util/EpisodeFilter.java
deleted file mode 100644
index 4c23b161b..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/EpisodeFilter.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import de.danoeh.antennapod.core.feed.FeedItem;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class EpisodeFilter {
- private EpisodeFilter() {
-
- }
-
- /** Return a copy of the itemlist without items which have no media. */
- public static ArrayList<FeedItem> getEpisodeList(List<FeedItem> items) {
- ArrayList<FeedItem> episodes = new ArrayList<FeedItem>(items);
- for (FeedItem item : items) {
- if (item.getMedia() == null) {
- episodes.remove(item);
- }
- }
- return episodes;
- }
-
- public static int countItemsWithEpisodes(List<FeedItem> items) {
- int count = 0;
- for (FeedItem item : items) {
- if (item.getMedia() != null) {
- count++;
- }
- }
- return count;
- }
-
- public static FeedItem accessEpisodeByIndex(List<FeedItem> items,
- int position) {
- int count = 0;
- for (FeedItem item : items) {
-
- if (item.getMedia() != null) {
- if (count == position) {
- return item;
- } else {
- count++;
- }
- }
- }
- return null;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/FeedtitleComparator.java b/app/src/main/java/de/danoeh/antennapod/core/util/FeedtitleComparator.java
deleted file mode 100644
index bf14cd23e..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/FeedtitleComparator.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import de.danoeh.antennapod.core.feed.Feed;
-
-import java.util.Comparator;
-
-/** Compares the title of two feeds for sorting. */
-public class FeedtitleComparator implements Comparator<Feed> {
-
- @Override
- public int compare(Feed lhs, Feed rhs) {
- return lhs.getTitle().compareToIgnoreCase(rhs.getTitle());
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java b/app/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java
deleted file mode 100644
index 00c023b64..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import java.util.Arrays;
-
-/** Generates valid filenames for a given string. */
-public class FileNameGenerator {
-
- private static final char[] ILLEGAL_CHARACTERS = { '/', '\\', '?', '%',
- '*', ':', '|', '"', '<', '>' };
- static {
- Arrays.sort(ILLEGAL_CHARACTERS);
- }
-
- private FileNameGenerator() {
-
- }
-
- /**
- * This method will return a new string that doesn't contain any illegal
- * characters of the given string.
- */
- public static String generateFileName(String string) {
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < string.length(); i++) {
- char c = string.charAt(i);
- if (Arrays.binarySearch(ILLEGAL_CHARACTERS, c) < 0) {
- builder.append(c);
- }
- }
- return builder.toString().replaceFirst(" *$","");
- }
-
- public static long generateLong(final String str) {
- return str.hashCode();
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/InvalidFeedException.java b/app/src/main/java/de/danoeh/antennapod/core/util/InvalidFeedException.java
deleted file mode 100644
index c98c2d82a..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/InvalidFeedException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-/** Thrown if a feed has invalid attribute values. */
-public class InvalidFeedException extends Exception {
-
- public InvalidFeedException() {
- }
-
- public InvalidFeedException(String detailMessage) {
- super(detailMessage);
- }
-
- public InvalidFeedException(Throwable throwable) {
- super(throwable);
- }
-
- public InvalidFeedException(String detailMessage, Throwable throwable) {
- super(detailMessage, throwable);
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java b/app/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java
deleted file mode 100644
index 07432d28a..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import java.nio.charset.Charset;
-import java.util.HashMap;
-
-public class LangUtils {
- public static final Charset UTF_8 = Charset.forName("UTF-8");
-
- private static HashMap<String, String> languages;
- static {
- languages = new HashMap<String, String>();
- languages.put("af", "Afrikaans");
- languages.put("sq", "Albanian");
- languages.put("sq", "Albanian");
- languages.put("eu", "Basque");
- languages.put("be", "Belarusian");
- languages.put("bg", "Bulgarian");
- languages.put("ca", "Catalan");
- languages.put("Chinese (Simplified)", "zh-cn");
- languages.put("Chinese (Traditional)", "zh-tw");
- languages.put("hr", "Croatian");
- languages.put("cs", "Czech");
- languages.put("da", "Danish");
- languages.put("nl", "Dutch");
- languages.put("nl-be", "Dutch (Belgium)");
- languages.put("nl-nl", "Dutch (Netherlands)");
- languages.put("en", "English");
- languages.put("en-au", "English (Australia)");
- languages.put("en-bz", "English (Belize)");
- languages.put("en-ca", "English (Canada)");
- languages.put("en-ie", "English (Ireland)");
- languages.put("en-jm", "English (Jamaica)");
- languages.put("en-nz", "English (New Zealand)");
- languages.put("en-ph", "English (Phillipines)");
- languages.put("en-za", "English (South Africa)");
- languages.put("en-tt", "English (Trinidad)");
- languages.put("en-gb", "English (United Kingdom)");
- languages.put("en-us", "English (United States)");
- languages.put("en-zw", "English (Zimbabwe)");
- languages.put("et", "Estonian");
- languages.put("fo", "Faeroese");
- languages.put("fi", "Finnish");
- languages.put("fr", "French");
- languages.put("fr-be", "French (Belgium)");
- languages.put("fr-ca", "French (Canada)");
- languages.put("fr-fr", "French (France)");
- languages.put("fr-lu", "French (Luxembourg)");
- languages.put("fr-mc", "French (Monaco)");
- languages.put("fr-ch", "French (Switzerland)");
- languages.put("gl", "Galician");
- languages.put("gd", "Gaelic");
- languages.put("de", "German");
- languages.put("de-at", "German (Austria)");
- languages.put("de-de", "German (Germany)");
- languages.put("de-li", "German (Liechtenstein)");
- languages.put("de-lu", "German (Luxembourg)");
- languages.put("de-ch", "German (Switzerland)");
- languages.put("el", "Greek");
- languages.put("haw", "Hawaiian");
- languages.put("hu", "Hungarian");
- languages.put("is", "Icelandic");
- languages.put("in", "Indonesian");
- languages.put("ga", "Irish");
- languages.put("it", "Italian");
- languages.put("it-it", "Italian (Italy)");
- languages.put("it-ch", "Italian (Switzerland)");
- languages.put("ja", "Japanese");
- languages.put("ko", "Korean");
- languages.put("mk", "Macedonian");
- languages.put("no", "Norwegian");
- languages.put("pl", "Polish");
- languages.put("pt", "Portugese");
- languages.put("pt-br", "Portugese (Brazil)");
- languages.put("pt-pt", "Portugese (Portugal");
- languages.put("ro", "Romanian");
- languages.put("ro-mo", "Romanian (Moldova)");
- languages.put("ro-ro", "Romanian (Romania");
- languages.put("ru", "Russian");
- languages.put("ru-mo", "Russian (Moldova)");
- languages.put("ru-ru", "Russian (Russia)");
- languages.put("sr", "Serbian");
- languages.put("sk", "Slovak");
- languages.put("sl", "Slovenian");
- languages.put("es", "Spanish");
- languages.put("es-ar", "Spanish (Argentinia)");
- languages.put("es=bo", "Spanish (Bolivia)");
- languages.put("es-cl", "Spanish (Chile)");
- languages.put("es-co", "Spanish (Colombia)");
- languages.put("es-cr", "Spanish (Costa Rica)");
- languages.put("es-do", "Spanish (Dominican Republic)");
- languages.put("es-ec", "Spanish (Ecuador)");
- languages.put("es-sv", "Spanish (El Salvador)");
- languages.put("es-gt", "Spanish (Guatemala)");
- languages.put("es-hn", "Spanish (Honduras)");
- languages.put("es-mx", "Spanish (Mexico)");
- languages.put("es-ni", "Spanish (Nicaragua)");
- languages.put("es-pa", "Spanish (Panama)");
- languages.put("es-py", "Spanish (Paraguay)");
- languages.put("es-pe", "Spanish (Peru)");
- languages.put("es-pr", "Spanish (Puerto Rico)");
- languages.put("es-es", "Spanish (Spain)");
- languages.put("es-uy", "Spanish (Uruguay)");
- languages.put("es-ve", "Spanish (Venezuela)");
- languages.put("sv", "Swedish");
- languages.put("sv-fi", "Swedish (Finland)");
- languages.put("sv-se", "Swedish (Sweden)");
- languages.put("tr", "Turkish");
- languages.put("uk", "Ukranian");
- }
-
- /** Finds language string for key or returns the language key if it can't be found. */
- public static String getLanguageString(String key) {
- String language = languages.get(key);
- if (language != null) {
- return language;
- } else {
- return key;
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java b/app/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java
deleted file mode 100644
index 89bba290c..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-
-import java.util.Arrays;
-import java.util.List;
-
-public class NetworkUtils {
- private static final String TAG = "NetworkUtils";
-
- private NetworkUtils() {
-
- }
-
- /**
- * Returns true if the device is connected to Wi-Fi and the Wi-Fi filter for
- * automatic downloads is disabled or the device is connected to a Wi-Fi
- * network that is on the 'selected networks' list of the Wi-Fi filter for
- * automatic downloads and false otherwise.
- * */
- public static boolean autodownloadNetworkAvailable(Context context) {
- ConnectivityManager cm = (ConnectivityManager) context
- .getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = cm.getActiveNetworkInfo();
- if (networkInfo != null) {
- if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Device is connected to Wi-Fi");
- if (networkInfo.isConnected()) {
- if (!UserPreferences.isEnableAutodownloadWifiFilter()) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Auto-dl filter is disabled");
- return true;
- } else {
- WifiManager wm = (WifiManager) context
- .getSystemService(Context.WIFI_SERVICE);
- WifiInfo wifiInfo = wm.getConnectionInfo();
- List<String> selectedNetworks = Arrays
- .asList(UserPreferences
- .getAutodownloadSelectedNetworks());
- if (selectedNetworks.contains(Integer.toString(wifiInfo
- .getNetworkId()))) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Current network is on the selected networks list");
- return true;
- }
- }
- }
- }
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Network for auto-dl is not available");
- return false;
- }
-
- public static boolean networkAvailable(Context context) {
- ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo info = cm.getActiveNetworkInfo();
- return info != null && info.isConnected();
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/QueueAccess.java b/app/src/main/java/de/danoeh/antennapod/core/util/QueueAccess.java
deleted file mode 100644
index 8e40ae184..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/QueueAccess.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import de.danoeh.antennapod.core.feed.FeedItem;
-
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Provides methods for accessing the queue. It is possible to load only a part of the information about the queue that
- * is stored in the database (e.g. sometimes the user just has to test if a specific item is contained in the List.
- * QueueAccess provides an interface for accessing the queue without having to care about the type of the queue
- * representation.
- */
-public abstract class QueueAccess {
- /**
- * Returns true if the item is in the queue, false otherwise.
- */
- public abstract boolean contains(long id);
-
- /**
- * Removes the item from the queue.
- *
- * @return true if the queue was modified by this operation.
- */
- public abstract boolean remove(long id);
-
- private QueueAccess() {
-
- }
-
- public static QueueAccess IDListAccess(final List<Long> ids) {
- return new QueueAccess() {
- @Override
- public boolean contains(long id) {
- return (ids != null) && ids.contains(id);
- }
-
- @Override
- public boolean remove(long id) {
- return ids.remove(id);
- }
-
-
- };
- }
-
- public static QueueAccess ItemListAccess(final List<FeedItem> items) {
- return new QueueAccess() {
- @Override
- public boolean contains(long id) {
- if (items == null) {
- return false;
- }
- for (FeedItem item : items) {
- if (item.getId() == id) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean remove(long id) {
- Iterator<FeedItem> it = items.iterator();
- FeedItem item;
- while (it.hasNext()) {
- item = it.next();
- if (item.getId() == id) {
- it.remove();
- return true;
- }
- }
- return false;
- }
- };
- }
-
- public static QueueAccess NotInQueueAccess() {
- return new QueueAccess() {
- @Override
- public boolean contains(long id) {
- return false;
- }
-
- @Override
- public boolean remove(long id) {
- return false;
- }
- };
-
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java b/app/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java
deleted file mode 100644
index 85f32ed50..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import android.content.Context;
-import android.content.Intent;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedItem;
-
-/** Utility methods for sharing data */
-public class ShareUtils {
- private static final String TAG = "ShareUtils";
-
- private ShareUtils() {}
-
- public static void shareLink(Context context, String link) {
- Intent i = new Intent(Intent.ACTION_SEND);
- i.setType("text/plain");
- i.putExtra(Intent.EXTRA_SUBJECT, "Sharing URL");
- i.putExtra(Intent.EXTRA_TEXT, link);
- context.startActivity(Intent.createChooser(i, "Share URL"));
- }
-
- public static void shareFeedItemLink(Context context, FeedItem item) {
- shareLink(context, item.getLink());
- }
-
- public static void shareFeedDownloadLink(Context context, Feed feed) {
- shareLink(context, feed.getDownload_url());
- }
-
- public static void shareFeedlink(Context context, Feed feed) {
- shareLink(context, feed.getLink());
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/ShownotesProvider.java b/app/src/main/java/de/danoeh/antennapod/core/util/ShownotesProvider.java
deleted file mode 100644
index 7e7c6c08b..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/ShownotesProvider.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import java.util.concurrent.Callable;
-
-/**
- * Created by daniel on 04.08.13.
- */
-public interface ShownotesProvider {
- /**
- * Loads shownotes. If the shownotes have to be loaded from a file or from a
- * database, it should be done in a separate thread. After the shownotes
- * have been loaded, callback.onShownotesLoaded should be called.
- */
- public Callable<String> loadShownotes();
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java b/app/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java
deleted file mode 100644
index f899c211f..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Build;
-import android.os.StatFs;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.PodcastApp;
-import de.danoeh.antennapod.activity.StorageErrorActivity;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-
-import java.io.File;
-
-/** Utility functions for handling storage errors */
-public class StorageUtils {
- private static final String TAG = "StorageUtils";
-
- public static boolean storageAvailable(Context context) {
- File dir = UserPreferences.getDataFolder(context, null);
- if (dir != null) {
- return dir.exists() && dir.canRead() && dir.canWrite();
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Storage not available: data folder is null");
- return false;
- }
- }
-
- /**
- * Checks if external storage is available. If external storage isn't
- * available, the current activity is finsished an an error activity is
- * launched.
- *
- * @param activity
- * the activity which would be finished if no storage is
- * available
- * @return true if external storage is available
- */
- public static boolean checkStorageAvailability(Activity activity) {
- boolean storageAvailable = storageAvailable(activity);
- if (!storageAvailable) {
- activity.finish();
- activity.startActivity(new Intent(activity,
- StorageErrorActivity.class));
- }
- return storageAvailable;
- }
-
- /** Get the number of free bytes that are available on the external storage. */
- public static long getFreeSpaceAvailable() {
- StatFs stat = new StatFs(UserPreferences.getDataFolder(
- PodcastApp.getInstance(), null).getAbsolutePath());
- long availableBlocks;
- long blockSize;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- availableBlocks = stat.getAvailableBlocksLong();
- blockSize = stat.getBlockSizeLong();
- } else {
- availableBlocks = stat.getAvailableBlocks();
- blockSize = stat.getBlockSize();
- }
- return availableBlocks * blockSize;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/ThemeUtils.java b/app/src/main/java/de/danoeh/antennapod/core/util/ThemeUtils.java
deleted file mode 100644
index 72d73138d..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/ThemeUtils.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import android.util.Log;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-
-public class ThemeUtils {
- private static final String TAG = "ThemeUtils";
-
- public static int getSelectionBackgroundColor() {
- switch (UserPreferences.getTheme()) {
- case R.style.Theme_AntennaPod_Dark:
- return R.color.selection_background_color_dark;
- case R.style.Theme_AntennaPod_Light:
- return R.color.selection_background_color_light;
- default:
- Log.e(TAG,
- "getSelectionBackgroundColor could not match the current theme to any color!");
- return R.color.selection_background_color_light;
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/URIUtil.java b/app/src/main/java/de/danoeh/antennapod/core/util/URIUtil.java
deleted file mode 100644
index c614abbc1..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/URIUtil.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-
-/**
- * Utility methods for dealing with URL encoding.
- */
-public class URIUtil {
- private static final String TAG = "URIUtil";
-
- private URIUtil() {}
-
- public static URI getURIFromRequestUrl(String source) {
- // try without encoding the URI
- try {
- return new URI(source);
- } catch (URISyntaxException e) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Source is not encoded, encoding now");
- }
- try {
- URL url = new URL(source);
- return new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
- } catch (MalformedURLException e) {
- throw new IllegalArgumentException(e);
- } catch (URISyntaxException e) {
- throw new IllegalArgumentException(e);
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java b/app/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java
deleted file mode 100644
index c707e55bc..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import android.util.Log;
-
-import org.apache.commons.lang3.StringUtils;
-
-import de.danoeh.antennapod.BuildConfig;
-
-/**
- * Provides methods for checking and editing a URL.
- */
-public final class URLChecker {
-
- /**
- * Class shall not be instantiated.
- */
- private URLChecker() {
- }
-
- /**
- * Logging tag.
- */
- private static final String TAG = "URLChecker";
-
- /**
- * Checks if URL is valid and modifies it if necessary.
- *
- * @param url The url which is going to be prepared
- * @return The prepared url
- */
- public static String prepareURL(String url) {
- StringBuilder builder = new StringBuilder();
- url = StringUtils.trim(url);
- if (url.startsWith("feed://")) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Replacing feed:// with http://");
- url = url.replaceFirst("feed://", "http://");
- } else if (url.startsWith("pcast://")) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Replacing pcast:// with http://");
- url = url.replaceFirst("pcast://", "http://");
- } else if (url.startsWith("itpc")) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Replacing itpc:// with http://");
- url = url.replaceFirst("itpc://", "http://");
- } else if (!(url.startsWith("http://") || url.startsWith("https://"))) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Adding http:// at the beginning of the URL");
- builder.append("http://");
- }
- builder.append(url);
-
- return builder.toString();
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/UndoBarController.java b/app/src/main/java/de/danoeh/antennapod/core/util/UndoBarController.java
deleted file mode 100644
index d0721ac23..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/UndoBarController.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2012 Roman Nurik
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package de.danoeh.antennapod.core.util;
-
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.view.View;
-import android.widget.TextView;
-import com.nineoldandroids.animation.Animator;
-import com.nineoldandroids.animation.AnimatorListenerAdapter;
-import com.nineoldandroids.view.ViewHelper;
-import com.nineoldandroids.view.ViewPropertyAnimator;
-import de.danoeh.antennapod.R;
-
-import static com.nineoldandroids.view.ViewPropertyAnimator.animate;
-
-public class UndoBarController {
- private View mBarView;
- private TextView mMessageView;
- private ViewPropertyAnimator mBarAnimator;
- private Handler mHideHandler = new Handler();
-
- private UndoListener mUndoListener;
-
- // State objects
- private Parcelable mUndoToken;
- private CharSequence mUndoMessage;
-
- public interface UndoListener {
- void onUndo(Parcelable token);
- }
-
- public UndoBarController(View undoBarView, UndoListener undoListener) {
- mBarView = undoBarView;
- mBarAnimator = animate(mBarView);
- mUndoListener = undoListener;
-
- mMessageView = (TextView) mBarView.findViewById(R.id.undobar_message);
- mBarView.findViewById(R.id.undobar_button)
- .setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- hideUndoBar(false);
- mUndoListener.onUndo(mUndoToken);
- }
- });
-
- hideUndoBar(true);
- }
-
- public void showUndoBar(boolean immediate, CharSequence message, Parcelable undoToken) {
- mUndoToken = undoToken;
- mUndoMessage = message;
- mMessageView.setText(mUndoMessage);
-
- mHideHandler.removeCallbacks(mHideRunnable);
- mHideHandler.postDelayed(mHideRunnable,
- mBarView.getResources().getInteger(R.integer.undobar_hide_delay));
-
- mBarView.setVisibility(View.VISIBLE);
- if (immediate) {
- ViewHelper.setAlpha(mBarView, 1);
- } else {
- mBarAnimator.cancel();
- mBarAnimator
- .alpha(1)
- .setDuration(
- mBarView.getResources()
- .getInteger(android.R.integer.config_shortAnimTime))
- .setListener(null);
- }
- }
-
- public void hideUndoBar(boolean immediate) {
- mHideHandler.removeCallbacks(mHideRunnable);
- if (immediate) {
- mBarView.setVisibility(View.GONE);
- ViewHelper.setAlpha(mBarView, 0);
- mUndoMessage = null;
- mUndoToken = null;
-
- } else {
- mBarAnimator.cancel();
- mBarAnimator
- .alpha(0)
- .setDuration(mBarView.getResources()
- .getInteger(android.R.integer.config_shortAnimTime))
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mBarView.setVisibility(View.GONE);
- mUndoMessage = null;
- mUndoToken = null;
- }
- });
- }
- }
-
- public void onSaveInstanceState(Bundle outState) {
- outState.putCharSequence("undo_message", mUndoMessage);
- outState.putParcelable("undo_token", mUndoToken);
- }
-
- public void onRestoreInstanceState(Bundle savedInstanceState) {
- if (savedInstanceState != null) {
- mUndoMessage = savedInstanceState.getCharSequence("undo_message");
- mUndoToken = savedInstanceState.getParcelable("undo_token");
-
- if (mUndoToken != null || !TextUtils.isEmpty(mUndoMessage)) {
- showUndoBar(true, mUndoMessage, mUndoToken);
- }
- }
- }
-
- private Runnable mHideRunnable = new Runnable() {
- @Override
- public void run() {
- hideUndoBar(false);
- }
- };
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/comparator/ChapterStartTimeComparator.java b/app/src/main/java/de/danoeh/antennapod/core/util/comparator/ChapterStartTimeComparator.java
deleted file mode 100644
index 5274ffc9e..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/comparator/ChapterStartTimeComparator.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package de.danoeh.antennapod.core.util.comparator;
-
-import de.danoeh.antennapod.core.feed.Chapter;
-
-import java.util.Comparator;
-
-public class ChapterStartTimeComparator implements Comparator<Chapter> {
-
- @Override
- public int compare(Chapter lhs, Chapter rhs) {
- if (lhs.getStart() == rhs.getStart()) {
- return 0;
- } else if (lhs.getStart() < rhs.getStart()) {
- return -1;
- } else {
- return 1;
- }
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/comparator/DownloadStatusComparator.java b/app/src/main/java/de/danoeh/antennapod/core/util/comparator/DownloadStatusComparator.java
deleted file mode 100644
index ebdbfe2a5..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/comparator/DownloadStatusComparator.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package de.danoeh.antennapod.core.util.comparator;
-
-import de.danoeh.antennapod.core.service.download.DownloadStatus;
-
-import java.util.Comparator;
-
-/** Compares the completion date of two Downloadstatus objects. */
-public class DownloadStatusComparator implements Comparator<DownloadStatus> {
-
- @Override
- public int compare(DownloadStatus lhs, DownloadStatus rhs) {
- return rhs.getCompletionDate().compareTo(lhs.getCompletionDate());
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/comparator/FeedItemPubdateComparator.java b/app/src/main/java/de/danoeh/antennapod/core/util/comparator/FeedItemPubdateComparator.java
deleted file mode 100644
index a1f3ec699..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/comparator/FeedItemPubdateComparator.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package de.danoeh.antennapod.core.util.comparator;
-
-import de.danoeh.antennapod.core.feed.FeedItem;
-
-import java.util.Comparator;
-
-/** Compares the pubDate of two FeedItems for sorting*/
-public class FeedItemPubdateComparator implements Comparator<FeedItem> {
-
- /** Returns a new instance of this comparator in reverse order.
- public static FeedItemPubdateComparator newInstance() {
- FeedItemPubdateComparator
- }*/
- @Override
- public int compare(FeedItem lhs, FeedItem rhs) {
- return rhs.getPubDate().compareTo(lhs.getPubDate());
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/comparator/PlaybackCompletionDateComparator.java b/app/src/main/java/de/danoeh/antennapod/core/util/comparator/PlaybackCompletionDateComparator.java
deleted file mode 100644
index 84d244660..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/comparator/PlaybackCompletionDateComparator.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package de.danoeh.antennapod.core.util.comparator;
-
-import de.danoeh.antennapod.core.feed.FeedItem;
-
-import java.util.Comparator;
-
-public class PlaybackCompletionDateComparator implements Comparator<FeedItem> {
-
- public int compare(FeedItem lhs, FeedItem rhs) {
- if (lhs.getMedia() != null
- && lhs.getMedia().getPlaybackCompletionDate() != null
- && rhs.getMedia() != null
- && rhs.getMedia().getPlaybackCompletionDate() != null) {
- return rhs.getMedia().getPlaybackCompletionDate()
- .compareTo(lhs.getMedia().getPlaybackCompletionDate());
- }
- return 0;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/comparator/SearchResultValueComparator.java b/app/src/main/java/de/danoeh/antennapod/core/util/comparator/SearchResultValueComparator.java
deleted file mode 100644
index b16e0949d..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/comparator/SearchResultValueComparator.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package de.danoeh.antennapod.core.util.comparator;
-
-import de.danoeh.antennapod.core.feed.SearchResult;
-
-import java.util.Comparator;
-
-public class SearchResultValueComparator implements Comparator<SearchResult> {
-
- @Override
- public int compare(SearchResult lhs, SearchResult rhs) {
- return rhs.getValue() - lhs.getValue();
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/exception/MediaFileNotFoundException.java b/app/src/main/java/de/danoeh/antennapod/core/util/exception/MediaFileNotFoundException.java
deleted file mode 100644
index 287fe1100..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/exception/MediaFileNotFoundException.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package de.danoeh.antennapod.core.util.exception;
-
-import de.danoeh.antennapod.core.feed.FeedMedia;
-
-public class MediaFileNotFoundException extends Exception {
- private static final long serialVersionUID = 1L;
-
- private FeedMedia media;
-
- public MediaFileNotFoundException(String msg, FeedMedia media) {
- super(msg);
- this.media = media;
- }
-
- public MediaFileNotFoundException(FeedMedia media) {
- super();
- this.media = media;
- }
-
- public FeedMedia getMedia() {
- return media;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrServiceCreator.java b/app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrServiceCreator.java
deleted file mode 100644
index 5a7cfa47f..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrServiceCreator.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package de.danoeh.antennapod.core.util.flattr;
-
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import org.shredzone.flattr4j.FlattrFactory;
-import org.shredzone.flattr4j.FlattrService;
-import org.shredzone.flattr4j.oauth.AccessToken;
-
-/** Ensures that only one instance of the FlattrService class exists at a time */
-
-public class FlattrServiceCreator {
- public static final String TAG = "FlattrServiceCreator";
-
- private static volatile FlattrService flattrService;
-
- public static FlattrService getService(AccessToken token) {
- return FlattrFactory.getInstance().createFlattrService(token);
- }
-
- public static void deleteFlattrService() {
- if (BuildConfig.DEBUG) Log.d(TAG, "Deleting service instance");
- flattrService = null;
- }
-}
-
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrStatus.java b/app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrStatus.java
deleted file mode 100644
index d82171d1a..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrStatus.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package de.danoeh.antennapod.core.util.flattr;
-
-import java.util.Calendar;
-
-public class FlattrStatus {
- public static final int STATUS_UNFLATTERED = 0;
- public static final int STATUS_QUEUE = 1;
- public static final int STATUS_FLATTRED = 2;
-
- private int status = STATUS_UNFLATTERED;
- private Calendar lastFlattred;
-
- public FlattrStatus() {
- status = STATUS_UNFLATTERED;
- lastFlattred = Calendar.getInstance();
- }
-
- public FlattrStatus(long status) {
- lastFlattred = Calendar.getInstance();
- fromLong(status);
- }
-
- public void setFlattred() {
- status = STATUS_FLATTRED;
- lastFlattred = Calendar.getInstance();
- }
-
- public void setUnflattred() {
- status = STATUS_UNFLATTERED;
- }
-
- public boolean getUnflattred() {
- return status == STATUS_UNFLATTERED;
- }
-
- public void setFlattrQueue() {
- if (flattrable())
- status = STATUS_QUEUE;
- }
-
- public void fromLong(long status) {
- if (status == STATUS_UNFLATTERED || status == STATUS_QUEUE)
- this.status = (int) status;
- else {
- this.status = STATUS_FLATTRED;
- lastFlattred.setTimeInMillis(status);
- }
- }
-
- public long toLong() {
- if (status == STATUS_UNFLATTERED || status == STATUS_QUEUE)
- return status;
- else {
- return lastFlattred.getTimeInMillis();
- }
- }
-
- public boolean flattrable() {
- Calendar firstOfMonth = Calendar.getInstance();
- firstOfMonth.set(Calendar.DAY_OF_MONTH, Calendar.getInstance().getActualMinimum(Calendar.DAY_OF_MONTH));
-
- return (status == STATUS_UNFLATTERED) || (status == STATUS_FLATTRED && firstOfMonth.after(lastFlattred) );
- }
-
- public boolean getFlattrQueue() {
- return status == STATUS_QUEUE;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrThing.java b/app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrThing.java
deleted file mode 100644
index 515028ab6..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrThing.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package de.danoeh.antennapod.core.util.flattr;
-
-public interface FlattrThing {
- public String getTitle();
- public String getPaymentLink();
- public FlattrStatus getFlattrStatus();
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrUtils.java b/app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrUtils.java
deleted file mode 100644
index e07ed11e9..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrUtils.java
+++ /dev/null
@@ -1,305 +0,0 @@
-package de.danoeh.antennapod.core.util.flattr;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.Uri;
-import android.preference.PreferenceManager;
-import android.util.Log;
-
-import org.apache.commons.lang3.StringUtils;
-import org.shredzone.flattr4j.FlattrService;
-import org.shredzone.flattr4j.exception.FlattrException;
-import org.shredzone.flattr4j.model.Flattr;
-import org.shredzone.flattr4j.model.Thing;
-import org.shredzone.flattr4j.oauth.AccessToken;
-import org.shredzone.flattr4j.oauth.AndroidAuthenticator;
-import org.shredzone.flattr4j.oauth.Scope;
-
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.TimeZone;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.PodcastApp;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.FlattrAuthActivity;
-import de.danoeh.antennapod.core.asynctask.FlattrTokenFetcher;
-import de.danoeh.antennapod.core.storage.DBWriter;
-
-/**
- * Utility methods for doing something with flattr.
- */
-
-public class FlattrUtils {
- private static final String TAG = "FlattrUtils";
-
- private static final String HOST_NAME = "de.danoeh.antennapod";
-
- private static final String PREF_ACCESS_TOKEN = "de.danoeh.antennapod.preference.flattrAccessToken";
-
- // Flattr URL for this app.
- public static final String APP_URL = "http://antennapod.com";
- // Human-readable flattr-page.
- public static final String APP_LINK = "https://flattr.com/thing/745609/";
- public static final String APP_THING_ID = "745609";
-
- private static volatile AccessToken cachedToken;
-
- private static AndroidAuthenticator createAuthenticator() {
- return new AndroidAuthenticator(HOST_NAME, BuildConfig.FLATTR_APP_KEY,
- BuildConfig.FLATTR_APP_SECRET);
- }
-
- public static void startAuthProcess(Context context) throws FlattrException {
- AndroidAuthenticator auth = createAuthenticator();
- auth.setScope(EnumSet.of(Scope.FLATTR));
- Intent intent = auth.createAuthenticateIntent();
- context.startActivity(intent);
- }
-
- private static AccessToken retrieveToken() {
- if (cachedToken == null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Retrieving access token");
- String token = PreferenceManager.getDefaultSharedPreferences(
- PodcastApp.getInstance())
- .getString(PREF_ACCESS_TOKEN, null);
- if (token != null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Found access token. Caching.");
- cachedToken = new AccessToken(token);
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "No access token found");
- return null;
- }
- }
- return cachedToken;
-
- }
-
- /**
- * Returns true if FLATTR_APP_KEY and FLATTR_APP_SECRET in BuildConfig are not null and not empty
- */
- public static boolean hasAPICredentials() {
- return StringUtils.isNotEmpty(BuildConfig.FLATTR_APP_KEY)
- && StringUtils.isNotEmpty(BuildConfig.FLATTR_APP_SECRET);
- }
-
- public static boolean hasToken() {
- return retrieveToken() != null;
- }
-
- public static void storeToken(AccessToken token) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Storing token");
- SharedPreferences.Editor editor = PreferenceManager
- .getDefaultSharedPreferences(PodcastApp.getInstance()).edit();
- if (token != null) {
- editor.putString(PREF_ACCESS_TOKEN, token.getToken());
- } else {
- editor.putString(PREF_ACCESS_TOKEN, null);
- }
- editor.commit();
- cachedToken = token;
- }
-
- public static void deleteToken() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Deleting flattr token");
- storeToken(null);
- }
-
- public static Thing getAppThing(Context context) {
- FlattrService fs = FlattrServiceCreator.getService(retrieveToken());
- try {
- Thing thing = fs.getThing(Thing.withId(APP_THING_ID));
- return thing;
- } catch (FlattrException e) {
- e.printStackTrace();
- showErrorDialog(context, e.getMessage());
- return null;
- }
- }
-
- public static void clickUrl(Context context, String url)
- throws FlattrException {
- if (hasToken()) {
- FlattrService fs = FlattrServiceCreator.getService(retrieveToken());
- fs.click(url);
- } else {
- Log.e(TAG, "clickUrl was called with null access token");
- }
- }
-
- public static List<Flattr> retrieveFlattredThings()
- throws FlattrException {
- ArrayList<Flattr> myFlattrs = new ArrayList<Flattr>();
-
- if (hasToken()) {
- FlattrService fs = FlattrServiceCreator.getService(retrieveToken());
-
- Calendar firstOfMonth = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- firstOfMonth.set(Calendar.MILLISECOND, 0);
- firstOfMonth.set(Calendar.SECOND, 0);
- firstOfMonth.set(Calendar.MINUTE, 0);
- firstOfMonth.set(Calendar.HOUR_OF_DAY, 0);
- firstOfMonth.set(Calendar.DAY_OF_MONTH, Calendar.getInstance().getActualMinimum(Calendar.DAY_OF_MONTH));
-
- Date firstOfMonthDate = firstOfMonth.getTime();
-
- // subscriptions some times get flattrd slightly before midnight - give it an hour leeway
- firstOfMonthDate = new Date(firstOfMonthDate.getTime() - 60 * 60 * 1000);
-
- final int FLATTR_COUNT = 30;
- final int FLATTR_MAXPAGE = 5;
-
- for (int page = 0; page < FLATTR_MAXPAGE; page++) {
- for (Flattr fl : fs.getMyFlattrs(FLATTR_COUNT, page)) {
- if (fl.getCreated().after(firstOfMonthDate))
- myFlattrs.add(fl);
- else
- break;
- }
- }
-
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "Got my flattrs list of length " + Integer.toString(myFlattrs.size()) + " comparison date" + firstOfMonthDate);
-
- for (Flattr fl : myFlattrs) {
- Thing thing = fl.getThing();
- Log.d(TAG, "Flattr thing: " + fl.getThingId() + " name: " + thing.getTitle() + " url: " + thing.getUrl() + " on: " + fl.getCreated());
- }
- }
-
- } else {
- Log.e(TAG, "retrieveFlattrdThings was called with null access token");
- }
-
- return myFlattrs;
- }
-
- public static void handleCallback(Context context, Uri uri) {
- AndroidAuthenticator auth = createAuthenticator();
- new FlattrTokenFetcher(context, auth, uri).executeAsync();
- }
-
- public static void revokeAccessToken(Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Revoking access token");
- deleteToken();
- FlattrServiceCreator.deleteFlattrService();
- showRevokeDialog(context);
- DBWriter.clearAllFlattrStatus(context);
- }
-
- // ------------------------------------------------ DIALOGS
-
- public static void showRevokeDialog(final Context context) {
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.access_revoked_title);
- builder.setMessage(R.string.access_revoked_info);
- builder.setNeutralButton(android.R.string.ok, new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.cancel();
- }
- });
- builder.create().show();
- }
-
- /**
- * Opens a dialog that ask the user to either connect the app with flattr or to be redirected to
- * the thing's website.
- * If no API credentials are available, the user will immediately be redirected to the thing's website.
- * */
- public static void showNoTokenDialogOrRedirect(final Context context, final String url) {
- if (hasAPICredentials()) {
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.no_flattr_token_title);
- builder.setMessage(R.string.no_flattr_token_msg);
- builder.setPositiveButton(R.string.authenticate_now_label,
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- context.startActivity(new Intent(context,
- FlattrAuthActivity.class));
- }
-
- }
- );
-
- builder.setNegativeButton(R.string.visit_website_label,
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- Uri uri = Uri.parse(url);
- context.startActivity(new Intent(Intent.ACTION_VIEW,
- uri));
- }
-
- }
- );
- builder.create().show();
- } else {
- Uri uri = Uri.parse(url);
- context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
- }
- }
-
- public static void showForbiddenDialog(final Context context,
- final String url) {
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.action_forbidden_title);
- builder.setMessage(R.string.action_forbidden_msg);
- builder.setPositiveButton(R.string.authenticate_now_label,
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- context.startActivity(new Intent(context,
- FlattrAuthActivity.class));
- }
-
- }
- );
- builder.setNegativeButton(R.string.visit_website_label,
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- Uri uri = Uri.parse(url);
- context.startActivity(new Intent(Intent.ACTION_VIEW,
- uri));
- }
-
- }
- );
- builder.create().show();
- }
-
- public static void showErrorDialog(final Context context, final String msg) {
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.error_label);
- builder.setMessage(msg);
- builder.setNeutralButton(android.R.string.ok, new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.cancel();
- }
- });
- builder.create().show();
- }
-
-} \ No newline at end of file
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/flattr/SimpleFlattrThing.java b/app/src/main/java/de/danoeh/antennapod/core/util/flattr/SimpleFlattrThing.java
deleted file mode 100644
index 2c178496e..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/flattr/SimpleFlattrThing.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package de.danoeh.antennapod.core.util.flattr;
-
-/* SimpleFlattrThing is a trivial implementation of the FlattrThing interface */
-public class SimpleFlattrThing implements FlattrThing {
- public SimpleFlattrThing(String title, String url, FlattrStatus status)
- {
- this.title = title;
- this.url = url;
- this.status = status;
- }
-
- public String getTitle()
- {
- return this.title;
- }
-
- public String getPaymentLink()
- {
- return this.url;
- }
-
- public FlattrStatus getFlattrStatus()
- {
- return this.status;
- }
-
- private String title;
- private String url;
- private FlattrStatus status;
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/gui/FeedItemUndoToken.java b/app/src/main/java/de/danoeh/antennapod/core/util/gui/FeedItemUndoToken.java
deleted file mode 100644
index 17581d3e9..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/gui/FeedItemUndoToken.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package de.danoeh.antennapod.core.util.gui;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import de.danoeh.antennapod.core.feed.FeedItem;
-
-/**
- * Used by an UndoBarController for saving a removed FeedItem
- */
-public class FeedItemUndoToken implements Parcelable {
- private long itemId;
- private long feedId;
- private int position;
-
- public FeedItemUndoToken(FeedItem item, int position) {
- this.itemId = item.getId();
- this.feedId = item.getFeed().getId();
- this.position = position;
- }
-
- private FeedItemUndoToken(Parcel in) {
- itemId = in.readLong();
- feedId = in.readLong();
- position = in.readInt();
- }
-
- public static final Parcelable.Creator<FeedItemUndoToken> CREATOR = new Parcelable.Creator<FeedItemUndoToken>() {
- public FeedItemUndoToken createFromParcel(Parcel in) {
- return new FeedItemUndoToken(in);
- }
-
- public FeedItemUndoToken[] newArray(int size) {
- return new FeedItemUndoToken[size];
- }
- };
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeLong(itemId);
- out.writeLong(feedId);
- out.writeInt(position);
- }
-
- public long getFeedItemId() {
- return itemId;
- }
-
- public int getPosition() {
- return position;
- }
-}
-
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java b/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java
deleted file mode 100644
index a0bce1c79..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package de.danoeh.antennapod.core.util.id3reader;
-
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.feed.Chapter;
-import de.danoeh.antennapod.core.feed.ID3Chapter;
-import de.danoeh.antennapod.core.util.id3reader.model.FrameHeader;
-import de.danoeh.antennapod.core.util.id3reader.model.TagHeader;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.List;
-
-public class ChapterReader extends ID3Reader {
- private static final String TAG = "ID3ChapterReader";
-
- private static final String FRAME_ID_CHAPTER = "CHAP";
- private static final String FRAME_ID_TITLE = "TIT2";
- private static final String FRAME_ID_LINK = "WXXX";
-
- private List<Chapter> chapters;
- private ID3Chapter currentChapter;
-
- @Override
- public int onStartTagHeader(TagHeader header) {
- chapters = new ArrayList<Chapter>();
- System.out.println(header.toString());
- return ID3Reader.ACTION_DONT_SKIP;
- }
-
- @Override
- public int onStartFrameHeader(FrameHeader header, InputStream input)
- throws IOException, ID3ReaderException {
- System.out.println(header.toString());
- if (header.getId().equals(FRAME_ID_CHAPTER)) {
- if (currentChapter != null) {
- if (!hasId3Chapter(currentChapter)) {
- chapters.add(currentChapter);
- if (BuildConfig.DEBUG) Log.d(TAG, "Found chapter: " + currentChapter);
- currentChapter = null;
- }
- }
- StringBuffer elementId = new StringBuffer();
- readISOString(elementId, input, Integer.MAX_VALUE);
- char[] startTimeSource = readBytes(input, 4);
- long startTime = ((int) startTimeSource[0] << 24)
- | ((int) startTimeSource[1] << 16)
- | ((int) startTimeSource[2] << 8) | startTimeSource[3];
- currentChapter = new ID3Chapter(elementId.toString(), startTime);
- skipBytes(input, 12);
- return ID3Reader.ACTION_DONT_SKIP;
- } else if (header.getId().equals(FRAME_ID_TITLE)) {
- if (currentChapter != null && currentChapter.getTitle() == null) {
- StringBuffer title = new StringBuffer();
- readString(title, input, header.getSize());
- currentChapter
- .setTitle(title.toString());
- if (BuildConfig.DEBUG) Log.d(TAG, "Found title: " + currentChapter.getTitle());
-
- return ID3Reader.ACTION_DONT_SKIP;
- }
- } else if (header.getId().equals(FRAME_ID_LINK)) {
- if (currentChapter != null) {
- // skip description
- int descriptionLength = readString(null, input, header.getSize());
- StringBuffer link = new StringBuffer();
- readISOString(link, input, header.getSize() - descriptionLength);
- String decodedLink = URLDecoder.decode(link.toString(), "UTF-8");
-
- currentChapter.setLink(decodedLink);
-
- if (BuildConfig.DEBUG) Log.d(TAG, "Found link: " + currentChapter.getLink());
- return ID3Reader.ACTION_DONT_SKIP;
- }
- } else if (header.getId().equals("APIC")) {
- Log.d(TAG, header.toString());
- }
-
- return super.onStartFrameHeader(header, input);
- }
-
- private boolean hasId3Chapter(ID3Chapter chapter) {
- for (Chapter c : chapters) {
- if (((ID3Chapter) c).getId3ID().equals(chapter.getId3ID())) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public void onEndTag() {
- if (currentChapter != null) {
- if (!hasId3Chapter(currentChapter)) {
- chapters.add(currentChapter);
- }
- }
- System.out.println("Reached end of tag");
- if (chapters != null) {
- for (Chapter c : chapters) {
- System.out.println(c.toString());
- }
- }
- }
-
- @Override
- public void onNoTagHeaderFound() {
- System.out.println("No tag header found");
- super.onNoTagHeaderFound();
- }
-
- public List<Chapter> getChapters() {
- return chapters;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java b/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java
deleted file mode 100644
index a238c11e9..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java
+++ /dev/null
@@ -1,250 +0,0 @@
-package de.danoeh.antennapod.core.util.id3reader;
-
-import de.danoeh.antennapod.core.util.id3reader.model.FrameHeader;
-import de.danoeh.antennapod.core.util.id3reader.model.TagHeader;
-import org.apache.commons.io.IOUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-
-/**
- * Reads the ID3 Tag of a given file. In order to use this class, you should
- * create a subclass of it and overwrite the onStart* - or onEnd* - methods.
- */
-public class ID3Reader {
- private static final int HEADER_LENGTH = 10;
- private static final int ID3_LENGTH = 3;
- private static final int FRAME_ID_LENGTH = 4;
-
- protected static final int ACTION_SKIP = 1;
- protected static final int ACTION_DONT_SKIP = 2;
-
- protected int readerPosition;
-
- private static final byte ENCODING_UTF16_WITH_BOM = 1;
- private static final byte ENCODING_UTF16_WITHOUT_BOM = 2;
- private static final byte ENCODING_UTF8 = 3;
-
- private TagHeader tagHeader;
-
- public ID3Reader() {
- }
-
- public final void readInputStream(InputStream input) throws IOException,
- ID3ReaderException {
- int rc;
- readerPosition = 0;
- char[] tagHeaderSource = readBytes(input, HEADER_LENGTH);
- tagHeader = createTagHeader(tagHeaderSource);
- if (tagHeader == null) {
- onNoTagHeaderFound();
- } else {
- rc = onStartTagHeader(tagHeader);
- if (rc == ACTION_SKIP) {
- onEndTag();
- } else {
- while (readerPosition < tagHeader.getSize()) {
- FrameHeader frameHeader = createFrameHeader(readBytes(
- input, HEADER_LENGTH));
- if (checkForNullString(frameHeader.getId())) {
- break;
- } else {
- rc = onStartFrameHeader(frameHeader, input);
- if (rc == ACTION_SKIP) {
-
- if (frameHeader.getSize() + readerPosition > tagHeader
- .getSize()) {
- break;
- } else {
- skipBytes(input, frameHeader.getSize());
- }
- }
- }
- }
- onEndTag();
- }
- }
- }
-
- /** Returns true if string only contains null-bytes. */
- private boolean checkForNullString(String s) {
- if (!s.isEmpty()) {
- int i = 0;
- if (s.charAt(i) == 0) {
- for (i = 1; i < s.length(); i++) {
- if (s.charAt(i) != 0) {
- return false;
- }
- }
- return true;
- }
- return false;
- } else {
- return true;
- }
-
- }
-
- /**
- * Read a certain number of bytes from the given input stream. This method
- * changes the readerPosition-attribute.
- */
- protected char[] readBytes(InputStream input, int number)
- throws IOException, ID3ReaderException {
- char[] header = new char[number];
- for (int i = 0; i < number; i++) {
- int b = input.read();
- readerPosition++;
- if (b != -1) {
- header[i] = (char) b;
- } else {
- throw new ID3ReaderException("Unexpected end of stream");
- }
- }
- return header;
- }
-
- /**
- * Skip a certain number of bytes on the given input stream. This method
- * changes the readerPosition-attribute.
- */
- protected void skipBytes(InputStream input, int number) throws IOException {
- if (number <= 0) {
- number = 1;
- }
- IOUtils.skipFully(input, number);
-
- readerPosition += number;
- }
-
- private TagHeader createTagHeader(char[] source) throws ID3ReaderException {
- boolean hasTag = (source[0] == 0x49) && (source[1] == 0x44)
- && (source[2] == 0x33);
- if (source.length != HEADER_LENGTH) {
- throw new ID3ReaderException("Length of header must be "
- + HEADER_LENGTH);
- }
- if (hasTag) {
- String id = new String(source, 0, ID3_LENGTH);
- char version = (char) ((source[3] << 8) | source[4]);
- byte flags = (byte) source[5];
- int size = (source[6] << 24) | (source[7] << 16) | (source[8] << 8)
- | source[9];
- size = unsynchsafe(size);
- return new TagHeader(id, size, version, flags);
- } else {
- return null;
- }
- }
-
- private FrameHeader createFrameHeader(char[] source)
- throws ID3ReaderException {
- if (source.length != HEADER_LENGTH) {
- throw new ID3ReaderException("Length of header must be "
- + HEADER_LENGTH);
- }
- String id = new String(source, 0, FRAME_ID_LENGTH);
-
- int size = (((int) source[4]) << 24) | (((int) source[5]) << 16)
- | (((int) source[6]) << 8) | source[7];
- if (tagHeader != null && tagHeader.getVersion() >= 0x0400) {
- size = unsynchsafe(size);
- }
- char flags = (char) ((source[8] << 8) | source[9]);
- return new FrameHeader(id, size, flags);
- }
-
- private int unsynchsafe(int in) {
- int out = 0;
- int mask = 0x7F000000;
-
- while (mask != 0) {
- out >>= 1;
- out |= in & mask;
- mask >>= 8;
- }
-
- return out;
- }
-
- protected int readString(StringBuffer buffer, InputStream input, int max) throws IOException,
- ID3ReaderException {
- if (max > 0) {
- char[] encoding = readBytes(input, 1);
- max--;
-
- if (encoding[0] == ENCODING_UTF16_WITH_BOM || encoding[0] == ENCODING_UTF16_WITHOUT_BOM) {
- return readUnicodeString(buffer, input, max, Charset.forName("UTF-16")) + 1; // take encoding byte into account
- } else if (encoding[0] == ENCODING_UTF8) {
- return readUnicodeString(buffer, input, max, Charset.forName("UTF-8")) + 1; // take encoding byte into account
- } else {
- return readISOString(buffer, input, max) + 1; // take encoding byte into account
- }
- } else {
- if (buffer != null) {
- buffer.append("");
- }
- return 0;
- }
- }
-
- protected int readISOString(StringBuffer buffer, InputStream input, int max)
- throws IOException, ID3ReaderException {
-
- int bytesRead = 0;
- char c;
- while (++bytesRead <= max && (c = (char) input.read()) > 0) {
- if (buffer != null) {
- buffer.append(c);
- }
- }
- return bytesRead;
- }
-
- private int readUnicodeString(StringBuffer strBuffer, InputStream input, int max, Charset charset)
- throws IOException, ID3ReaderException {
- byte[] buffer = new byte[max];
- int c, cZero = -1;
- int i = 0;
- for (; i < max; i++) {
- c = input.read();
- if (c == -1) {
- break;
- } else if (c == 0) {
- if (cZero == 0) {
- // termination character found
- break;
- } else {
- cZero = 0;
- }
- } else {
- buffer[i] = (byte) c;
- cZero = -1;
- }
- }
- if (strBuffer != null) {
- strBuffer.append(charset.newDecoder().decode(ByteBuffer.wrap(buffer)).toString());
- }
- return i;
- }
-
- public int onStartTagHeader(TagHeader header) {
- return ACTION_SKIP;
- }
-
- public int onStartFrameHeader(FrameHeader header, InputStream input)
- throws IOException, ID3ReaderException {
- return ACTION_SKIP;
- }
-
- public void onEndTag() {
-
- }
-
- public void onNoTagHeaderFound() {
-
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3ReaderException.java b/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3ReaderException.java
deleted file mode 100644
index 0c746d7e5..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3ReaderException.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package de.danoeh.antennapod.core.util.id3reader;
-
-public class ID3ReaderException extends Exception {
-
- public ID3ReaderException() {
- }
-
- public ID3ReaderException(String arg0) {
- super(arg0);
- }
-
- public ID3ReaderException(Throwable arg0) {
- super(arg0);
- }
-
- public ID3ReaderException(String arg0, Throwable arg1) {
- super(arg0, arg1);
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/FrameHeader.java b/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/FrameHeader.java
deleted file mode 100644
index 89eab1398..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/FrameHeader.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package de.danoeh.antennapod.core.util.id3reader.model;
-
-public class FrameHeader extends Header {
-
- protected char flags;
-
- public FrameHeader(String id, int size, char flags) {
- super(id, size);
- this.flags = flags;
- }
-
- @Override
- public String toString() {
- return String.format("FrameHeader [flags=%s, id=%s, size=%s]", Integer.toBinaryString(flags), id, Integer.toBinaryString(size));
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/Header.java b/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/Header.java
deleted file mode 100644
index 346e2893f..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/Header.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package de.danoeh.antennapod.core.util.id3reader.model;
-
-public abstract class Header {
-
- protected String id;
- protected int size;
-
- public Header(String id, int size) {
- super();
- this.id = id;
- this.size = size;
- }
-
- public String getId() {
- return id;
- }
-
- public int getSize() {
- return size;
- }
-
- @Override
- public String toString() {
- return "Header [id=" + id + ", size=" + size + "]";
- }
-
-
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/TagHeader.java b/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/TagHeader.java
deleted file mode 100644
index 0a6b8357f..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/TagHeader.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package de.danoeh.antennapod.core.util.id3reader.model;
-
-public class TagHeader extends Header {
-
- protected char version;
- protected byte flags;
-
- public TagHeader(String id, int size, char version, byte flags) {
- super(id, size);
- this.version = version;
- this.flags = flags;
- }
-
- @Override
- public String toString() {
- return "TagHeader [version=" + version + ", flags=" + flags + ", id="
- + id + ", size=" + size + "]";
- }
-
- public char getVersion() {
- return version;
- }
-
-
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java b/app/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java
deleted file mode 100644
index aafcea307..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package de.danoeh.antennapod.core.util.playback;
-
-import android.content.Context;
-import android.util.Log;
-import android.view.SurfaceHolder;
-import com.aocate.media.MediaPlayer;
-
-public class AudioPlayer extends MediaPlayer implements IPlayer {
- private static final String TAG = "AudioPlayer";
-
- public AudioPlayer(Context context) {
- super(context);
- }
-
- @Override
- public void setScreenOnWhilePlaying(boolean screenOn) {
- Log.e(TAG, "Setting screen on while playing not supported in Audio Player");
- throw new UnsupportedOperationException("Setting screen on while playing not supported in Audio Player");
-
- }
-
- @Override
- public void setDisplay(SurfaceHolder sh) {
- if (sh != null) {
- Log.e(TAG, "Setting display not supported in Audio Player");
- throw new UnsupportedOperationException("Setting display not supported in Audio Player");
- }
- }
-
- @Override
- public void setVideoScalingMode(int mode) {
- throw new UnsupportedOperationException("Setting scaling mode is not supported in Audio Player");
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java b/app/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java
deleted file mode 100644
index 49769f4f0..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java
+++ /dev/null
@@ -1,235 +0,0 @@
-package de.danoeh.antennapod.core.util.playback;
-
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.media.MediaMetadataRetriever;
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-import de.danoeh.antennapod.core.feed.Chapter;
-import de.danoeh.antennapod.core.feed.MediaType;
-import de.danoeh.antennapod.core.util.ChapterUtils;
-
-import java.util.List;
-import java.util.concurrent.Callable;
-
-/** Represents a media file that is stored on the local storage device. */
-public class ExternalMedia implements Playable {
-
- public static final int PLAYABLE_TYPE_EXTERNAL_MEDIA = 2;
- public static final String PREF_SOURCE_URL = "ExternalMedia.PrefSourceUrl";
- public static final String PREF_POSITION = "ExternalMedia.PrefPosition";
- public static final String PREF_MEDIA_TYPE = "ExternalMedia.PrefMediaType";
-
- private String source;
-
- private String episodeTitle;
- private String feedTitle;
- private MediaType mediaType = MediaType.AUDIO;
- private List<Chapter> chapters;
- private int duration;
- private int position;
-
- public ExternalMedia(String source, MediaType mediaType) {
- super();
- this.source = source;
- this.mediaType = mediaType;
- }
-
- public ExternalMedia(String source, MediaType mediaType, int position) {
- this(source, mediaType);
- this.position = position;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(source);
- dest.writeString(mediaType.toString());
- dest.writeInt(position);
- }
-
- @Override
- public void writeToPreferences(Editor prefEditor) {
- prefEditor.putString(PREF_SOURCE_URL, source);
- prefEditor.putString(PREF_MEDIA_TYPE, mediaType.toString());
- prefEditor.putInt(PREF_POSITION, position);
- }
-
- @Override
- public void loadMetadata() throws PlayableException {
- MediaMetadataRetriever mmr = new MediaMetadataRetriever();
- try {
- mmr.setDataSource(source);
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- throw new PlayableException(
- "IllegalArgumentException when setting up MediaMetadataReceiver");
- } catch (RuntimeException e) {
- // http://code.google.com/p/android/issues/detail?id=39770
- e.printStackTrace();
- throw new PlayableException(
- "RuntimeException when setting up MediaMetadataRetriever");
- }
- episodeTitle = mmr
- .extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
- feedTitle = mmr
- .extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
- try {
- duration = Integer.parseInt(mmr
- .extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION));
- } catch (NumberFormatException e) {
- e.printStackTrace();
- throw new PlayableException("NumberFormatException when reading duration of media file");
- }
- ChapterUtils.loadChaptersFromFileUrl(this);
- }
-
- @Override
- public void loadChapterMarks() {
-
- }
-
- @Override
- public String getEpisodeTitle() {
- return episodeTitle;
- }
-
- @Override
- public Callable<String> loadShownotes() {
- return new Callable<String>() {
- @Override
- public String call() throws Exception {
- return "";
- }
- };
- }
-
- @Override
- public List<Chapter> getChapters() {
- return chapters;
- }
-
- @Override
- public String getWebsiteLink() {
- return null;
- }
-
- @Override
- public String getPaymentLink() {
- return null;
- }
-
- @Override
- public String getFeedTitle() {
- return feedTitle;
- }
-
- @Override
- public Object getIdentifier() {
- return source;
- }
-
- @Override
- public int getDuration() {
- return duration;
- }
-
- @Override
- public int getPosition() {
- return position;
- }
-
- @Override
- public MediaType getMediaType() {
- return mediaType;
- }
-
- @Override
- public String getLocalMediaUrl() {
- return source;
- }
-
- @Override
- public String getStreamUrl() {
- return null;
- }
-
- @Override
- public boolean localFileAvailable() {
- return true;
- }
-
- @Override
- public boolean streamAvailable() {
- return false;
- }
-
- @Override
- public void saveCurrentPosition(SharedPreferences pref, int newPosition) {
- SharedPreferences.Editor editor = pref.edit();
- editor.putInt(PREF_POSITION, newPosition);
- position = newPosition;
- editor.commit();
- }
-
- @Override
- public void setPosition(int newPosition) {
- position = newPosition;
- }
-
- @Override
- public void setDuration(int newDuration) {
- duration = newDuration;
- }
-
- @Override
- public void onPlaybackStart() {
-
- }
-
- @Override
- public void onPlaybackCompleted() {
-
- }
-
- @Override
- public int getPlayableType() {
- return PLAYABLE_TYPE_EXTERNAL_MEDIA;
- }
-
- @Override
- public void setChapters(List<Chapter> chapters) {
- this.chapters = chapters;
- }
-
- public static final Parcelable.Creator<ExternalMedia> CREATOR = new Parcelable.Creator<ExternalMedia>() {
- public ExternalMedia createFromParcel(Parcel in) {
- String source = in.readString();
- MediaType type = MediaType.valueOf(in.readString());
- int position = 0;
- if (in.dataAvail() > 0) {
- position = in.readInt();
- }
- ExternalMedia extMedia = new ExternalMedia(source, type, position);
- return extMedia;
- }
-
- public ExternalMedia[] newArray(int size) {
- return new ExternalMedia[size];
- }
- };
-
- @Override
- public Uri getImageUri() {
- if (localFileAvailable()) {
- return new Uri.Builder().scheme(SCHEME_MEDIA).encodedPath(getLocalMediaUrl()).build();
- } else {
- return null;
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java b/app/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java
deleted file mode 100644
index 147c7848d..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package de.danoeh.antennapod.core.util.playback;
-
-import android.content.Context;
-import android.view.SurfaceHolder;
-
-import java.io.IOException;
-
-public interface IPlayer {
- boolean canSetPitch();
-
- boolean canSetSpeed();
-
- float getCurrentPitchStepsAdjustment();
-
- int getCurrentPosition();
-
- float getCurrentSpeedMultiplier();
-
- int getDuration();
-
- float getMaxSpeedMultiplier();
-
- float getMinSpeedMultiplier();
-
- boolean isLooping();
-
- boolean isPlaying();
-
- void pause();
-
- void prepare() throws IllegalStateException, IOException;
-
- void prepareAsync();
-
- void release();
-
- void reset();
-
- void seekTo(int msec);
-
- void setAudioStreamType(int streamtype);
-
- void setScreenOnWhilePlaying(boolean screenOn);
-
- void setDataSource(String path) throws IllegalStateException, IOException,
- IllegalArgumentException, SecurityException;
-
- void setDisplay(SurfaceHolder sh);
-
- void setEnableSpeedAdjustment(boolean enableSpeedAdjustment);
-
- void setLooping(boolean looping);
-
- void setPitchStepsAdjustment(float pitchSteps);
-
- void setPlaybackPitch(float f);
-
- void setPlaybackSpeed(float f);
-
- void setVolume(float left, float right);
-
- void start();
-
- void stop();
-
- public void setVideoScalingMode(int mode);
-
- public void setWakeMode(Context context, int mode);
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/playback/MediaPlayerError.java b/app/src/main/java/de/danoeh/antennapod/core/util/playback/MediaPlayerError.java
deleted file mode 100644
index a3a907e48..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/playback/MediaPlayerError.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package de.danoeh.antennapod.core.util.playback;
-
-import android.content.Context;
-import android.media.MediaPlayer;
-import de.danoeh.antennapod.R;
-
-/** Utility class for MediaPlayer errors. */
-public class MediaPlayerError {
-
- /** Get a human-readable string for a specific error code. */
- public static String getErrorString(Context context, int code) {
- int resId;
- switch(code) {
- case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
- resId = R.string.playback_error_server_died;
- break;
- default:
- resId = R.string.playback_error_unknown;
- break;
- }
- return context.getString(resId);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java b/app/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java
deleted file mode 100644
index 7ebd580f7..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java
+++ /dev/null
@@ -1,207 +0,0 @@
-package de.danoeh.antennapod.core.util.playback;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.Parcelable;
-import android.util.Log;
-
-import java.util.List;
-
-import de.danoeh.antennapod.core.asynctask.PicassoImageResource;
-import de.danoeh.antennapod.core.feed.Chapter;
-import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.feed.MediaType;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.util.ShownotesProvider;
-
-/**
- * Interface for objects that can be played by the PlaybackService.
- */
-public interface Playable extends Parcelable,
- ShownotesProvider, PicassoImageResource {
-
- /**
- * Save information about the playable in a preference so that it can be
- * restored later via PlayableUtils.createInstanceFromPreferences.
- * Implementations must NOT call commit() after they have written the values
- * to the preferences file.
- */
- public void writeToPreferences(SharedPreferences.Editor prefEditor);
-
- /**
- * This method is called from a separate thread by the PlaybackService.
- * Playable objects should load their metadata in this method. This method
- * should execute as quickly as possible and NOT load chapter marks if no
- * local file is available.
- */
- public void loadMetadata() throws PlayableException;
-
- /**
- * This method is called from a separate thread by the PlaybackService.
- * Playable objects should load their chapter marks in this method if no
- * local file was available when loadMetadata() was called.
- */
- public void loadChapterMarks();
-
- /**
- * Returns the title of the episode that this playable represents
- */
- public String getEpisodeTitle();
-
- /**
- * Returns a list of chapter marks or null if this Playable has no chapters.
- */
- public List<Chapter> getChapters();
-
- /**
- * Returns a link to a website that is meant to be shown in a browser
- */
- public String getWebsiteLink();
-
- public String getPaymentLink();
-
- /**
- * Returns the title of the feed this Playable belongs to.
- */
- public String getFeedTitle();
-
- /**
- * Returns a unique identifier, for example a file url or an ID from a
- * database.
- */
- public Object getIdentifier();
-
- /**
- * Return duration of object or 0 if duration is unknown.
- */
- public int getDuration();
-
- /**
- * Return position of object or 0 if position is unknown.
- */
- public int getPosition();
-
- /**
- * Returns the type of media. This method should return the correct value
- * BEFORE loadMetadata() is called.
- */
- public MediaType getMediaType();
-
- /**
- * Returns an url to a local file that can be played or null if this file
- * does not exist.
- */
- public String getLocalMediaUrl();
-
- /**
- * Returns an url to a file that can be streamed by the player or null if
- * this url is not known.
- */
- public String getStreamUrl();
-
- /**
- * Returns true if a local file that can be played is available. getFileUrl
- * MUST return a non-null string if this method returns true.
- */
- public boolean localFileAvailable();
-
- /**
- * Returns true if a streamable file is available. getStreamUrl MUST return
- * a non-null string if this method returns true.
- */
- public boolean streamAvailable();
-
- /**
- * Saves the current position of this object. Implementations can use the
- * provided SharedPreference to save this information and retrieve it later
- * via PlayableUtils.createInstanceFromPreferences.
- */
- public void saveCurrentPosition(SharedPreferences pref, int newPosition);
-
- public void setPosition(int newPosition);
-
- public void setDuration(int newDuration);
-
- /**
- * Is called by the PlaybackService when playback starts.
- */
- public void onPlaybackStart();
-
- /**
- * Is called by the PlaybackService when playback is completed.
- */
- public void onPlaybackCompleted();
-
- /**
- * Returns an integer that must be unique among all Playable classes. The
- * return value is later used by PlayableUtils to determine the type of the
- * Playable object that is restored.
- */
- public int getPlayableType();
-
- public void setChapters(List<Chapter> chapters);
-
- /**
- * Provides utility methods for Playable objects.
- */
- public static class PlayableUtils {
- private static final String TAG = "PlayableUtils";
-
- /**
- * Restores a playable object from a sharedPreferences file. This method might load data from the database,
- * depending on the type of playable that was restored.
- *
- * @param type An integer that represents the type of the Playable object
- * that is restored.
- * @param pref The SharedPreferences file from which the Playable object
- * is restored
- * @return The restored Playable object
- */
- public static Playable createInstanceFromPreferences(Context context, int type,
- SharedPreferences pref) {
- // ADD new Playable types here:
- switch (type) {
- case FeedMedia.PLAYABLE_TYPE_FEEDMEDIA:
- long mediaId = pref.getLong(FeedMedia.PREF_MEDIA_ID, -1);
- if (mediaId != -1) {
- return DBReader.getFeedMedia(context, mediaId);
- }
- break;
- case ExternalMedia.PLAYABLE_TYPE_EXTERNAL_MEDIA:
- String source = pref.getString(ExternalMedia.PREF_SOURCE_URL,
- null);
- String mediaType = pref.getString(
- ExternalMedia.PREF_MEDIA_TYPE, null);
- if (source != null && mediaType != null) {
- int position = pref.getInt(ExternalMedia.PREF_POSITION, 0);
- return new ExternalMedia(source,
- MediaType.valueOf(mediaType), position);
- }
- break;
- }
- Log.e(TAG, "Could not restore Playable object from preferences");
- return null;
- }
- }
-
- public static class PlayableException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public PlayableException() {
- super();
- }
-
- public PlayableException(String detailMessage, Throwable throwable) {
- super(detailMessage, throwable);
- }
-
- public PlayableException(String detailMessage) {
- super(detailMessage);
- }
-
- public PlayableException(Throwable throwable) {
- super(throwable);
- }
-
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/app/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
deleted file mode 100644
index 35bd27057..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
+++ /dev/null
@@ -1,784 +0,0 @@
-package de.danoeh.antennapod.core.util.playback;
-
-import android.app.Activity;
-import android.content.*;
-import android.content.res.TypedArray;
-import android.media.MediaPlayer;
-import android.os.AsyncTask;
-import android.os.IBinder;
-import android.preference.PreferenceManager;
-import android.util.Log;
-import android.util.Pair;
-import android.view.SurfaceHolder;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.ImageButton;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.Validate;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.feed.Chapter;
-import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.feed.MediaType;
-import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.core.service.playback.PlaybackServiceMediaPlayer;
-import de.danoeh.antennapod.core.service.playback.PlayerStatus;
-import de.danoeh.antennapod.core.storage.DBTasks;
-import de.danoeh.antennapod.core.util.Converter;
-import de.danoeh.antennapod.core.util.playback.Playable.PlayableUtils;
-
-import java.util.concurrent.*;
-
-/**
- * Communicates with the playback service. GUI classes should use this class to
- * control playback instead of communicating with the PlaybackService directly.
- */
-public abstract class PlaybackController {
- private static final String TAG = "PlaybackController";
-
- public static final int INVALID_TIME = -1;
-
- private final Activity activity;
-
- private PlaybackService playbackService;
- private Playable media;
- private PlayerStatus status;
-
- private ScheduledThreadPoolExecutor schedExecutor;
- private static final int SCHED_EX_POOLSIZE = 1;
-
- protected MediaPositionObserver positionObserver;
- protected ScheduledFuture positionObserverFuture;
-
- private boolean mediaInfoLoaded = false;
- private boolean released = false;
-
- /**
- * True if controller should reinit playback service if 'pause' button is
- * pressed.
- */
- private boolean reinitOnPause;
-
- public PlaybackController(Activity activity, boolean reinitOnPause) {
- Validate.notNull(activity);
-
- this.activity = activity;
- this.reinitOnPause = reinitOnPause;
- schedExecutor = new ScheduledThreadPoolExecutor(SCHED_EX_POOLSIZE,
- new ThreadFactory() {
-
- @Override
- public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setPriority(Thread.MIN_PRIORITY);
- return t;
- }
- }, new RejectedExecutionHandler() {
-
- @Override
- public void rejectedExecution(Runnable r,
- ThreadPoolExecutor executor) {
- Log.w(TAG,
- "Rejected execution of runnable in schedExecutor");
- }
- }
- );
- }
-
- /**
- * Creates a new connection to the playbackService. Should be called in the
- * activity's onResume() method.
- */
- public void init() {
- activity.registerReceiver(statusUpdate, new IntentFilter(
- PlaybackService.ACTION_PLAYER_STATUS_CHANGED));
-
- activity.registerReceiver(notificationReceiver, new IntentFilter(
- PlaybackService.ACTION_PLAYER_NOTIFICATION));
-
- activity.registerReceiver(shutdownReceiver, new IntentFilter(
- PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
-
- if (!released) {
- bindToService();
- } else {
- throw new IllegalStateException(
- "Can't call init() after release() has been called");
- }
- }
-
- /**
- * Should be called if the PlaybackController is no longer needed, for
- * example in the activity's onStop() method.
- */
- public void release() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Releasing PlaybackController");
-
- try {
- activity.unregisterReceiver(statusUpdate);
- } catch (IllegalArgumentException e) {
- // ignore
- }
-
- try {
- activity.unregisterReceiver(notificationReceiver);
- } catch (IllegalArgumentException e) {
- // ignore
- }
-
- try {
- activity.unbindService(mConnection);
- } catch (IllegalArgumentException e) {
- // ignore
- }
-
- try {
- activity.unregisterReceiver(shutdownReceiver);
- } catch (IllegalArgumentException e) {
- // ignore
- }
- cancelPositionObserver();
- schedExecutor.shutdownNow();
- media = null;
- released = true;
-
- }
-
- /**
- * Should be called in the activity's onPause() method.
- */
- public void pause() {
- mediaInfoLoaded = false;
- }
-
- /**
- * Tries to establish a connection to the PlaybackService. If it isn't
- * running, the PlaybackService will be started with the last played media
- * as the arguments of the launch intent.
- */
- private void bindToService() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Trying to connect to service");
- AsyncTask<Void, Void, Intent> intentLoader = new AsyncTask<Void, Void, Intent>() {
- @Override
- protected Intent doInBackground(Void... voids) {
- return getPlayLastPlayedMediaIntent();
- }
-
- @Override
- protected void onPostExecute(Intent serviceIntent) {
- boolean bound = false;
- if (!PlaybackService.started) {
- if (serviceIntent != null) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Calling start service");
- activity.startService(serviceIntent);
- bound = activity.bindService(serviceIntent, mConnection, 0);
- } else {
- status = PlayerStatus.STOPPED;
- setupGUI();
- handleStatus();
- }
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "PlaybackService is running, trying to connect without start command.");
- bound = activity.bindService(new Intent(activity,
- PlaybackService.class), mConnection, 0);
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Result for service binding: " + bound);
- }
- };
- intentLoader.execute();
- }
-
- /**
- * Returns an intent that starts the PlaybackService and plays the last
- * played media or null if no last played media could be found.
- */
- private Intent getPlayLastPlayedMediaIntent() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Trying to restore last played media");
- SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(activity.getApplicationContext());
- long currentlyPlayingMedia = PlaybackPreferences
- .getCurrentlyPlayingMedia();
- if (currentlyPlayingMedia != PlaybackPreferences.NO_MEDIA_PLAYING) {
- Playable media = PlayableUtils.createInstanceFromPreferences(activity,
- (int) currentlyPlayingMedia, prefs);
- if (media != null) {
- Intent serviceIntent = new Intent(activity,
- PlaybackService.class);
- serviceIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
- serviceIntent.putExtra(
- PlaybackService.EXTRA_START_WHEN_PREPARED, false);
- serviceIntent.putExtra(
- PlaybackService.EXTRA_PREPARE_IMMEDIATELY, false);
- boolean fileExists = media.localFileAvailable();
- boolean lastIsStream = PlaybackPreferences
- .getCurrentEpisodeIsStream();
- if (!fileExists && !lastIsStream && media instanceof FeedMedia) {
- DBTasks.notifyMissingFeedMediaFile(
- activity, (FeedMedia) media);
- }
- serviceIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM,
- lastIsStream || !fileExists);
- return serviceIntent;
- }
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, "No last played media found");
- return null;
- }
-
- public abstract void setupGUI();
-
- private void setupPositionObserver() {
- if ((positionObserverFuture != null && positionObserverFuture
- .isCancelled())
- || (positionObserverFuture != null && positionObserverFuture
- .isDone()) || positionObserverFuture == null) {
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Setting up position observer");
- positionObserver = new MediaPositionObserver();
- positionObserverFuture = schedExecutor.scheduleWithFixedDelay(
- positionObserver, MediaPositionObserver.WAITING_INTERVALL,
- MediaPositionObserver.WAITING_INTERVALL,
- TimeUnit.MILLISECONDS);
- }
- }
-
- private void cancelPositionObserver() {
- if (positionObserverFuture != null) {
- boolean result = positionObserverFuture.cancel(true);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "PositionObserver cancelled. Result: " + result);
- }
- }
-
- public abstract void onPositionObserverUpdate();
-
- private ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- playbackService = ((PlaybackService.LocalBinder) service)
- .getService();
- if (!released) {
- queryService();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Connection to Service established");
- } else {
- Log.i(TAG, "Connection to playback service has been established, but controller has already been released");
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- playbackService = null;
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Disconnected from Service");
-
- }
- };
-
- protected BroadcastReceiver statusUpdate = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received statusUpdate Intent.");
- if (isConnectedToPlaybackService()) {
- PlaybackServiceMediaPlayer.PSMPInfo info = playbackService.getPSMPInfo();
- status = info.playerStatus;
- media = info.playable;
- handleStatus();
- } else {
- Log.w(TAG,
- "Couldn't receive status update: playbackService was null");
- bindToService();
- }
- }
- };
-
- protected BroadcastReceiver notificationReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (isConnectedToPlaybackService()) {
- int type = intent.getIntExtra(
- PlaybackService.EXTRA_NOTIFICATION_TYPE, -1);
- int code = intent.getIntExtra(
- PlaybackService.EXTRA_NOTIFICATION_CODE, -1);
- if (code != -1 && type != -1) {
- switch (type) {
- case PlaybackService.NOTIFICATION_TYPE_ERROR:
- handleError(code);
- break;
- case PlaybackService.NOTIFICATION_TYPE_BUFFER_UPDATE:
- float progress = ((float) code) / 100;
- onBufferUpdate(progress);
- break;
- case PlaybackService.NOTIFICATION_TYPE_RELOAD:
- cancelPositionObserver();
- mediaInfoLoaded = false;
- queryService();
- onReloadNotification(intent.getIntExtra(
- PlaybackService.EXTRA_NOTIFICATION_CODE, -1));
- break;
- case PlaybackService.NOTIFICATION_TYPE_SLEEPTIMER_UPDATE:
- onSleepTimerUpdate();
- break;
- case PlaybackService.NOTIFICATION_TYPE_BUFFER_START:
- onBufferStart();
- break;
- case PlaybackService.NOTIFICATION_TYPE_BUFFER_END:
- onBufferEnd();
- break;
- case PlaybackService.NOTIFICATION_TYPE_PLAYBACK_END:
- onPlaybackEnd();
- break;
- case PlaybackService.NOTIFICATION_TYPE_PLAYBACK_SPEED_CHANGE:
- onPlaybackSpeedChange();
- break;
- }
-
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Bad arguments. Won't handle intent");
- }
- } else {
- bindToService();
- }
- }
-
- };
-
- private BroadcastReceiver shutdownReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (isConnectedToPlaybackService()) {
- if (StringUtils.equals(intent.getAction(),
- PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)) {
- release();
- onShutdownNotification();
- }
- }
- }
- };
-
- public abstract void onPlaybackSpeedChange();
-
- public abstract void onShutdownNotification();
-
- /**
- * Called when the currently displayed information should be refreshed.
- */
- public abstract void onReloadNotification(int code);
-
- public abstract void onBufferStart();
-
- public abstract void onBufferEnd();
-
- public abstract void onBufferUpdate(float progress);
-
- public abstract void onSleepTimerUpdate();
-
- public abstract void handleError(int code);
-
- public abstract void onPlaybackEnd();
-
- /**
- * Is called whenever the PlaybackService changes it's status. This method
- * should be used to update the GUI or start/cancel background threads.
- */
- private void handleStatus() {
- final int playResource;
- final int pauseResource;
- final CharSequence playText = activity.getString(R.string.play_label);
- final CharSequence pauseText = activity.getString(R.string.pause_label);
-
- if (PlaybackService.getCurrentMediaType() == MediaType.AUDIO) {
- TypedArray res = activity.obtainStyledAttributes(new int[]{
- R.attr.av_play, R.attr.av_pause});
- playResource = res.getResourceId(0, R.drawable.av_play);
- pauseResource = res.getResourceId(1, R.drawable.av_pause);
- res.recycle();
- } else {
- playResource = R.drawable.ic_action_play_over_video;
- pauseResource = R.drawable.ic_action_pause_over_video;
- }
-
- switch (status) {
-
- case ERROR:
- postStatusMsg(R.string.player_error_msg);
- handleError(MediaPlayer.MEDIA_ERROR_UNKNOWN);
- break;
- case PAUSED:
- clearStatusMsg();
- checkMediaInfoLoaded();
- cancelPositionObserver();
- updatePlayButtonAppearance(playResource, playText);
- if (PlaybackService.getCurrentMediaType() == MediaType.VIDEO) {
- setScreenOn(false);
- }
- break;
- case PLAYING:
- clearStatusMsg();
- checkMediaInfoLoaded();
- if (PlaybackService.getCurrentMediaType() == MediaType.VIDEO) {
- onAwaitingVideoSurface();
- setScreenOn(true);
- }
- setupPositionObserver();
- updatePlayButtonAppearance(pauseResource, pauseText);
- break;
- case PREPARING:
- postStatusMsg(R.string.player_preparing_msg);
- checkMediaInfoLoaded();
- if (playbackService != null) {
- if (playbackService.isStartWhenPrepared()) {
- updatePlayButtonAppearance(pauseResource, pauseText);
- } else {
- updatePlayButtonAppearance(playResource, playText);
- }
- }
- break;
- case STOPPED:
- postStatusMsg(R.string.player_stopped_msg);
- break;
- case PREPARED:
- checkMediaInfoLoaded();
- postStatusMsg(R.string.player_ready_msg);
- updatePlayButtonAppearance(playResource, playText);
- break;
- case SEEKING:
- postStatusMsg(R.string.player_seeking_msg);
- break;
- case INITIALIZED:
- checkMediaInfoLoaded();
- clearStatusMsg();
- updatePlayButtonAppearance(playResource, playText);
- break;
- }
- }
-
- private void checkMediaInfoLoaded() {
- mediaInfoLoaded = (mediaInfoLoaded || loadMediaInfo());
- }
-
- private void updatePlayButtonAppearance(int resource, CharSequence contentDescription) {
- ImageButton butPlay = getPlayButton();
- butPlay.setImageResource(resource);
- butPlay.setContentDescription(contentDescription);
- }
-
- public abstract ImageButton getPlayButton();
-
- public abstract void postStatusMsg(int msg);
-
- public abstract void clearStatusMsg();
-
- public abstract boolean loadMediaInfo();
-
- public abstract void onAwaitingVideoSurface();
-
- /**
- * Called when connection to playback service has been established or
- * information has to be refreshed
- */
- void queryService() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Querying service info");
- if (playbackService != null) {
- status = playbackService.getStatus();
- media = playbackService.getPlayable();
- /*
- if (media == null) {
- Log.w(TAG,
- "PlaybackService has no media object. Trying to restore last played media.");
- Intent serviceIntent = getPlayLastPlayedMediaIntent();
- if (serviceIntent != null) {
- activity.startService(serviceIntent);
- }
- }
- */
- onServiceQueried();
-
- setupGUI();
- handleStatus();
- // make sure that new media is loaded if it's available
- mediaInfoLoaded = false;
-
- } else {
- Log.e(TAG,
- "queryService() was called without an existing connection to playbackservice");
- }
- }
-
- public abstract void onServiceQueried();
-
- /**
- * Should be used by classes which implement the OnSeekBarChanged interface.
- */
- public float onSeekBarProgressChanged(SeekBar seekBar, int progress,
- boolean fromUser, TextView txtvPosition) {
- if (fromUser && playbackService != null && media != null) {
- float prog = progress / ((float) seekBar.getMax());
- int duration = media.getDuration();
- txtvPosition.setText(Converter
- .getDurationStringLong((int) (prog * duration)));
- return prog;
- }
- return 0;
-
- }
-
- /**
- * Should be used by classes which implement the OnSeekBarChanged interface.
- */
- public void onSeekBarStartTrackingTouch(SeekBar seekBar) {
- // interrupt position Observer, restart later
- cancelPositionObserver();
- }
-
- /**
- * Should be used by classes which implement the OnSeekBarChanged interface.
- */
- public void onSeekBarStopTrackingTouch(SeekBar seekBar, float prog) {
- if (playbackService != null) {
- playbackService.seekTo((int) (prog * media.getDuration()));
- setupPositionObserver();
- }
- }
-
- /**
- * Should be implemented by classes that show a video. The default implementation
- * does nothing
- *
- * @param enable True if the screen should be kept on, false otherwise
- */
- protected void setScreenOn(boolean enable) {
-
- }
-
- public OnClickListener newOnPlayButtonClickListener() {
- return new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (playbackService != null) {
- switch (status) {
- case PLAYING:
- playbackService.pause(true, reinitOnPause);
- break;
- case PAUSED:
- case PREPARED:
- playbackService.resume();
- break;
- case PREPARING:
- playbackService.setStartWhenPrepared(!playbackService
- .isStartWhenPrepared());
- if (reinitOnPause
- && playbackService.isStartWhenPrepared() == false) {
- playbackService.reinit();
- }
- break;
- case INITIALIZED:
- playbackService.setStartWhenPrepared(true);
- playbackService.prepare();
- break;
- }
- } else {
- Log.w(TAG,
- "Play/Pause button was pressed, but playbackservice was null!");
- }
- }
-
- };
- }
-
- public OnClickListener newOnRevButtonClickListener() {
- return new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (status == PlayerStatus.PLAYING) {
- playbackService.seekDelta(-UserPreferences.getSeekDeltaMs());
- }
- }
- };
- }
-
- public OnClickListener newOnFFButtonClickListener() {
- return new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (status == PlayerStatus.PLAYING) {
- playbackService.seekDelta(UserPreferences.getSeekDeltaMs());
- }
- }
- };
- }
-
- public boolean serviceAvailable() {
- return playbackService != null;
- }
-
- public int getPosition() {
- if (playbackService != null) {
- return playbackService.getCurrentPosition();
- } else {
- return PlaybackService.INVALID_TIME;
- }
- }
-
- public int getDuration() {
- if (playbackService != null) {
- return playbackService.getDuration();
- } else {
- return PlaybackService.INVALID_TIME;
- }
- }
-
- public Playable getMedia() {
- return media;
- }
-
- public boolean sleepTimerActive() {
- return playbackService != null && playbackService.sleepTimerActive();
- }
-
- public boolean sleepTimerNotActive() {
- return playbackService != null && !playbackService.sleepTimerActive();
- }
-
- public void disableSleepTimer() {
- if (playbackService != null) {
- playbackService.disableSleepTimer();
- }
- }
-
- public long getSleepTimerTimeLeft() {
- if (playbackService != null) {
- return playbackService.getSleepTimerTimeLeft();
- } else {
- return INVALID_TIME;
- }
- }
-
- public void setSleepTimer(long time) {
- if (playbackService != null) {
- playbackService.setSleepTimer(time);
- }
- }
-
- public void seekToChapter(Chapter chapter) {
- if (playbackService != null) {
- playbackService.seekToChapter(chapter);
- }
- }
-
- public void seekTo(int time) {
- if (playbackService != null) {
- playbackService.seekTo(time);
- }
- }
-
- public void setVideoSurface(SurfaceHolder holder) {
- if (playbackService != null) {
- playbackService.setVideoSurface(holder);
- }
- }
-
- public PlayerStatus getStatus() {
- return status;
- }
-
- public boolean canSetPlaybackSpeed() {
- return playbackService != null && playbackService.canSetSpeed();
- }
-
- public void setPlaybackSpeed(float speed) {
- if (playbackService != null) {
- playbackService.setSpeed(speed);
- }
- }
-
- public float getCurrentPlaybackSpeedMultiplier() {
- if (canSetPlaybackSpeed()) {
- return playbackService.getCurrentPlaybackSpeed();
- } else {
- return -1;
- }
- }
-
- public boolean isPlayingVideo() {
- if (playbackService != null) {
- return PlaybackService.getCurrentMediaType() == MediaType.VIDEO;
- }
- return false;
- }
-
- public Pair<Integer, Integer> getVideoSize() {
- if (playbackService != null) {
- return playbackService.getVideoSize();
- } else {
- return null;
- }
- }
-
-
- /**
- * Returns true if PlaybackController can communicate with the playback
- * service.
- */
- public boolean isConnectedToPlaybackService() {
- return playbackService != null;
- }
-
- public void notifyVideoSurfaceAbandoned() {
- if (playbackService != null) {
- playbackService.notifyVideoSurfaceAbandoned();
- }
- }
-
- /**
- * Move service into INITIALIZED state if it's paused to save bandwidth
- */
- public void reinitServiceIfPaused() {
- if (playbackService != null
- && playbackService.isStreaming()
- && (playbackService.getStatus() == PlayerStatus.PAUSED || (playbackService
- .getStatus() == PlayerStatus.PREPARING && playbackService
- .isStartWhenPrepared() == false))) {
- playbackService.reinit();
- }
- }
-
- /**
- * Refreshes the current position of the media file that is playing.
- */
- public class MediaPositionObserver implements Runnable {
-
- public static final int WAITING_INTERVALL = 1000;
-
- @Override
- public void run() {
- if (playbackService != null && playbackService.getStatus() == PlayerStatus.PLAYING) {
- activity.runOnUiThread(new Runnable() {
-
- @Override
- public void run() {
- onPositionObserverUpdate();
- }
- });
- }
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java b/app/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
deleted file mode 100644
index 5177bbca3..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
+++ /dev/null
@@ -1,161 +0,0 @@
-package de.danoeh.antennapod.core.util.playback;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.util.Log;
-import android.util.TypedValue;
-
-import org.apache.commons.lang3.Validate;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.util.Converter;
-import de.danoeh.antennapod.core.util.ShownotesProvider;
-
-/**
- * Connects chapter information and shownotes of a shownotesProvider, for example by making it possible to use the
- * shownotes to navigate to another position in the podcast or by highlighting certain parts of the shownotesProvider's
- * shownotes.
- * <p/>
- * A timeline object needs a shownotesProvider from which the chapter information is retrieved and shownotes are generated.
- */
-public class Timeline {
- private static final String TAG = "Timeline";
-
- private static final String WEBVIEW_STYLE = "@font-face { font-family: 'Roboto-Light'; src: url('file:///android_asset/Roboto-Light.ttf'); } * { color: %s; font-family: roboto-Light; font-size: 11pt; } a { font-style: normal; text-decoration: none; font-weight: normal; color: #00A8DF; } a.timecode { color: #669900; } img { display: block; margin: 10 auto; max-width: %s; height: auto; } body { margin: %dpx %dpx %dpx %dpx; }";
-
-
- private ShownotesProvider shownotesProvider;
-
-
- private final String colorString;
- private final int pageMargin;
-
- public Timeline(Context context, ShownotesProvider shownotesProvider) {
- if (shownotesProvider == null) throw new IllegalArgumentException("shownotesProvider = null");
- this.shownotesProvider = shownotesProvider;
-
- TypedArray res = context
- .getTheme()
- .obtainStyledAttributes(
- new int[]{android.R.attr.textColorPrimary});
- int colorResource = res.getColor(0, 0);
- colorString = String.format("#%06X",
- 0xFFFFFF & colorResource);
- res.recycle();
-
- pageMargin = (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, 8, context.getResources()
- .getDisplayMetrics()
- );
- }
-
- private static final Pattern TIMECODE_LINK_REGEX = Pattern.compile("antennapod://timecode/((\\d+))");
- private static final String TIMECODE_LINK = "<a class=\"timecode\" href=\"antennapod://timecode/%d\">%s</a>";
- private static final Pattern TIMECODE_REGEX = Pattern.compile("\\b(?:(?:(([0-9][0-9])):))?(([0-9][0-9])):(([0-9][0-9]))\\b");
-
- /**
- * Applies an app-specific CSS stylesheet and adds timecode links (optional).
- * <p/>
- * This method does NOT change the original shownotes string of the shownotesProvider object and it should
- * also not be changed by the caller.
- *
- * @param addTimecodes True if this method should add timecode links
- * @return The processed HTML string.
- */
- public String processShownotes(final boolean addTimecodes) {
- final Playable playable = (shownotesProvider instanceof Playable) ? (Playable) shownotesProvider : null;
-
- // load shownotes
-
- String shownotes;
- try {
- shownotes = shownotesProvider.loadShownotes().call();
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- if (shownotes == null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "shownotesProvider contained no shownotes. Returning empty string");
- return "";
- }
-
- Document document = Jsoup.parse(shownotes);
-
- // apply style
- String styleStr = String.format(WEBVIEW_STYLE, colorString, "100%", pageMargin,
- pageMargin, pageMargin, pageMargin);
- document.head().appendElement("style").attr("type", "text/css").text(styleStr);
-
- // apply timecode links
- if (addTimecodes) {
- Elements elementsWithTimeCodes = document.body().getElementsMatchingOwnText(TIMECODE_REGEX);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Recognized " + elementsWithTimeCodes.size() + " timecodes");
- for (Element element : elementsWithTimeCodes) {
- Matcher matcherLong = TIMECODE_REGEX.matcher(element.text());
- StringBuffer buffer = new StringBuffer();
- while (matcherLong.find()) {
- String h = matcherLong.group(1);
- String group = matcherLong.group(0);
- int time = (h != null) ? Converter.durationStringLongToMs(group) :
- Converter.durationStringShortToMs(group);
-
- String rep;
- if (playable == null || playable.getDuration() > time) {
- rep = String.format(TIMECODE_LINK, time, group);
- } else {
- rep = group;
- }
- matcherLong.appendReplacement(buffer, rep);
- }
- matcherLong.appendTail(buffer);
-
- element.html(buffer.toString());
- }
- }
-
- Log.i(TAG, "Out: " + document.toString());
- return document.toString();
- }
-
-
- /**
- * Returns true if the given link is a timecode link.
- */
- public static boolean isTimecodeLink(String link) {
- return link != null && link.matches(TIMECODE_LINK_REGEX.pattern());
- }
-
- /**
- * Returns the time in milliseconds that is attached to this link or -1
- * if the link is no valid timecode link.
- */
- public static int getTimecodeLinkTime(String link) {
- if (isTimecodeLink(link)) {
- Matcher m = TIMECODE_LINK_REGEX.matcher(link);
-
- try {
- if (m.find()) {
- return Integer.valueOf(m.group(1));
- }
- } catch (NumberFormatException e) {
- e.printStackTrace();
- }
- }
- return -1;
- }
-
-
- public void setShownotesProvider(ShownotesProvider shownotesProvider) {
- Validate.notNull(shownotesProvider);
- this.shownotesProvider = shownotesProvider;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java b/app/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java
deleted file mode 100644
index dc5270d8f..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package de.danoeh.antennapod.core.util.playback;
-
-import android.media.MediaPlayer;
-import android.util.Log;
-
-public class VideoPlayer extends MediaPlayer implements IPlayer {
- private static final String TAG = "VideoPlayer";
-
- @Override
- public boolean canSetPitch() {
- return false;
- }
-
- @Override
- public boolean canSetSpeed() {
- return false;
- }
-
- @Override
- public float getCurrentPitchStepsAdjustment() {
- return 1;
- }
-
- @Override
- public float getCurrentSpeedMultiplier() {
- return 1;
- }
-
- @Override
- public float getMaxSpeedMultiplier() {
- return 1;
- }
-
- @Override
- public float getMinSpeedMultiplier() {
- return 1;
- }
-
- @Override
- public void setEnableSpeedAdjustment(boolean enableSpeedAdjustment) throws UnsupportedOperationException {
- Log.e(TAG, "Setting enable speed adjustment unsupported in video player");
- throw new UnsupportedOperationException("Setting enable speed adjustment unsupported in video player");
- }
-
- @Override
- public void setPitchStepsAdjustment(float pitchSteps) {
- Log.e(TAG, "Setting pitch steps adjustment unsupported in video player");
- throw new UnsupportedOperationException("Setting pitch steps adjustment unsupported in video player");
- }
-
- @Override
- public void setPlaybackPitch(float f) {
- Log.e(TAG, "Setting playback pitch unsupported in video player");
- throw new UnsupportedOperationException("Setting playback pitch unsupported in video player");
- }
-
- @Override
- public void setPlaybackSpeed(float f) {
- Log.e(TAG, "Setting playback speed unsupported in video player");
- throw new UnsupportedOperationException("Setting playback speed unsupported in video player");
- }
-
- @Override
- public void setVideoScalingMode(int mode) {
- super.setVideoScalingMode(mode);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java b/app/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java
deleted file mode 100644
index 9588265b8..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package de.danoeh.antennapod.core.util.syndication;
-
-import android.net.Uri;
-import org.apache.commons.lang3.StringUtils;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-/**
- * Finds RSS/Atom URLs in a HTML document using the auto-discovery techniques described here:
- * <p/>
- * http://www.rssboard.org/rss-autodiscovery
- * <p/>
- * http://blog.whatwg.org/feed-autodiscovery
- */
-public class FeedDiscoverer {
-
- private static final String MIME_RSS = "application/rss+xml";
- private static final String MIME_ATOM = "application/atom+xml";
-
- /**
- * Discovers links to RSS and Atom feeds in the given File which must be a HTML document.
- *
- * @return A map which contains the feed URLs as keys and titles as values (the feed URL is also used as a title if
- * a title cannot be found).
- */
- public Map<String, String> findLinks(File in, String baseUrl) throws IOException {
- return findLinks(Jsoup.parse(in, null), baseUrl);
- }
-
- /**
- * Discovers links to RSS and Atom feeds in the given File which must be a HTML document.
- *
- * @return A map which contains the feed URLs as keys and titles as values (the feed URL is also used as a title if
- * a title cannot be found).
- */
- public Map<String, String> findLinks(String in, String baseUrl) throws IOException {
- return findLinks(Jsoup.parse(in), baseUrl);
- }
-
- private Map<String, String> findLinks(Document document, String baseUrl) {
- Map<String, String> res = new LinkedHashMap<String, String>();
- Elements links = document.head().getElementsByTag("link");
- for (Element link : links) {
- String rel = link.attr("rel");
- String href = link.attr("href");
- if (!StringUtils.isEmpty(href) &&
- (rel.equals("alternate") || rel.equals("feed"))) {
- String type = link.attr("type");
- if (type.equals(MIME_RSS) || type.equals(MIME_ATOM)) {
- String title = link.attr("title");
- String processedUrl = processURL(baseUrl, href);
- if (processedUrl != null) {
- res.put(processedUrl,
- (StringUtils.isEmpty(title)) ? href : title);
- }
- }
- }
- }
- return res;
- }
-
- private String processURL(String baseUrl, String strUrl) {
- Uri uri = Uri.parse(strUrl);
- if (uri.isRelative()) {
- Uri res = Uri.parse(baseUrl).buildUpon().path(strUrl).build();
- return (res != null) ? res.toString() : null;
- } else {
- return strUrl;
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java b/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java
deleted file mode 100644
index 4799d3881..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package de.danoeh.antennapod.core.util.vorbiscommentreader;
-
-import org.apache.commons.io.IOUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-
-public class OggInputStream extends InputStream {
- private InputStream input;
-
- /** True if OggInputStream is currently inside an Ogg page. */
- private boolean isInPage;
- private long bytesLeft;
-
- public OggInputStream(InputStream input) {
- super();
- isInPage = false;
- this.input = input;
- }
-
- @Override
- public int read() throws IOException {
- if (!isInPage) {
- readOggPage();
- }
-
- if (isInPage && bytesLeft > 0) {
- int result = input.read();
- bytesLeft -= 1;
- if (bytesLeft == 0) {
- isInPage = false;
- }
- return result;
- }
- return -1;
- }
-
- private void readOggPage() throws IOException {
- // find OggS
- int[] buffer = new int[4];
- int c = 0;
- boolean isInOggS = false;
- while ((c = input.read()) != -1) {
- switch (c) {
- case 'O':
- isInOggS = true;
- buffer[0] = c;
- break;
- case 'g':
- if (buffer[1] != c) {
- buffer[1] = c;
- } else {
- buffer[2] = c;
- }
- break;
- case 'S':
- buffer[3] = c;
- break;
- default:
- if (isInOggS) {
- Arrays.fill(buffer, 0);
- isInOggS = false;
- }
- }
- if (buffer[0] == 'O' && buffer[1] == 'g' && buffer[2] == 'g'
- && buffer[3] == 'S') {
- break;
- }
- }
- // read segments
- IOUtils.skipFully(input, 22);
- bytesLeft = 0;
- int numSegments = input.read();
- for (int i = 0; i < numSegments; i++) {
- bytesLeft += input.read();
- }
- isInPage = true;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java b/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java
deleted file mode 100644
index a6934c60e..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package de.danoeh.antennapod.core.util.vorbiscommentreader;
-
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.feed.Chapter;
-import de.danoeh.antennapod.core.feed.VorbisCommentChapter;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class VorbisCommentChapterReader extends VorbisCommentReader {
- private static final String TAG = "VorbisCommentChapterReader";
-
- private static final String CHAPTER_KEY = "chapter\\d\\d\\d.*";
- private static final String CHAPTER_ATTRIBUTE_TITLE = "name";
- private static final String CHAPTER_ATTRIBUTE_LINK = "url";
-
- private List<Chapter> chapters;
-
- public VorbisCommentChapterReader() {
- }
-
- @Override
- public void onVorbisCommentFound() {
- System.out.println("Vorbis comment found");
- }
-
- @Override
- public void onVorbisCommentHeaderFound(VorbisCommentHeader header) {
- chapters = new ArrayList<Chapter>();
- System.out.println(header.toString());
- }
-
- @Override
- public boolean onContentVectorKey(String content) {
- return content.matches(CHAPTER_KEY);
- }
-
- @Override
- public void onContentVectorValue(String key, String value)
- throws VorbisCommentReaderException {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Key: " + key + ", value: " + value);
- String attribute = VorbisCommentChapter.getAttributeTypeFromKey(key);
- int id = VorbisCommentChapter.getIDFromKey(key);
- Chapter chapter = getChapterById(id);
- if (attribute == null) {
- if (getChapterById(id) == null) {
- // new chapter
- long start = VorbisCommentChapter.getStartTimeFromValue(value);
- chapter = new VorbisCommentChapter(id);
- chapter.setStart(start);
- chapters.add(chapter);
- } else {
- throw new VorbisCommentReaderException(
- "Found chapter with duplicate ID (" + key + ", "
- + value + ")");
- }
- } else if (attribute.equals(CHAPTER_ATTRIBUTE_TITLE)) {
- if (chapter != null) {
- chapter.setTitle(value);
- }
- } else if (attribute.equals(CHAPTER_ATTRIBUTE_LINK)) {
- if (chapter != null) {
- chapter.setLink(value);
- }
- }
- }
-
- @Override
- public void onNoVorbisCommentFound() {
- System.out.println("No vorbis comment found");
- }
-
- @Override
- public void onEndOfComment() {
- System.out.println("End of comment");
- for (Chapter c : chapters) {
- System.out.println(c.toString());
- }
- }
-
- @Override
- public void onError(VorbisCommentReaderException exception) {
- exception.printStackTrace();
- }
-
- private Chapter getChapterById(long id) {
- for (Chapter c : chapters) {
- if (((VorbisCommentChapter) c).getVorbisCommentId() == id) {
- return c;
- }
- }
- return null;
- }
-
- public List<Chapter> getChapters() {
- return chapters;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentHeader.java b/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentHeader.java
deleted file mode 100644
index 5f9dd0faf..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentHeader.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package de.danoeh.antennapod.core.util.vorbiscommentreader;
-public class VorbisCommentHeader {
- private String vendorString;
- private long userCommentLength;
-
- public VorbisCommentHeader(String vendorString, long userCommentLength) {
- super();
- this.vendorString = vendorString;
- this.userCommentLength = userCommentLength;
- }
-
- @Override
- public String toString() {
- return "VorbisCommentHeader [vendorString=" + vendorString
- + ", userCommentLength=" + userCommentLength + "]";
- }
-
- public String getVendorString() {
- return vendorString;
- }
-
- public long getUserCommentLength() {
- return userCommentLength;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java b/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java
deleted file mode 100644
index 9639b9c42..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java
+++ /dev/null
@@ -1,194 +0,0 @@
-package de.danoeh.antennapod.core.util.vorbiscommentreader;
-
-import org.apache.commons.io.EndianUtils;
-import org.apache.commons.io.IOUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.Arrays;
-
-
-public abstract class VorbisCommentReader {
- /** Length of first page in an ogg file in bytes. */
- private static final int FIRST_PAGE_LENGTH = 58;
- private static final int SECOND_PAGE_MAX_LENGTH = 64 * 1024 * 1024;
- private static final int PACKET_TYPE_IDENTIFICATION = 1;
- private static final int PACKET_TYPE_COMMENT = 3;
-
- /** Called when Reader finds identification header. */
- public abstract void onVorbisCommentFound();
-
- public abstract void onVorbisCommentHeaderFound(VorbisCommentHeader header);
-
- /**
- * Is called every time the Reader finds a content vector. The handler
- * should return true if it wants to handle the content vector.
- */
- public abstract boolean onContentVectorKey(String content);
-
- /**
- * Is called if onContentVectorKey returned true for the key.
- *
- * @throws VorbisCommentReaderException
- */
- public abstract void onContentVectorValue(String key, String value)
- throws VorbisCommentReaderException;
-
- public abstract void onNoVorbisCommentFound();
-
- public abstract void onEndOfComment();
-
- public abstract void onError(VorbisCommentReaderException exception);
-
- public void readInputStream(InputStream input)
- throws VorbisCommentReaderException {
- try {
- // look for identification header
- if (findIdentificationHeader(input)) {
-
- onVorbisCommentFound();
- input = new OggInputStream(input);
- if (findCommentHeader(input)) {
- VorbisCommentHeader commentHeader = readCommentHeader(input);
- if (commentHeader != null) {
- onVorbisCommentHeaderFound(commentHeader);
- for (int i = 0; i < commentHeader
- .getUserCommentLength(); i++) {
- try {
- long vectorLength = EndianUtils
- .readSwappedUnsignedInteger(input);
- String key = readContentVectorKey(input,
- vectorLength).toLowerCase();
- boolean readValue = onContentVectorKey(key);
- if (readValue) {
- String value = readUTF8String(
- input,
- (int) (vectorLength - key.length() - 1));
- onContentVectorValue(key, value);
- } else {
- IOUtils.skipFully(input,
- vectorLength - key.length() - 1);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- onEndOfComment();
- }
-
- } else {
- onError(new VorbisCommentReaderException(
- "No comment header found"));
- }
- } else {
- onNoVorbisCommentFound();
- }
- } catch (IOException e) {
- onError(new VorbisCommentReaderException(e));
- }
- }
-
- private String readUTF8String(InputStream input, long length)
- throws IOException {
- byte[] buffer = new byte[(int) length];
-
- IOUtils.readFully(input, buffer);
- Charset charset = Charset.forName("UTF-8");
- return charset.newDecoder().decode(ByteBuffer.wrap(buffer)).toString();
- }
-
- /**
- * Looks for an identification header in the first page of the file. If an
- * identification header is found, it will be skipped completely and the
- * method will return true, otherwise false.
- *
- * @throws IOException
- */
- private boolean findIdentificationHeader(InputStream input)
- throws IOException {
- byte[] buffer = new byte[FIRST_PAGE_LENGTH];
- IOUtils.readFully(input, buffer);
- int i;
- for (i = 6; i < buffer.length; i++) {
- if (buffer[i - 5] == 'v' && buffer[i - 4] == 'o'
- && buffer[i - 3] == 'r' && buffer[i - 2] == 'b'
- && buffer[i - 1] == 'i' && buffer[i] == 's'
- && buffer[i - 6] == PACKET_TYPE_IDENTIFICATION) {
- return true;
- }
- }
- return false;
- }
-
- private boolean findCommentHeader(InputStream input) throws IOException {
- char[] buffer = new char["vorbis".length() + 1];
- for (int bytesRead = 0; bytesRead < SECOND_PAGE_MAX_LENGTH; bytesRead++) {
- char c = (char) input.read();
- int dest = -1;
- switch (c) {
- case PACKET_TYPE_COMMENT:
- dest = 0;
- break;
- case 'v':
- dest = 1;
- break;
- case 'o':
- dest = 2;
- break;
- case 'r':
- dest = 3;
- break;
- case 'b':
- dest = 4;
- break;
- case 'i':
- dest = 5;
- break;
- case 's':
- dest = 6;
- break;
- }
- if (dest >= 0) {
- buffer[dest] = c;
- if (buffer[1] == 'v' && buffer[2] == 'o' && buffer[3] == 'r'
- && buffer[4] == 'b' && buffer[5] == 'i'
- && buffer[6] == 's' && buffer[0] == PACKET_TYPE_COMMENT) {
- return true;
- }
- } else {
- Arrays.fill(buffer, (char) 0);
- }
- }
- return false;
- }
-
- private VorbisCommentHeader readCommentHeader(InputStream input)
- throws IOException, VorbisCommentReaderException {
- try {
- long vendorLength = EndianUtils.readSwappedUnsignedInteger(input);
- String vendorName = readUTF8String(input, vendorLength);
- long userCommentLength = EndianUtils
- .readSwappedUnsignedInteger(input);
- return new VorbisCommentHeader(vendorName, userCommentLength);
- } catch (UnsupportedEncodingException e) {
- throw new VorbisCommentReaderException(e);
- }
- }
-
- private String readContentVectorKey(InputStream input, long vectorLength)
- throws IOException {
- StringBuffer buffer = new StringBuffer();
- for (int i = 0; i < vectorLength; i++) {
- char c = (char) input.read();
- if (c == '=') {
- return buffer.toString();
- } else {
- buffer.append(c);
- }
- }
- return null; // no key found
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReaderException.java b/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReaderException.java
deleted file mode 100644
index 89ab20db0..000000000
--- a/app/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReaderException.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package de.danoeh.antennapod.core.util.vorbiscommentreader;
-public class VorbisCommentReaderException extends Exception {
-
- public VorbisCommentReaderException() {
- super();
- // TODO Auto-generated constructor stub
- }
-
- public VorbisCommentReaderException(String arg0, Throwable arg1) {
- super(arg0, arg1);
- // TODO Auto-generated constructor stub
- }
-
- public VorbisCommentReaderException(String arg0) {
- super(arg0);
- // TODO Auto-generated constructor stub
- }
-
- public VorbisCommentReaderException(Throwable arg0) {
- super(arg0);
- // TODO Auto-generated constructor stub
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/FeedItemDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/FeedItemDialog.java
index e62daa08b..8cdddc121 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/FeedItemDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/FeedItemDialog.java
@@ -42,7 +42,7 @@ import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.QueueAccess;
import de.danoeh.antennapod.core.util.ShownotesProvider;
-import de.danoeh.antennapod.core.util.menuhandler.FeedItemMenuHandler;
+import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
/**
* Shows information about a specific FeedItem and provides actions like playing, downloading, etc.
diff --git a/app/src/main/java/de/danoeh/antennapod/core/dialog/TimeDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/TimeDialog.java
index a95e8c6c5..6561d501e 100644
--- a/app/src/main/java/de/danoeh/antennapod/core/dialog/TimeDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/TimeDialog.java
@@ -1,4 +1,4 @@
-package de.danoeh.antennapod.core.dialog;
+package de.danoeh.antennapod.dialog;
import android.app.Dialog;
import android.content.Context;
@@ -10,7 +10,7 @@ import android.view.View;
import android.view.Window;
import android.view.inputmethod.InputMethodManager;
import android.widget.*;
-import de.danoeh.antennapod.BuildConfig;
+import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.R;
import java.util.concurrent.TimeUnit;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
index b16e4f930..9eaeb56dd 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
@@ -48,9 +48,9 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.QueueAccess;
-import de.danoeh.antennapod.core.util.menuhandler.FeedMenuHandler;
-import de.danoeh.antennapod.core.util.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.core.util.menuhandler.NavDrawerActivity;
+import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
/**
* Displays a list of FeedItems.
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
index 4f37f4613..d126f2980 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
@@ -33,8 +33,8 @@ import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.QueueAccess;
-import de.danoeh.antennapod.core.util.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.core.util.menuhandler.NavDrawerActivity;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
index 61e4ae1bb..4a07ce2b7 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -25,8 +25,8 @@ import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.QueueAccess;
-import de.danoeh.antennapod.core.util.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.core.util.menuhandler.NavDrawerActivity;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
index c1191d933..3192a84de 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -37,8 +37,8 @@ import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.QueueAccess;
-import de.danoeh.antennapod.core.util.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.core.util.menuhandler.NavDrawerActivity;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
/**
* Shows all items in the queue
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
index 23cc1d0b8..c16ba426e 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -20,8 +20,8 @@ import de.danoeh.antennapod.core.feed.*;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.FeedSearcher;
import de.danoeh.antennapod.core.util.QueueAccess;
-import de.danoeh.antennapod.core.util.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.core.util.menuhandler.NavDrawerActivity;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
import java.util.List;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
index 14b3a9c40..15a0b55b1 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
@@ -18,8 +18,8 @@ import de.danoeh.antennapod.adapter.gpodnet.PodcastListAdapter;
import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetPodcast;
-import de.danoeh.antennapod.core.util.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.core.util.menuhandler.NavDrawerActivity;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
import java.util.List;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
index b099953a8..635842196 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
@@ -13,8 +13,8 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetPodcast;
-import de.danoeh.antennapod.core.util.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.core.util.menuhandler.NavDrawerActivity;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
/**
* Performs a search on the gpodder.net directory and displays the results.
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
index 819a28c2d..24e0e4caa 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
@@ -21,8 +21,8 @@ import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetTag;
-import de.danoeh.antennapod.core.util.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.core.util.menuhandler.NavDrawerActivity;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
public class TagListFragment extends ListFragment {
private static final String TAG = "TagListFragment";
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/menuhandler/FeedItemMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
index f85ac412d..8ccbdafc6 100644
--- a/app/src/main/java/de/danoeh/antennapod/core/util/menuhandler/FeedItemMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
@@ -1,10 +1,10 @@
-package de.danoeh.antennapod.core.util.menuhandler;
+package de.danoeh.antennapod.menuhandler;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
-import de.danoeh.antennapod.BuildConfig;
+import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/menuhandler/FeedMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
index 757cc5f56..62ae28820 100644
--- a/app/src/main/java/de/danoeh/antennapod/core/util/menuhandler/FeedMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
@@ -1,4 +1,4 @@
-package de.danoeh.antennapod.core.util.menuhandler;
+package de.danoeh.antennapod.menuhandler;
import android.content.Context;
import android.content.Intent;
@@ -7,7 +7,7 @@ import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-import de.danoeh.antennapod.BuildConfig;
+import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.service.download.DownloadService;
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/menuhandler/MenuItemUtils.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
index 4258c4d22..c4a96ac3f 100644
--- a/app/src/main/java/de/danoeh/antennapod/core/util/menuhandler/MenuItemUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
@@ -1,11 +1,11 @@
-package de.danoeh.antennapod.core.util.menuhandler;
+package de.danoeh.antennapod.menuhandler;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.SearchView;
import android.view.Menu;
import android.view.MenuItem;
-import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.R;
/**
* Utilities for menu items
diff --git a/app/src/main/java/de/danoeh/antennapod/core/util/menuhandler/NavDrawerActivity.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/NavDrawerActivity.java
index 61bf9960f..6ceaaada4 100644
--- a/app/src/main/java/de/danoeh/antennapod/core/util/menuhandler/NavDrawerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/NavDrawerActivity.java
@@ -1,4 +1,4 @@
-package de.danoeh.antennapod.core.util.menuhandler;
+package de.danoeh.antennapod.menuhandler;
/**
* Defines useful methods for activities that have a navigation drawer
diff --git a/app/src/main/java/de/danoeh/antennapod/core/receiver/PlayerWidget.java b/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java
index 3dcfecdbd..7ab386edf 100644
--- a/app/src/main/java/de/danoeh/antennapod/core/receiver/PlayerWidget.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java
@@ -1,4 +1,4 @@
-package de.danoeh.antennapod.core.receiver;
+package de.danoeh.antennapod.receiver;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
@@ -8,19 +8,18 @@ import android.util.Log;
import org.apache.commons.lang3.StringUtils;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.core.service.playback.PlayerWidgetService;
+import de.danoeh.antennapod.core.BuildConfig;
+import de.danoeh.antennapod.core.service.playback.PlaybackService;
+import de.danoeh.antennapod.service.PlayerWidgetService;
public class PlayerWidget extends AppWidgetProvider {
private static final String TAG = "PlayerWidget";
- public static final String FORCE_WIDGET_UPDATE = "de.danoeh.antennapod.FORCE_WIDGET_UPDATE";
- public static final String STOP_WIDGET_UPDATE = "de.danoeh.antennapod.STOP_WIDGET_UPDATE";
- @Override
+ @Override
public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), FORCE_WIDGET_UPDATE)) {
+ if (StringUtils.equals(intent.getAction(), PlaybackService.FORCE_WIDGET_UPDATE)) {
startUpdate(context);
- } else if (StringUtils.equals(intent.getAction(), STOP_WIDGET_UPDATE)) {
+ } else if (StringUtils.equals(intent.getAction(), PlaybackService.STOP_WIDGET_UPDATE)) {
stopUpdate(context);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/core/service/playback/PlayerWidgetService.java b/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java
index 495e2c0f2..514cbb74e 100644
--- a/app/src/main/java/de/danoeh/antennapod/core/service/playback/PlayerWidgetService.java
+++ b/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java
@@ -1,4 +1,4 @@
-package de.danoeh.antennapod.core.service.playback;
+package de.danoeh.antennapod.service;
import android.app.PendingIntent;
import android.app.Service;
@@ -12,10 +12,12 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.RemoteViews;
-import de.danoeh.antennapod.BuildConfig;
+import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
-import de.danoeh.antennapod.core.receiver.PlayerWidget;
+import de.danoeh.antennapod.receiver.PlayerWidget;
+import de.danoeh.antennapod.core.service.playback.PlaybackService;
+import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.playback.Playable;