summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Kalderstam <jonas@cowboyprogrammer.org>2019-10-05 01:18:14 +0200
committerJonas Kalderstam <jonas@cowboyprogrammer.org>2019-10-05 01:18:14 +0200
commit97aa36061186ae589b26e90939a32e83573368c2 (patch)
treeda900ade55ada0976017046c8ba0b7dd49937f9e
parentde78c0e31eeff0609fe5388204e6e39e8f60579b (diff)
parenteb70b4e0fa48f72eef50b2ca55eb590ae5df5726 (diff)
downloadAntennaPod-97aa36061186ae589b26e90939a32e83573368c2.zip
Merge remote-tracking branch 'antennapod/develop' into per_feed_playbackspeed
-rw-r--r--.circleci/config.yml69
-rw-r--r--.gitignore1
-rw-r--r--.tx/config2
-rw-r--r--CHANGELOG.md11
-rw-r--r--app/build.gradle70
-rw-r--r--app/proguard.cfg14
-rw-r--r--app/src/androidTest/java/de/danoeh/antennapod/core/service/download/StubDownloader.java52
-rw-r--r--app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java34
-rw-r--r--app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java5
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java127
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/playback/CancelablePSMPCallback.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/playback/DefaultPSMPCallback.java4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java57
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java8
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java20
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java32
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java9
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java16
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java14
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/VideoplayerActivityTest.java12
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java46
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java14
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java3
-rw-r--r--app/src/free/java/de/danoeh/antennapod/activity/CastEnabledActivity.java205
-rw-r--r--app/src/main/AndroidManifest.xml29
-rw-r--r--app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java22
-rw-r--r--app/src/main/java/de/danoeh/antennapod/PodcastApp.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java55
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java225
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java130
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java88
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java97
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java27
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java18
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java37
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java50
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java133
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java72
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java103
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java234
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java91
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java75
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java26
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java118
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java31
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java8
-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/TagFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java88
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java73
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java14
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java (renamed from app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java)97
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java195
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java13
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java95
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/PieChartView.java121
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java30
-rw-r--r--app/src/main/res/anim/card_flip_left_in.xml25
-rw-r--r--app/src/main/res/anim/card_flip_left_out.xml18
-rw-r--r--app/src/main/res/anim/card_flip_right_in.xml25
-rw-r--r--app/src/main/res/anim/card_flip_right_out.xml18
-rw-r--r--app/src/main/res/layout/addfeed.xml12
-rw-r--r--app/src/main/res/layout/all_episodes_fragment.xml2
-rw-r--r--app/src/main/res/layout/bug_report.xml28
-rw-r--r--app/src/main/res/layout/checkbox_do_not_show_again.xml17
-rw-r--r--app/src/main/res/layout/choose_data_folder_dialog_entry.xml2
-rw-r--r--app/src/main/res/layout/downloaded_episodeslist_item.xml2
-rw-r--r--app/src/main/res/layout/feedinfo.xml4
-rw-r--r--app/src/main/res/layout/feeditem_fragment.xml4
-rw-r--r--app/src/main/res/layout/feeditemlist_header.xml16
-rw-r--r--app/src/main/res/layout/gpodnet_podcast_listitem.xml2
-rw-r--r--app/src/main/res/layout/itunes_podcast_listitem.xml2
-rw-r--r--app/src/main/res/layout/main.xml6
-rw-r--r--app/src/main/res/layout/mediaplayerinfo_activity.xml41
-rw-r--r--app/src/main/res/layout/nav_feedlistitem.xml2
-rw-r--r--app/src/main/res/layout/pager_fragment.xml4
-rw-r--r--app/src/main/res/layout/queue_fragment.xml2
-rw-r--r--app/src/main/res/layout/queue_listitem.xml2
-rw-r--r--app/src/main/res/layout/quick_feed_discovery.xml4
-rw-r--r--app/src/main/res/layout/searchlist_item.xml2
-rw-r--r--app/src/main/res/layout/statistics_activity.xml55
-rw-r--r--app/src/main/res/layout/statistics_listitem.xml96
-rw-r--r--app/src/main/res/layout/statistics_listitem_total_time.xml42
-rw-r--r--app/src/main/res/menu/allepisodes_context.xml86
-rw-r--r--app/src/main/res/menu/episodes.xml2
-rw-r--r--app/src/main/res/menu/feedinfo.xml2
-rw-r--r--app/src/main/res/menu/feeditem_options.xml5
-rw-r--r--app/src/main/res/menu/feeditemlist_context.xml5
-rw-r--r--app/src/main/res/menu/feedlist.xml4
-rw-r--r--app/src/main/res/menu/gpodder_podcasts.xml2
-rw-r--r--app/src/main/res/menu/itunes_search.xml2
-rw-r--r--app/src/main/res/menu/mediaplayer.xml8
-rw-r--r--app/src/main/res/menu/queue.xml2
-rw-r--r--app/src/main/res/menu/queue_context.xml73
-rw-r--r--app/src/main/res/menu/subscriptions.xml7
-rw-r--r--app/src/main/res/values/integers.xml5
-rw-r--r--app/src/main/res/xml/preferences.xml14
-rw-r--r--app/src/main/res/xml/preferences_user_interface.xml2
-rw-r--r--app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java60
-rw-r--r--app/src/play/java/de/danoeh/antennapod/config/CastCallbackImpl.java6
-rw-r--r--app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java38
-rw-r--r--app/src/play/java/de/danoeh/antennapod/fragment/CustomMRControllerDialogFragment.java4
-rw-r--r--app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java15
-rw-r--r--build.gradle20
-rw-r--r--config/checkstyle/checkstyle-best-practice.xml252
-rw-r--r--config/checkstyle/checkstyle.xml82
-rw-r--r--core/build.gradle20
-rw-r--r--core/src/androidTest/java/de/danoeh/antennapod/core/util/DateUtilsTest.java2
-rw-r--r--core/src/free/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java2
-rw-r--r--core/src/main/AndroidManifest.xml5
-rw-r--r--core/src/main/java/androidx/core/app/SafeJobIntentService.java (renamed from core/src/main/java/android/support/v4/app/SafeJobIntentService.java)4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/dialog/DownloadRequestErrorDialogCreator.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/FeedMediaEvent.java23
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/MessageEvent.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/PlaybackPositionEvent.java19
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/ProgressEvent.java36
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/QueueEvent.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java18
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java69
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/SleepTimerPreferences.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java45
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java30
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java8
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java18
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java23
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java95
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/Downloader.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java42
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java134
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java49
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java36
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java66
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java9
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java20
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/DuckType.java117
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java38
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java36
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/FeedtitleComparator.java15
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/IntentUtils.java16
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/Optional.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/ThemeUtils.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/comparator/SearchResultValueComparator.java27
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java70
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/exception/RxJavaErrorHandlerSetup.java18
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/gui/NotificationUtils.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java55
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java2
-rwxr-xr-xcore/src/main/res/drawable-hdpi/ic_baseline_question_answer_white_24dp.pngbin187 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_cast_disabled_light.pngbin770 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_cast_light.pngbin975 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_cast_off_light.pngbin867 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_cast_on_0_light.pngbin961 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_cast_on_1_light.pngbin979 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_cast_on_2_light.pngbin976 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_cast_on_light.pngbin982 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_close_light.pngbin493 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_format_list_bulleted_grey600_24dp.pngbin492 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_format_list_bulleted_white_24dp.pngbin459 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_forum_grey600_24dp.pngbin601 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_media_cast_disconnect.pngbin2355 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_pause_light.pngbin191 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_play_light.pngbin562 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_stat_antenna_default.pngbin541 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_stat_authentication.pngbin371 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-ldpi/ic_stat_antenna_default.pngbin259 -> 0 bytes
-rwxr-xr-xcore/src/main/res/drawable-mdpi/ic_baseline_question_answer_white_24dp.pngbin139 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_cast_disabled_light.pngbin536 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_cast_light.pngbin693 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_cast_off_light.pngbin635 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_cast_on_0_light.pngbin684 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_cast_on_1_light.pngbin696 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_cast_on_2_light.pngbin690 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_cast_on_light.pngbin694 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_close_light.pngbin379 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_format_list_bulleted_grey600_24dp.pngbin423 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_format_list_bulleted_white_24dp.pngbin406 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_forum_grey600_24dp.pngbin488 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_media_cast_disconnect.pngbin1467 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_pause_light.pngbin280 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_play_light.pngbin447 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_stat_antenna_default.pngbin349 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_stat_authentication.pngbin244 -> 0 bytes
-rwxr-xr-xcore/src/main/res/drawable-xhdpi/ic_baseline_question_answer_white_24dp.pngbin212 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_cast_disabled_light.pngbin976 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_cast_light.pngbin1328 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_cast_off_light.pngbin1161 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_cast_on_0_light.pngbin1286 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_cast_on_1_light.pngbin1308 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_cast_on_2_light.pngbin1309 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_cast_on_light.pngbin1331 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_close_light.pngbin526 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_format_list_bulleted_grey600_24dp.pngbin504 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_format_list_bulleted_white_24dp.pngbin462 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_forum_grey600_24dp.pngbin602 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_media_cast_disconnect.pngbin4496 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_pause_light.pngbin221 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_play_light.pngbin678 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_stat_antenna_default.pngbin783 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_stat_authentication.pngbin418 -> 0 bytes
-rwxr-xr-xcore/src/main/res/drawable-xxhdpi/ic_baseline_question_answer_white_24dp.pngbin276 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_cast_disabled_light.pngbin1429 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_cast_light.pngbin1952 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_cast_off_light.pngbin1679 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_cast_on_0_light.pngbin1832 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_cast_on_1_light.pngbin1893 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_cast_on_2_light.pngbin1910 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_cast_on_light.pngbin1944 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_close_light.pngbin673 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_format_list_bulleted_grey600_24dp.pngbin631 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_format_list_bulleted_white_24dp.pngbin594 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_forum_grey600_24dp.pngbin766 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_media_cast_disconnect.pngbin7096 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_pause_light.pngbin317 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_play_light.pngbin955 -> 0 bytes
-rwxr-xr-xcore/src/main/res/drawable-xxhdpi/ic_stat_authentication.pngbin848 -> 0 bytes
-rwxr-xr-xcore/src/main/res/drawable-xxxhdpi/ic_baseline_question_answer_white_24db.pngbin310 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_close_light.pngbin805 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_format_list_bulleted_grey600_24dp.pngbin738 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_format_list_bulleted_white_24dp.pngbin666 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_forum_grey600_24dp.pngbin900 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_pause_light.pngbin400 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_play_light.pngbin1190 -> 0 bytes
-rw-r--r--core/src/main/res/drawable/ic_antenna.xml6
-rw-r--r--core/src/main/res/drawable/ic_chat_grey600.xml5
-rw-r--r--core/src/main/res/drawable/ic_chat_white.xml5
-rw-r--r--core/src/main/res/drawable/ic_notification.pngbin3887 -> 0 bytes
-rw-r--r--core/src/main/res/drawable/ic_notification_cast_off.xml5
-rw-r--r--core/src/main/res/drawable/ic_notification_fast_forward.xml5
-rw-r--r--core/src/main/res/drawable/ic_notification_fast_rewind.xml5
-rw-r--r--core/src/main/res/drawable/ic_notification_key.xml6
-rw-r--r--core/src/main/res/drawable/ic_notification_pause.xml5
-rw-r--r--core/src/main/res/drawable/ic_notification_play.xml5
-rw-r--r--core/src/main/res/drawable/ic_notification_skip.xml5
-rw-r--r--core/src/main/res/drawable/ic_playback_speed_dark.xml8
-rw-r--r--core/src/main/res/drawable/ic_playback_speed_white.xml8
-rw-r--r--core/src/main/res/drawable/ic_questionmark_grey600.xml5
-rw-r--r--core/src/main/res/drawable/ic_questionmark_white.xml5
-rw-r--r--core/src/main/res/drawable/ic_warning_red.xml5
-rw-r--r--core/src/main/res/drawable/notification_default_large_icon.xml15
-rw-r--r--core/src/main/res/drawable/white_circle.xml11
-rw-r--r--core/src/main/res/values-de/strings.xml6
-rw-r--r--core/src/main/res/values-hu/strings.xml1
-rw-r--r--core/src/main/res/values-in/strings.xml (renamed from core/src/main/res/values-id/strings.xml)0
-rw-r--r--core/src/main/res/values-land/styles.xml6
-rw-r--r--core/src/main/res/values-large/dimens.xml1
-rw-r--r--core/src/main/res/values-pl-rPL/strings.xml12
-rw-r--r--core/src/main/res/values-v16/styles.xml8
-rw-r--r--core/src/main/res/values-v19/colors.xml1
-rw-r--r--core/src/main/res/values/arrays.xml10
-rw-r--r--core/src/main/res/values/attrs.xml5
-rw-r--r--core/src/main/res/values/colors.xml6
-rw-r--r--core/src/main/res/values/dimens.xml3
-rw-r--r--core/src/main/res/values/integers.xml1
-rw-r--r--core/src/main/res/values/strings.xml55
-rw-r--r--core/src/main/res/values/styles.xml27
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/CastCallbacks.java4
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/ClientConfig.java13
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java14
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/cast/RemoteMedia.java2
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/cast/SwitchableMediaRouteActionProvider.java12
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java37
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java2
-rw-r--r--gradle.properties3
397 files changed, 3719 insertions, 2865 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 258340afc..b5903350f 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -1,39 +1,74 @@
-version: 2
+version: 2.1
jobs:
build:
+ parameters:
+ build-steps:
+ description: "Steps that will be executed for this build"
+ type: steps
+ default: []
docker:
- image: circleci/android:api-28
-
working_directory: ~/AntennaPod
-
environment:
GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx1536m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError"'
_JAVA_OPTIONS: "-Xms256m -Xmx1280m"
-
steps:
- checkout
-
- restore_cache:
keys:
- v1-android-{{ checksum "build.gradle" }}
- # fallback to using the latest cache if no exact match is found
- v1-android-
-
- run:
- # To build release, we need to create a temporary keystore that can be used to sign the app
- command: |
- keytool -noprompt -genkey -v -keystore "app/keystore" -alias alias -storepass password -keypass password -keyalg RSA -validity 10 -dname "CN=antennapod.org, OU=dummy, O=dummy, L=dummy, S=dummy, C=US"
- ./gradlew assembleRelease :core:testPlayReleaseUnitTest :app:assemblePlayDebugAndroidTest -PdisablePreDex
- no_output_timeout: 1800
-
- - store_artifacts:
- path: app/build/outputs/apk
- destination: apks
-
+ name: Create temporary release keystore
+ command: keytool -noprompt -genkey -v -keystore "app/keystore" -alias alias -storepass password -keypass password -keyalg RSA -validity 10 -dname "CN=antennapod.org, OU=dummy, O=dummy, L=dummy, S=dummy, C=US"
+ - steps: << parameters.build-steps >>
- save_cache:
paths:
- ~/.android
- ~/.gradle
- ~/android
key: v1-android-{{ checksum "build.gradle" }}
+
+workflows:
+ unit-tests:
+ jobs:
+ - build:
+ name: Build debug
+ build-steps:
+ - run:
+ name: Build debug
+ command: ./gradlew assembleDebug -PdisablePreDex
+ - run:
+ name: Execute debug unit tests
+ command: ./gradlew :core:testPlayDebugUnitTest -PdisablePreDex
+ - build:
+ name: Build release
+ build-steps:
+ - run:
+ name: Build release
+ command: ./gradlew assembleRelease -PdisablePreDex
+ - run:
+ name: Execute release unit tests
+ command: ./gradlew :core:testPlayReleaseUnitTest -PdisablePreDex
+ - build:
+ name: Build integration tests
+ build-steps:
+ - run:
+ name: Build integration tests
+ command: ./gradlew :app:assemblePlayDebugAndroidTest -PdisablePreDex
+ - build:
+ name: Build free
+ build-steps:
+ - run:
+ name: Build free (for F-Droid)
+ command: ./gradlew assembleFreeRelease -PdisablePreDex -PfreeBuild
+
+ static-analysis:
+ jobs:
+ - build:
+ name: Checkstyle
+ build-steps:
+ - run:
+ name: Checkstyle
+ command: ./gradlew checkstyle
diff --git a/.gitignore b/.gitignore
index 7e39550e9..b10f948bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,7 +16,6 @@ build/
# Local configuration file (sdk path, etc)
local.properties
-gradle.properties
.gradle
build.xml
diff --git a/.tx/config b/.tx/config
index d7356e199..ea1c0ccef 100644
--- a/.tx/config
+++ b/.tx/config
@@ -24,7 +24,7 @@ trans.gl = core/src/main/res/values-gl-rES/strings.xml
trans.he_IL = core/src/main/res/values-iw-rIL/strings.xml
trans.hi_IN = core/src/main/res/values-hi-rIN/strings.xml
trans.hu = core/src/main/res/values-hu/strings.xml
-trans.id = core/src/main/res/values-id/strings.xml
+trans.id = core/src/main/res/values-in/strings.xml
trans.it_IT = core/src/main/res/values-it/strings.xml
trans.is = core/src/main/res/values-is-rIS/strings.xml
trans.ja = core/src/main/res/values-ja/strings.xml
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1e966b997..fb429f026 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,17 @@
Change Log
==========
+Version 1.7.3
+-------------
+* Display episode image on widget (by @brad)
+* Added checkbox to keep queue sorted (by @damoasda)
+* New UI for "Add podcast" screen (by @ByteHamster)
+* Added batch editing to the queue (by @ByteHamster)
+* Added option to adapt remaining time to playback speed (by @CedricCabessa)
+* Removed broken Flattr integration (by @ByteHamster)
+* Added filter to "All episodes" list (by @jhunnius)
+* Tons of bug fixes and performance improvements
+
Version 1.7.2
-------------
* Added configurable behavior of the back button
diff --git a/app/build.gradle b/app/build.gradle
index 7545386a2..5f70d285f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -18,10 +18,10 @@ android {
// "1.2.3-SNAPSHOT" -> 1020300
// "1.2.3-RC4" -> 1020304
// "1.2.3" -> 1020395
- versionCode 1070306
- versionName "1.7.3-RC6"
+ versionCode 1070396
+ versionName "1.7.3b"
testApplicationId "de.test.antennapod"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
generatedDensities = []
javaCompileOptions {
@@ -131,18 +131,14 @@ dependencies {
} else {
System.out.println("app: free build hack, skipping some dependencies")
}
- implementation "com.android.support:support-v4:$supportVersion"
- implementation "com.android.support:appcompat-v7:$supportVersion"
- implementation "com.android.support:design:$supportVersion"
- implementation "com.android.support:preference-v14:$supportVersion"
- implementation "com.android.support:gridlayout-v7:$supportVersion"
- implementation "com.android.support:recyclerview-v7:$supportVersion"
- compileOnly 'com.google.android.wearable:wearable:2.2.0'
-
- // ViewModel and LiveData
- implementation "android.arch.lifecycle:extensions:$lifecycle_version"
- annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"
-
+ implementation "androidx.appcompat:appcompat:1.1.0"
+ implementation "androidx.preference:preference:1.1.0"
+ implementation "androidx.gridlayout:gridlayout:1.0.0"
+ implementation "androidx.recyclerview:recyclerview:1.0.0"
+ implementation "androidx.media:media:1.1.0"
+ implementation "com.google.android.material:material:1.0.0"
+ annotationProcessor "androidx.annotation:annotation:1.1.0"
+ compileOnly "com.google.android.wearable:wearable:$wearableSupportVersion"
implementation "org.apache.commons:commons-lang3:$commonslangVersion"
implementation "commons-io:commons-io:$commonsioVersion"
implementation "org.jsoup:jsoup:$jsoupVersion"
@@ -162,26 +158,21 @@ dependencies {
transitive = true
}
implementation "com.yqritc:recyclerview-flexibledivider:$recyclerviewFlexibledividerVersion"
- implementation("com.githang:viewpagerindicator:2.5.1@aar") {
- exclude module: "support-v4"
- }
-
+ implementation "com.githang:viewpagerindicator:2.5.1@aar"
implementation "com.github.shts:TriangleLabelView:$triangleLabelViewVersion"
- implementation 'com.leinardi.android:speed-dial:1.0.2' // 1.0.2 uses support 27.1.1 ; newer versions use 28.0.0;
-
+ implementation 'com.leinardi.android:speed-dial:3.0.0'
implementation "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion"
-
implementation 'com.github.mfietz:fyydlin:v0.4.2'
implementation 'com.github.ByteHamster:SearchPreference:v1.3.0'
- implementation "org.awaitility:awaitility:$awaitilityVersion"
+ androidTestImplementation "org.awaitility:awaitility:$awaitilityVersion"
androidTestImplementation 'com.nanohttpd:nanohttpd-webserver:2.1.1'
androidTestImplementation "com.jayway.android.robotium:robotium-solo:$robotiumSoloVersion"
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
- androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:3.0.2'
- androidTestImplementation 'com.android.support.test.espresso:espresso-intents:3.0.2'
- androidTestImplementation 'com.android.support.test:runner:1.0.2'
- androidTestImplementation 'com.android.support.test:rules:1.0.2'
+ androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
+ androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
+ androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
+ androidTestImplementation 'androidx.test:runner:1.2.0'
+ androidTestImplementation 'androidx.test:rules:1.2.0'
}
if (project.hasProperty("antennaPodServiceAccountEmail")) {
@@ -193,20 +184,14 @@ if (project.hasProperty("antennaPodServiceAccountEmail")) {
}
}
-// about.html is templatized so that we can automatically insert
-// our version string in to it at build time.
-task filterAbout {
- inputs.files files(["src/main/templates/about.html",
- "src/main/AndroidManifest.xml"])
- outputs.file "src/main/assets/about.html"
-} doLast {
- copy {
- from "src/main/templates/about.html"
- into "src/main/assets"
- filter(ReplaceTokens, tokens: [versionname: android.defaultConfig.versionName,
- commit : "git rev-parse --short HEAD".execute().text,
- year : new Date().format('yyyy')])
- }
+task filterAbout(type: Copy) {
+ from "src/main/templates/about.html"
+ into "src/main/assets"
+ filter(ReplaceTokens, tokens: [
+ versionname: android.defaultConfig.versionName,
+ commit : "git rev-parse --short HEAD".execute().text,
+ year : new Date().format('yyyy')])
+ outputs.upToDateWhen { false }
}
task copyTextFiles(type: Copy) {
@@ -216,6 +201,7 @@ task copyTextFiles(type: Copy) {
rename { String fileName ->
fileName + ".txt"
}
+ outputs.upToDateWhen { false }
}
preBuild.dependsOn filterAbout, copyTextFiles
diff --git a/app/proguard.cfg b/app/proguard.cfg
index 958048ef3..5309e833d 100644
--- a/app/proguard.cfg
+++ b/app/proguard.cfg
@@ -66,13 +66,13 @@
# for retrolambda
-dontwarn java.lang.invoke.*
--keep class android.support.v4.** { *; }
--keep interface android.support.v4.** { *; }
--keep class !android.support.v7.internal.view.menu.**,android.support.v7.** {*;}
--keep interface android.support.v7.** { *; }
--keep class com.google.android.wearable.** { *; }
--dontwarn android.support.v4.**
--dontwarn android.support.v7.**
+-dontwarn com.google.android.material.**
+-keep class com.google.android.material.** { *; }
+
+-dontwarn androidx.**
+-keep class androidx.** { *; }
+-keep interface androidx.** { *; }
+
-dontwarn com.google.android.wearable.**
-keep class org.apache.commons.** { *; }
diff --git a/app/src/androidTest/java/de/danoeh/antennapod/core/service/download/StubDownloader.java b/app/src/androidTest/java/de/danoeh/antennapod/core/service/download/StubDownloader.java
new file mode 100644
index 000000000..e7fe079a6
--- /dev/null
+++ b/app/src/androidTest/java/de/danoeh/antennapod/core/service/download/StubDownloader.java
@@ -0,0 +1,52 @@
+package de.danoeh.antennapod.core.service.download;
+
+import androidx.annotation.NonNull;
+
+import de.danoeh.antennapod.core.util.Consumer;
+
+public class StubDownloader extends Downloader {
+
+ private final long downloadTime;
+
+ @NonNull
+ private final Consumer<DownloadStatus> onDownloadComplete;
+
+ public StubDownloader(@NonNull DownloadRequest request, long downloadTime, @NonNull Consumer<DownloadStatus> onDownloadComplete) {
+ super(request);
+ this.downloadTime = downloadTime;
+ this.onDownloadComplete = onDownloadComplete;
+ }
+
+ @Override
+ protected void download() {
+ try {
+ Thread.sleep(downloadTime);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ onDownloadComplete.accept(result);
+ }
+
+ @NonNull
+ @Override
+ public DownloadRequest getDownloadRequest() {
+ return super.getDownloadRequest();
+ }
+
+ @NonNull
+ @Override
+ public DownloadStatus getResult() {
+ return super.getResult();
+ }
+
+ @Override
+ public boolean isFinished() {
+ return super.isFinished();
+ }
+
+ @Override
+ public void cancel() {
+ super.cancel();
+ result.setCancelled();
+ }
+}
diff --git a/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java b/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java
index 9e86275fc..f895b4d5e 100644
--- a/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java
@@ -1,33 +1,31 @@
package de.test.antennapod;
import android.content.Context;
-import android.content.SharedPreferences;
-import android.support.annotation.StringRes;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.espresso.PerformException;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.contrib.DrawerActions;
-import android.support.test.espresso.contrib.RecyclerViewActions;
-import android.support.test.espresso.util.HumanReadables;
-import android.support.test.espresso.util.TreeIterables;
+import androidx.annotation.StringRes;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.espresso.PerformException;
+import androidx.test.espresso.UiController;
+import androidx.test.espresso.ViewAction;
+import androidx.test.espresso.contrib.DrawerActions;
+import androidx.test.espresso.contrib.RecyclerViewActions;
+import androidx.test.espresso.util.HumanReadables;
+import androidx.test.espresso.util.TreeIterables;
import android.view.View;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.dialog.RatingDialog;
-import de.danoeh.antennapod.fragment.QueueFragment;
import org.hamcrest.Matcher;
import java.io.File;
import java.util.concurrent.TimeoutException;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
-import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
+import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
public class EspressoTestUtils {
/**
@@ -115,7 +113,7 @@ public class EspressoTestUtils {
}
public static void clickPreference(@StringRes int title) {
- onView(withId(R.id.list)).perform(
+ onView(withId(R.id.recycler_view)).perform(
RecyclerViewActions.actionOnItem(hasDescendant(withText(title)),
click()));
}
diff --git a/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java b/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java
index e8a87ecf1..b3c79367f 100644
--- a/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java
@@ -4,9 +4,9 @@ import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SmallTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
import org.junit.After;
diff --git a/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java b/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java
index 8cd9b0fa1..4b81a4f2b 100644
--- a/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java
@@ -1,6 +1,6 @@
package de.test.antennapod.feed;
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
import de.danoeh.antennapod.core.feed.FeedFilter;
import de.danoeh.antennapod.core.feed.FeedItem;
import org.junit.Test;
diff --git a/app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java b/app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java
index 9779b32a5..0b9a67d0a 100644
--- a/app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java
@@ -1,6 +1,6 @@
package de.test.antennapod.feed;
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
import de.danoeh.antennapod.core.feed.FeedItem;
import org.junit.Test;
diff --git a/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java b/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java
index 91e31e73c..cd3847f17 100644
--- a/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java
@@ -4,7 +4,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetDevice;
diff --git a/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java b/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
index dfb78d5a9..4f6bf0c1f 100644
--- a/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
@@ -1,8 +1,8 @@
package de.test.antennapod.handler;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -12,7 +12,6 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
-import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
diff --git a/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java b/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java
new file mode 100644
index 000000000..cb099cc85
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java
@@ -0,0 +1,127 @@
+package de.test.antennapod.service.download;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.awaitility.Awaitility;
+import org.awaitility.core.ConditionTimeoutException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.service.download.DownloadRequest;
+import de.danoeh.antennapod.core.service.download.DownloadService;
+import de.danoeh.antennapod.core.service.download.DownloadStatus;
+import de.danoeh.antennapod.core.service.download.Downloader;
+import de.danoeh.antennapod.core.service.download.StubDownloader;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.core.storage.DownloadRequester;
+import de.danoeh.antennapod.core.util.Consumer;
+
+import static de.test.antennapod.util.event.FeedItemEventListener.withFeedItemEventListener;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @see HttpDownloaderTest for the test of actual download (and saving the file)
+ */
+@RunWith(AndroidJUnit4.class)
+public class DownloadServiceTest {
+
+ private CountDownLatch latch = null;
+ private Feed testFeed = null;
+ private FeedMedia testMedia11 = null;
+
+ private DownloadService.DownloaderFactory origFactory = null;
+
+ @Before
+ public void setUp() throws Exception {
+ origFactory = DownloadService.getDownloaderFactory();
+ testFeed = setUpTestFeeds();
+ testMedia11 = testFeed.getItemAtIndex(0).getMedia();
+ }
+
+ private Feed setUpTestFeeds() throws Exception {
+ Feed feed = new Feed("url", null, "Test Feed title 1");
+ List<FeedItem> items = new ArrayList<>();
+ feed.setItems(items);
+ FeedItem item1 = new FeedItem(0, "Item 1-1", "Item 1-1", "url", new Date(), FeedItem.NEW, feed);
+ items.add(item1);
+ FeedMedia media1 = new FeedMedia(0, item1, 123, 1, 1, "audio/mp3", null, "http://example.com/episode.mp3", false, null, 0, 0);
+ item1.setMedia(media1);
+
+ DBWriter.setFeedItem(item1).get();
+ return feed;
+ }
+
+
+ @After
+ public void tearDown() throws Exception {
+ DownloadService.setDownloaderFactory(origFactory);
+ }
+
+ @Test
+ public void testEventsGeneratedCaseMediaDownloadSuccess() throws Exception {
+ // create a stub download that returns successful
+ //
+ // OPEN: Ideally, I'd like the download time long enough so that multiple in-progress DownloadEvents
+ // are generated (to simulate typical download), but it'll make download time quite long (1-2 seconds)
+ // to do so
+ DownloadService.setDownloaderFactory(new StubDownloaderFactory(50, downloadStatus -> {
+ downloadStatus.setSuccessful();
+ }));
+
+ withFeedItemEventListener(feedItemEventListener -> {
+ try {
+ assertEquals(0, feedItemEventListener.getEvents().size());
+ assertFalse("The media in test should not yet been downloaded",
+ DBReader.getFeedMedia(testMedia11.getId()).isDownloaded());
+
+ DownloadRequester.getInstance().downloadMedia(InstrumentationRegistry.getTargetContext(),
+ testMedia11);
+ Awaitility.await()
+ .atMost(1000, TimeUnit.MILLISECONDS)
+ .until(() -> feedItemEventListener.getEvents().size() > 0);
+ assertTrue("After media download has completed, FeedMedia object in db should indicate so.",
+ DBReader.getFeedMedia(testMedia11.getId()).isDownloaded());
+ } catch (ConditionTimeoutException cte) {
+ fail("The expected FeedItemEvent (for media download complete) has not been posted. "
+ + cte.getMessage());
+ }
+ });
+ }
+
+ private static class StubDownloaderFactory implements DownloadService.DownloaderFactory {
+ private final long downloadTime;
+
+ @NonNull
+ private final Consumer<DownloadStatus> onDownloadComplete;
+
+ StubDownloaderFactory(long downloadTime, @NonNull Consumer<DownloadStatus> onDownloadComplete) {
+ this.downloadTime = downloadTime;
+ this.onDownloadComplete = onDownloadComplete;
+ }
+
+ @Nullable
+ @Override
+ public Downloader create(@NonNull DownloadRequest request) {
+ return new StubDownloader(request, downloadTime, onDownloadComplete);
+ }
+ }
+
+}
diff --git a/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java b/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java
index 967bf431c..4530b7679 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java
@@ -1,7 +1,7 @@
package de.test.antennapod.service.download;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
import android.util.Log;
import java.io.File;
diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/CancelablePSMPCallback.java b/app/src/androidTest/java/de/test/antennapod/service/playback/CancelablePSMPCallback.java
index 085e2c479..6bd519228 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/playback/CancelablePSMPCallback.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/playback/CancelablePSMPCallback.java
@@ -1,6 +1,6 @@
package de.test.antennapod.service.playback;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.service.playback.PlaybackServiceMediaPlayer;
import de.danoeh.antennapod.core.util.playback.Playable;
diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/DefaultPSMPCallback.java b/app/src/androidTest/java/de/test/antennapod/service/playback/DefaultPSMPCallback.java
index 113239908..5a16ab954 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/playback/DefaultPSMPCallback.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/playback/DefaultPSMPCallback.java
@@ -1,7 +1,7 @@
package de.test.antennapod.service.playback;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.service.playback.PlaybackServiceMediaPlayer;
import de.danoeh.antennapod.core.util.playback.Playable;
diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
index 502115cc3..c43818a73 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
@@ -2,8 +2,8 @@ package de.test.antennapod.service.playback;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
import de.test.antennapod.EspressoTestUtils;
import junit.framework.AssertionFailedError;
@@ -32,7 +32,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import static android.support.test.InstrumentationRegistry.getInstrumentation;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java
index 9c0e90929..415ee9b68 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java
@@ -1,9 +1,15 @@
package de.test.antennapod.service.playback;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.LargeTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+
+import org.awaitility.Awaitility;
+import org.greenrobot.eventbus.EventBus;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
import java.util.ArrayList;
import java.util.Date;
@@ -15,14 +21,14 @@ import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.service.playback.PlaybackServiceTaskManager;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.playback.Playable;
-import org.greenrobot.eventbus.EventBus;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import static de.test.antennapod.util.event.FeedItemEventListener.withFeedItemEventListener;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -124,6 +130,43 @@ public class PlaybackServiceTaskManagerTest {
}
@Test
+ public void testQueueUpdatedUponDownloadComplete() throws Exception {
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ { // Setup test data
+ List<FeedItem> queue = writeTestQueue("a");
+ FeedItem item = DBReader.getFeedItem(queue.get(0).getId());
+ FeedMedia media = new FeedMedia(item, "http://example.com/episode.mp3", 12345, "audio/mp3");
+ item.setMedia(media);
+ DBWriter.setFeedMedia(media).get();
+ DBWriter.setFeedItem(item).get();
+ }
+
+ PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
+ final FeedItem testItem = pstm.getQueue().get(0);
+ assertFalse("The item should not yet be downloaded", testItem.getMedia().isDownloaded());
+
+ withFeedItemEventListener( feedItemEventListener -> {
+ // simulate download complete (in DownloadService.MediaHandlerThread)
+ FeedItem item = DBReader.getFeedItem(testItem.getId());
+ item.getMedia().setDownloaded(true);
+ item.getMedia().setFile_url("file://123");
+ item.setAutoDownload(false);
+ DBWriter.setFeedMedia(item.getMedia()).get();
+ DBWriter.setFeedItem(item).get();
+
+ Awaitility.await()
+ .atMost(1000, TimeUnit.MILLISECONDS)
+ .until(() -> feedItemEventListener.getEvents().size() > 0);
+
+ final FeedItem itemUpdated = pstm.getQueue().get(0);
+ assertTrue("media.isDownloaded() should be true - The queue in PlaybackService should be updated after download is completed",
+ itemUpdated.getMedia().isDownloaded());
+ });
+
+ pstm.shutdown();
+ }
+
+ @Test
public void testStartPositionSaver() throws InterruptedException {
final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
final int NUM_COUNTDOWNS = 2;
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java b/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
index e78894e59..1acb96d01 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
@@ -10,9 +10,9 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SmallTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java
index fe5091eb9..24cc80061 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java
@@ -10,9 +10,9 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SmallTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java
index 3320aa545..de810c701 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java
@@ -5,7 +5,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.preferences.UserPreferences;
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java
index d99a409d3..647ab911f 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java
@@ -7,9 +7,9 @@ import java.util.Date;
import java.util.List;
import java.util.Random;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SmallTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java
index 6af12315c..55ea16f13 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java
@@ -7,9 +7,9 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SmallTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
index 7663bb3c9..42f4413d3 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
@@ -4,9 +4,9 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.preference.PreferenceManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
import android.util.Log;
import org.awaitility.Awaitility;
@@ -33,7 +33,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import static android.support.test.InstrumentationRegistry.getInstrumentation;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
index 0c65bb2e6..9f16888fa 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
@@ -1,20 +1,16 @@
package de.test.antennapod.ui;
import android.app.Activity;
-import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.espresso.intent.rule.IntentsTestRule;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.espresso.intent.rule.IntentsTestRule;
+import androidx.test.runner.AndroidJUnit4;
import com.robotium.solo.Solo;
import com.robotium.solo.Timeout;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
-import de.danoeh.antennapod.dialog.RatingDialog;
import de.test.antennapod.EspressoTestUtils;
import org.junit.After;
import org.junit.Before;
@@ -24,11 +20,11 @@ import org.junit.runner.RunWith;
import java.io.IOException;
-import static android.support.test.InstrumentationRegistry.getInstrumentation;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.contrib.ActivityResultMatchers.hasResultCode;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.contrib.ActivityResultMatchers.hasResultCode;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static de.test.antennapod.EspressoTestUtils.clickPreference;
import static de.test.antennapod.EspressoTestUtils.openNavDrawer;
import static junit.framework.TestCase.assertTrue;
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java b/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java
index 548843636..360b55ce6 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java
@@ -1,21 +1,17 @@
package de.test.antennapod.ui;
-import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.espresso.ViewInteraction;
-import android.support.test.espresso.contrib.DrawerActions;
-import android.support.test.espresso.intent.rule.IntentsTestRule;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.espresso.ViewInteraction;
+import androidx.test.espresso.contrib.DrawerActions;
+import androidx.test.espresso.intent.rule.IntentsTestRule;
+import androidx.test.runner.AndroidJUnit4;
import android.view.View;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.PodDBAdapter;
-import de.danoeh.antennapod.dialog.RatingDialog;
import de.danoeh.antennapod.fragment.DownloadsFragment;
import de.danoeh.antennapod.fragment.EpisodesFragment;
import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
@@ -33,15 +29,15 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.action.ViewActions.longClick;
-import static android.support.test.espresso.action.ViewActions.scrollTo;
-import static android.support.test.espresso.intent.Intents.intended;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
-import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.action.ViewActions.longClick;
+import static androidx.test.espresso.action.ViewActions.scrollTo;
+import static androidx.test.espresso.intent.Intents.intended;
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
+import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static de.test.antennapod.EspressoTestUtils.waitForView;
import static de.test.antennapod.NthMatcher.first;
import static junit.framework.TestCase.assertTrue;
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java
index 22959917d..5b3530ea8 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java
@@ -4,9 +4,9 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
import android.view.View;
import android.widget.ListView;
@@ -23,14 +23,13 @@ import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.test.antennapod.EspressoTestUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import static android.support.test.InstrumentationRegistry.getInstrumentation;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
index b302bcc91..eb5de03c4 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
@@ -4,9 +4,9 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
import android.view.View;
import android.widget.ListView;
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
index 1063ac90a..b46af83c8 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
@@ -4,9 +4,9 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.preference.PreferenceManager;
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
+import androidx.test.rule.ActivityTestRule;
import com.robotium.solo.Solo;
import com.robotium.solo.Timeout;
@@ -29,12 +29,12 @@ import de.danoeh.antennapod.fragment.EpisodesFragment;
import de.danoeh.antennapod.fragment.QueueFragment;
import de.danoeh.antennapod.fragment.SubscriptionFragment;
-import static android.support.test.InstrumentationRegistry.getInstrumentation;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static de.test.antennapod.EspressoTestUtils.clickPreference;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java b/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java
index d1023dd9e..7f0bf8fa2 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java
@@ -1,9 +1,9 @@
package de.test.antennapod.ui;
import android.content.Intent;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.intent.rule.IntentsTestRule;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.espresso.Espresso;
+import androidx.test.espresso.intent.rule.IntentsTestRule;
+import androidx.test.runner.AndroidJUnit4;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.fragment.QueueFragment;
@@ -13,10 +13,10 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
/**
* User interface tests for queue fragment
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java
index 7555bb69a..a183b648e 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java
@@ -5,9 +5,9 @@ import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import org.junit.After;
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/VideoplayerActivityTest.java b/app/src/androidTest/java/de/test/antennapod/ui/VideoplayerActivityTest.java
index c4dd032d7..ab16d7603 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/VideoplayerActivityTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/VideoplayerActivityTest.java
@@ -1,8 +1,8 @@
package de.test.antennapod.ui;
import android.content.Intent;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.VideoplayerActivity;
@@ -10,10 +10,10 @@ import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
/**
* Test class for VideoplayerActivity
diff --git a/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java b/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java
index ac98d2802..f2dfca92e 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java
@@ -1,8 +1,8 @@
package de.test.antennapod.util;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SmallTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
import android.text.TextUtils;
import java.io.File;
diff --git a/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java b/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java
index b96cb273b..5bc2f7bd8 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java
@@ -1,6 +1,6 @@
package de.test.antennapod.util;
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
import de.danoeh.antennapod.core.util.URLChecker;
import org.junit.Test;
diff --git a/app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java b/app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java
new file mode 100644
index 000000000..601bba853
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java
@@ -0,0 +1,46 @@
+package de.test.antennapod.util.event;
+
+import androidx.annotation.NonNull;
+
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.danoeh.antennapod.core.event.FeedItemEvent;
+import io.reactivex.functions.Consumer;
+
+/**
+ * Test helpers to listen {@link FeedItemEvent} and handle them accordingly
+ *
+ */
+public class FeedItemEventListener {
+ private final List<FeedItemEvent> events = new ArrayList<>();
+
+ /**
+ * Provides an listener subscribing to {@link FeedItemEvent} that the callers can use
+ *
+ * Note: it uses RxJava's version of {@link Consumer} because it allows exceptions to be thrown.
+ */
+ public static void withFeedItemEventListener(@NonNull Consumer<FeedItemEventListener> consumer)
+ throws Exception {
+ FeedItemEventListener feedItemEventListener = new FeedItemEventListener();
+ try {
+ EventBus.getDefault().register(feedItemEventListener);
+ consumer.accept(feedItemEventListener);
+ } finally {
+ EventBus.getDefault().unregister(feedItemEventListener);
+ }
+ }
+
+ @Subscribe
+ public void onEvent(FeedItemEvent event) {
+ events.add(event);
+ }
+
+ @NonNull
+ public List<? extends FeedItemEvent> getEvents() {
+ return events;
+ }
+}
diff --git a/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java b/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java
index df69859a0..c42695a57 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java
@@ -2,8 +2,8 @@ package de.test.antennapod.util.playback;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
diff --git a/app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java b/app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java
index 3d8417bf6..4158fd31c 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java
@@ -72,20 +72,6 @@ public class HTTPBin extends NanoHTTPD {
return servedFiles.size() - 1;
}
- /**
- * Removes the file with the given ID from the server.
- *
- * @return True if a file was removed, false otherwise
- */
- public synchronized boolean removeFile(int id) {
- if (id < 0) throw new IllegalArgumentException("ID < 0");
- if (id >= servedFiles.size()) {
- return false;
- } else {
- return servedFiles.remove(id) != null;
- }
- }
-
public synchronized File accessFile(int id) {
if (id < 0 || id >= servedFiles.size()) {
return null;
diff --git a/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java b/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java
index d4837ef60..2dda77524 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java
@@ -1,12 +1,11 @@
package de.test.antennapod.util.syndication;
-import android.support.test.InstrumentationRegistry;
+import androidx.test.InstrumentationRegistry;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileOutputStream;
-import java.nio.file.Files;
import java.util.Map;
import de.danoeh.antennapod.core.util.syndication.FeedDiscoverer;
diff --git a/app/src/free/java/de/danoeh/antennapod/activity/CastEnabledActivity.java b/app/src/free/java/de/danoeh/antennapod/activity/CastEnabledActivity.java
index 79d7e02f2..aff1d6ea4 100644
--- a/app/src/free/java/de/danoeh/antennapod/activity/CastEnabledActivity.java
+++ b/app/src/free/java/de/danoeh/antennapod/activity/CastEnabledActivity.java
@@ -1,218 +1,15 @@
package de.danoeh.antennapod.activity;
-import android.support.v7.app.AppCompatActivity;
+import androidx.appcompat.app.AppCompatActivity;
/**
* Activity that allows for showing the MediaRouter button whenever there's a cast device in the
* network.
*/
public abstract class CastEnabledActivity extends AppCompatActivity {
-// implements SharedPreferences.OnSharedPreferenceChangeListener {
public static final String TAG = "CastEnabledActivity";
-// protected CastManager castManager;
-// protected SwitchableMediaRouteActionProvider mediaRouteActionProvider;
-// private final CastButtonVisibilityManager castButtonVisibilityManager = new CastButtonVisibilityManager();
-//
-// @Override
-// protected void onCreate(Bundle savedInstanceState) {
-// super.onCreate(savedInstanceState);
-//
-// PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).
-// registerOnSharedPreferenceChangeListener(this);
-//
-// castManager = CastManager.getInstance();
-// castManager.addCastConsumer(castConsumer);
-// castButtonVisibilityManager.setPrefEnabled(UserPreferences.isCastEnabled());
-// onCastConnectionChanged(castManager.isConnected());
-// }
-//
-// @Override
-// protected void onDestroy() {
-// PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
-// .unregisterOnSharedPreferenceChangeListener(this);
-// castManager.removeCastConsumer(castConsumer);
-// super.onDestroy();
-// }
-//
-// @Override
-// @CallSuper
-// public boolean onCreateOptionsMenu(Menu menu) {
-// super.onCreateOptionsMenu(menu);
-// getMenuInflater().inflate(R.menu.cast_enabled, menu);
-// castButtonVisibilityManager.setMenu(menu);
-// return true;
-// }
-//
-// @Override
-// @CallSuper
-// public boolean onPrepareOptionsMenu(Menu menu) {
-// super.onPrepareOptionsMenu(menu);
-// mediaRouteActionProvider = castManager
-// .addMediaRouterButton(menu.findItem(R.id.media_route_menu_item));
-// mediaRouteActionProvider.setEnabled(castButtonVisibilityManager.shouldEnable());
-// return true;
-// }
-//
-// @Override
-// protected void onResume() {
-// super.onResume();
-// castButtonVisibilityManager.setResumed(true);
-// }
-//
-// @Override
-// protected void onPause() {
-// super.onPause();
-// castButtonVisibilityManager.setResumed(false);
-// }
-//
-// @Override
-// public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
-// if (UserPreferences.PREF_CAST_ENABLED.equals(key)) {
-// boolean newValue = UserPreferences.isCastEnabled();
-// Log.d(TAG, "onSharedPreferenceChanged(), isCastEnabled set to " + newValue);
-// castButtonVisibilityManager.setPrefEnabled(newValue);
-// // PlaybackService has its own listener, so if it's active we don't have to take action here.
-// if (!newValue && !PlaybackService.isRunning) {
-// CastManager.getInstance().disconnect();
-// }
-// }
-// }
-//
-// CastConsumer castConsumer = new DefaultCastConsumer() {
-// @Override
-// public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) {
-// onCastConnectionChanged(true);
-// }
-//
-// @Override
-// public void onDisconnected() {
-// onCastConnectionChanged(false);
-// }
-// };
-//
-// private void onCastConnectionChanged(boolean connected) {
-// if (connected) {
-// castButtonVisibilityManager.onConnected();
-// setVolumeControlStream(AudioManager.USE_DEFAULT_STREAM_TYPE);
-// } else {
-// castButtonVisibilityManager.onDisconnected();
-// setVolumeControlStream(AudioManager.STREAM_MUSIC);
-// }
-// }
-//
-// /**
-// * Should be called by any activity or fragment for which the cast button should be shown.
-// *
-// * @param showAsAction refer to {@link MenuItem#setShowAsAction(int)}
-// */
public final void requestCastButton(int showAsAction) {
// no-op
}
-
-// private class CastButtonVisibilityManager {
-// private volatile boolean prefEnabled = false;
-// private volatile boolean viewRequested = false;
-// private volatile boolean resumed = false;
-// private volatile boolean connected = false;
-// private volatile int showAsAction = MenuItem.SHOW_AS_ACTION_IF_ROOM;
-// private Menu menu;
-//
-// public synchronized void setPrefEnabled(boolean newValue) {
-// if (prefEnabled != newValue && resumed && (viewRequested || connected)) {
-// if (newValue) {
-// castManager.incrementUiCounter();
-// } else {
-// castManager.decrementUiCounter();
-// }
-// }
-// prefEnabled = newValue;
-// if (mediaRouteActionProvider != null) {
-// mediaRouteActionProvider.setEnabled(prefEnabled && (viewRequested || connected));
-// }
-// }
-//
-// public synchronized void setResumed(boolean newValue) {
-// if (resumed == newValue) {
-// Log.e(TAG, "resumed should never change to the same value");
-// return;
-// }
-// resumed = newValue;
-// if (prefEnabled && (viewRequested || connected)) {
-// if (resumed) {
-// castManager.incrementUiCounter();
-// } else {
-// castManager.decrementUiCounter();
-// }
-// }
-// }
-//
-// public synchronized void setViewRequested(boolean newValue) {
-// if (viewRequested != newValue && resumed && prefEnabled && !connected) {
-// if (newValue) {
-// castManager.incrementUiCounter();
-// } else {
-// castManager.decrementUiCounter();
-// }
-// }
-// viewRequested = newValue;
-// if (mediaRouteActionProvider != null) {
-// mediaRouteActionProvider.setEnabled(prefEnabled && (viewRequested || connected));
-// }
-// }
-//
-// public synchronized void setConnected(boolean newValue) {
-// if (connected != newValue && resumed && prefEnabled && !prefEnabled) {
-// if (newValue) {
-// castManager.incrementUiCounter();
-// } else {
-// castManager.decrementUiCounter();
-// }
-// }
-// connected = newValue;
-// if (mediaRouteActionProvider != null) {
-// mediaRouteActionProvider.setEnabled(prefEnabled && (viewRequested || connected));
-// }
-// }
-//
-// public synchronized boolean shouldEnable() {
-// return prefEnabled && viewRequested;
-// }
-//
-// public void setMenu(Menu menu) {
-// setViewRequested(false);
-// showAsAction = MenuItem.SHOW_AS_ACTION_IF_ROOM;
-// this.menu = menu;
-// setShowAsAction();
-// }
-//
-// public void requestCastButton(int showAsAction) {
-// setViewRequested(true);
-// this.showAsAction = showAsAction;
-// setShowAsAction();
-// }
-//
-// public void onConnected() {
-// setConnected(true);
-// setShowAsAction();
-// }
-//
-// public void onDisconnected() {
-// setConnected(false);
-// setShowAsAction();
-// }
-//
-// private void setShowAsAction() {
-// if (menu == null) {
-// Log.d(TAG, "setShowAsAction() without a menu");
-// return;
-// }
-// MenuItem item = menu.findItem(R.id.media_route_menu_item);
-// if (item == null) {
-// Log.e(TAG, "setShowAsAction(), but cast button not inflated");
-// return;
-// }
-// MenuItemCompat.setShowAsAction(item, connected? MenuItem.SHOW_AS_ACTION_ALWAYS : showAsAction);
-// }
-// }
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 73af654e9..488d4e473 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -36,7 +36,7 @@
android:usesCleartextTraffic="true"
android:logo="@mipmap/ic_launcher">
<meta-data android:name="com.google.android.gms.car.notification.SmallIcon"
- android:resource="@drawable/ic_notification" />
+ android:resource="@drawable/ic_antenna" />
<meta-data
android:name="com.google.android.backup.api_key"
android:value="AEdPqrEAAAAI3a05VToCTlqBymJrbFGaKQMvF-bBAuLsOdavBA"/>
@@ -105,17 +105,6 @@
android:value="de.danoeh.antennapod.activity.MainActivity"/>
</activity>
- <activity
- android:name=".activity.FeedInfoActivity"
- android:label="@string/feed_info_label">
- </activity>
-
- <activity
- android:name=".activity.FeedSettingsActivity"
- android:windowSoftInputMode="stateHidden"
- android:label="@string/feed_settings_label">
- </activity>
-
<service
android:name=".core.service.PlayerWidgetJobService"
android:permission="android.permission.BIND_JOB_SERVICE"
@@ -151,13 +140,6 @@
android:value="de.danoeh.antennapod.activity.PreferenceActivity"/>
</activity>
<activity
- android:name=".activity.StatisticsActivity"
- android:label="@string/statistics_label">
- <meta-data
- android:name="android.support.PARENT_ACTIVITY"
- android:value="de.danoeh.antennapod.activity.PreferenceActivity"/>
- </activity>
- <activity
android:name=".activity.ImportExportActivity"
android:label="@string/import_export">
<meta-data
@@ -209,6 +191,13 @@
android:name=".activity.OpmlFeedChooserActivity"
android:label="@string/opml_import_label">
</activity>
+ <activity
+ android:name=".activity.BugReportActivity"
+ android:label="@string/bug_report_title">
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value="de.danoeh.antennapod.activity.PreferenceActivity"/>
+ </activity>
<activity
android:name=".activity.VideoplayerActivity"
@@ -350,7 +339,7 @@
<provider
android:authorities="@string/provider_authority"
- android:name="android.support.v4.content.FileProvider"
+ android:name="androidx.core.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
diff --git a/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java b/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java
index ea2166674..061ea9ae2 100644
--- a/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java
+++ b/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java
@@ -9,6 +9,9 @@ import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -32,13 +35,7 @@ public class CrashReportWriter implements Thread.UncaughtExceptionHandler {
PrintWriter out = null;
try {
out = new PrintWriter(new FileWriter(path));
- out.println("[ Environment ]");
- out.println("Android version: " + Build.VERSION.RELEASE);
- out.println("OS version: " + System.getProperty("os.version"));
- out.println("AntennaPod version: " + BuildConfig.VERSION_NAME);
- out.println("Model: " + Build.MODEL);
- out.println("Device: " + Build.DEVICE);
- out.println("Product: " + Build.PRODUCT);
+ out.println(getSystemInfo());
out.println();
out.println("[ StackTrace ]");
ex.printStackTrace(out);
@@ -49,4 +46,15 @@ public class CrashReportWriter implements Thread.UncaughtExceptionHandler {
}
defaultHandler.uncaughtException(thread, ex);
}
+
+ public static String getSystemInfo() {
+ return "[ Environment ]" +
+ "\nAndroid version: " + Build.VERSION.RELEASE +
+ "\nOS version: " + System.getProperty("os.version") +
+ "\nAntennaPod version: " + BuildConfig.VERSION_NAME +
+ "\nModel: " + Build.MODEL +
+ "\nDevice: " + Build.DEVICE +
+ "\nProduct: " + Build.PRODUCT +
+ "\nTime: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date()) + "\n";
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
index cb2f597d6..94d281a45 100644
--- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
+++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
@@ -63,6 +63,8 @@ public class PodcastApp extends Application {
EventBus.builder()
.addIndex(new ApEventBusIndex())
.addIndex(new ApCoreEventBusIndex())
+ .logNoSubscriberMessages(false)
+ .sendNoSubscriberEvent(false)
.installDefaultEventBus();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java
index 1bcdada44..ef7ea2b16 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java
@@ -1,12 +1,10 @@
package de.danoeh.antennapod.activity;
-import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Color;
-import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
@@ -15,6 +13,7 @@ import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.LinearLayout;
+import de.danoeh.antennapod.core.util.IntentUtils;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
@@ -57,8 +56,7 @@ public class AboutActivity extends AppCompatActivity {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("http")) {
- Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- startActivity(browserIntent);
+ IntentUtils.openInBrowser(AboutActivity.this, url);
return true;
} else {
url = url.replace("file:///android_asset/", "");
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 8e063374a..7c26cc484 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.activity;
import android.content.Intent;
-import android.support.v4.view.ViewCompat;
+import androidx.core.view.ViewCompat;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@@ -62,11 +62,13 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
}
if (controller == null) {
butPlaybackSpeed.setVisibility(View.GONE);
+ txtvPlaybackSpeed.setVisibility(View.GONE);
return;
}
updatePlaybackSpeedButtonText();
ViewCompat.setAlpha(butPlaybackSpeed, controller.canSetPlaybackSpeed() ? 1.0f : 0.5f);
butPlaybackSpeed.setVisibility(View.VISIBLE);
+ txtvPlaybackSpeed.setVisibility(View.VISIBLE);
}
@Override
@@ -76,14 +78,15 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
}
if (controller == null) {
butPlaybackSpeed.setVisibility(View.GONE);
+ txtvPlaybackSpeed.setVisibility(View.GONE);
return;
}
float speed = 1.0f;
if(controller.canSetPlaybackSpeed()) {
speed = UserPreferences.getPlaybackSpeed(controller.getMedia());
}
- String speedStr = new DecimalFormat("0.00x").format(speed);
- butPlaybackSpeed.setText(speedStr);
+ String speedStr = new DecimalFormat("0.00").format(speed);
+ txtvPlaybackSpeed.setText(speedStr);
}
@Override
@@ -142,6 +145,7 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
return true;
});
butPlaybackSpeed.setVisibility(View.VISIBLE);
+ txtvPlaybackSpeed.setVisibility(View.VISIBLE);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java
new file mode 100644
index 000000000..666eacfa8
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java
@@ -0,0 +1,55 @@
+package de.danoeh.antennapod.activity;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.os.Bundle;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.appcompat.app.AppCompatActivity;
+import android.widget.TextView;
+import de.danoeh.antennapod.CrashReportWriter;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.IntentUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+/**
+ * Displays the 'crash report' screen
+ */
+public class BugReportActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ setTheme(UserPreferences.getTheme());
+ super.onCreate(savedInstanceState);
+ getSupportActionBar().setDisplayShowHomeEnabled(true);
+ setContentView(R.layout.bug_report);
+
+ TextView crashDetailsText = findViewById(R.id.crash_report_logs);
+
+ try {
+ File crashFile = CrashReportWriter.getFile();
+ String crashReportContent = IOUtils.toString(new FileInputStream(crashFile), Charset.forName("UTF-8"));
+ crashDetailsText.setText(crashReportContent);
+ } catch (IOException e) {
+ e.printStackTrace();
+ crashDetailsText.setText("No crash report recorded\n" + CrashReportWriter.getSystemInfo());
+ }
+
+ findViewById(R.id.btn_open_bug_tracker).setOnClickListener(v -> {
+ IntentUtils.openInBrowser(BugReportActivity.this, "https://github.com/AntennaPod/AntennaPod/issues");
+ });
+
+ findViewById(R.id.btn_copy_log).setOnClickListener(v -> {
+ ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText(getString(R.string.bug_report_title), crashDetailsText.getText());
+ clipboard.setPrimaryClip(clip);
+ Snackbar.make(findViewById(android.R.id.content), R.string.copied_to_clipboard, Snackbar.LENGTH_SHORT).show();
+ });
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java
index 871e9c279..c60c7b769 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java
@@ -49,6 +49,7 @@ public class CastplayerActivity extends MediaplayerInfoActivity {
super.setupGUI();
if (butPlaybackSpeed != null) {
butPlaybackSpeed.setVisibility(View.GONE);
+ txtvPlaybackSpeed.setVisibility(View.GONE);
}
// if (butCastDisconnect != null) {
// butCastDisconnect.setOnClickListener(v -> castManager.disconnect());
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
index 33def125e..49ce954bc 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
@@ -5,9 +5,9 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.FileObserver;
-import android.support.v4.app.NavUtils;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
+import androidx.core.app.NavUtils;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java
index 5e04d743d..08ebc6421 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java
@@ -3,8 +3,8 @@ package de.danoeh.antennapod.activity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
deleted file mode 100644
index 26e360bd3..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
+++ /dev/null
@@ -1,225 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.content.ClipData;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.LightingColorFilter;
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.bumptech.glide.Glide;
-import com.bumptech.glide.request.RequestOptions;
-import com.joanzapata.iconify.Iconify;
-
-import org.apache.commons.lang3.StringUtils;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.glide.ApGlideSettings;
-import de.danoeh.antennapod.core.glide.FastBlurTransformation;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DownloadRequestException;
-import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.core.util.LangUtils;
-import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText;
-import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
-import io.reactivex.Maybe;
-import io.reactivex.MaybeOnSubscribe;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.disposables.Disposable;
-import io.reactivex.schedulers.Schedulers;
-
-/**
- * Displays information about a feed.
- */
-public class FeedInfoActivity extends AppCompatActivity {
-
- public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
- private static final String TAG = "FeedInfoActivity";
- private Feed feed;
-
- private ImageView imgvCover;
- private TextView txtvTitle;
- private TextView txtvDescription;
- private TextView lblLanguage;
- private TextView txtvLanguage;
- private TextView lblAuthor;
- private TextView txtvAuthor;
- private TextView txtvUrl;
-
- private Disposable disposable;
-
-
- private final View.OnClickListener copyUrlToClipboard = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if(feed != null && feed.getDownload_url() != null) {
- String url = feed.getDownload_url();
- ClipData clipData = ClipData.newPlainText(url, url);
- android.content.ClipboardManager cm = (android.content.ClipboardManager) FeedInfoActivity.this
- .getSystemService(Context.CLIPBOARD_SERVICE);
- cm.setPrimaryClip(clipData);
- Toast t = Toast.makeText(FeedInfoActivity.this, R.string.copied_url_msg, Toast.LENGTH_SHORT);
- t.show();
- }
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- setContentView(R.layout.feedinfo);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- long feedId = getIntent().getLongExtra(EXTRA_FEED_ID, -1);
-
- imgvCover = findViewById(R.id.imgvCover);
- txtvTitle = findViewById(R.id.txtvTitle);
- TextView txtvAuthorHeader = findViewById(R.id.txtvAuthor);
- ImageView imgvBackground = findViewById(R.id.imgvBackground);
- findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE);
- findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE);
- // https://github.com/bumptech/glide/issues/529
- imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
-
-
- txtvDescription = findViewById(R.id.txtvDescription);
- lblLanguage = findViewById(R.id.lblLanguage);
- txtvLanguage = findViewById(R.id.txtvLanguage);
- lblAuthor = findViewById(R.id.lblAuthor);
- txtvAuthor = findViewById(R.id.txtvDetailsAuthor);
- txtvUrl = findViewById(R.id.txtvUrl);
-
- txtvUrl.setOnClickListener(copyUrlToClipboard);
-
- disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
- Feed feed = DBReader.getFeed(feedId);
- if (feed != null) {
- emitter.onSuccess(feed);
- } else {
- emitter.onComplete();
- }
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> {
- feed = result;
- Log.d(TAG, "Language is " + feed.getLanguage());
- Log.d(TAG, "Author is " + feed.getAuthor());
- Log.d(TAG, "URL is " + feed.getDownload_url());
- Glide.with(FeedInfoActivity.this)
- .load(feed.getImageLocation())
- .apply(new RequestOptions()
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate())
- .into(imgvCover);
- Glide.with(FeedInfoActivity.this)
- .load(feed.getImageLocation())
- .apply(new RequestOptions()
- .placeholder(R.color.image_readability_tint)
- .error(R.color.image_readability_tint)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .transform(new FastBlurTransformation())
- .dontAnimate())
- .into(imgvBackground);
-
- txtvTitle.setText(feed.getTitle());
-
- String description = feed.getDescription();
- if(description != null) {
- if(Feed.TYPE_ATOM1.equals(feed.getType())) {
- HtmlToPlainText formatter = new HtmlToPlainText();
- Document feedDescription = Jsoup.parse(feed.getDescription());
- description = StringUtils.trim(formatter.getPlainText(feedDescription));
- }
- } else {
- description = "";
- }
- txtvDescription.setText(description);
-
- if (!TextUtils.isEmpty(feed.getAuthor())) {
- txtvAuthor.setText(feed.getAuthor());
- txtvAuthorHeader.setText(feed.getAuthor());
- } else {
- lblAuthor.setVisibility(View.GONE);
- txtvAuthor.setVisibility(View.GONE);
- }
- if (!TextUtils.isEmpty(feed.getLanguage())) {
- txtvLanguage.setText(LangUtils.getLanguageString(feed.getLanguage()));
- } else {
- lblLanguage.setVisibility(View.GONE);
- txtvLanguage.setVisibility(View.GONE);
- }
- txtvUrl.setText(feed.getDownload_url() + " {fa-paperclip}");
- Iconify.addIcons(txtvUrl);
-
- supportInvalidateOptionsMenu();
- }, error -> {
- Log.d(TAG, Log.getStackTraceString(error));
- finish();
- }, () -> {
- Log.e(TAG, "Activity was started with invalid arguments");
- finish();
- });
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- if (disposable != null) {
- disposable.dispose();
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.feedinfo, menu);
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- menu.findItem(R.id.share_link_item).setVisible(feed != null && feed.getLink() != null);
- menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null &&
- IntentUtils.isCallable(this, new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink()))));
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- default:
- try {
- return FeedMenuHandler.onOptionsItemClicked(this, item, feed);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(this,
- e.getMessage());
- }
- return super.onOptionsItemSelected(item);
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java
deleted file mode 100644
index fbd19f88a..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.arch.lifecycle.ViewModelProviders;
-import android.graphics.LightingColorFilter;
-import android.os.Bundle;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v7.app.AppCompatActivity;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-import com.bumptech.glide.Glide;
-import com.bumptech.glide.request.RequestOptions;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.glide.ApGlideSettings;
-import de.danoeh.antennapod.core.glide.FastBlurTransformation;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.fragment.FeedSettingsFragment;
-import de.danoeh.antennapod.viewmodel.FeedSettingsViewModel;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.disposables.Disposable;
-import io.reactivex.schedulers.Schedulers;
-
-/**
- * Displays information about a feed.
- */
-public class FeedSettingsActivity extends AppCompatActivity {
- public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
- private static final String TAG = "FeedSettingsActivity";
- private Feed feed;
- private Disposable disposable;
- private ImageView imgvCover;
- private TextView txtvTitle;
- private ImageView imgvBackground;
- private TextView txtvAuthorHeader;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- setContentView(R.layout.feedsettings);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- imgvCover = findViewById(R.id.imgvCover);
- txtvTitle = findViewById(R.id.txtvTitle);
- txtvAuthorHeader = findViewById(R.id.txtvAuthor);
- imgvBackground = findViewById(R.id.imgvBackground);
- findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE);
- findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE);
- // https://github.com/bumptech/glide/issues/529
- imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
-
- long feedId = getIntent().getLongExtra(EXTRA_FEED_ID, -1);
- disposable = ViewModelProviders.of(this).get(FeedSettingsViewModel.class).getFeed(feedId)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> {
- feed = result;
- showFragment();
- showHeader();
- }, error -> {
- Log.d(TAG, Log.getStackTraceString(error));
- finish();
- }, () -> {
- Log.e(TAG, "Activity was started with invalid arguments");
- finish();
- });
- }
-
- private void showFragment() {
- FeedSettingsFragment fragment = new FeedSettingsFragment();
- fragment.setArguments(getIntent().getExtras());
-
- FragmentManager fragmentManager = getSupportFragmentManager();
- FragmentTransaction fragmentTransaction =
- fragmentManager.beginTransaction();
- fragmentTransaction.replace(R.id.settings_fragment_container, fragment);
- fragmentTransaction.commit();
- }
-
- private void showHeader() {
- txtvTitle.setText(feed.getTitle());
-
- if (!TextUtils.isEmpty(feed.getAuthor())) {
- txtvAuthorHeader.setText(feed.getAuthor());
- }
-
- Glide.with(FeedSettingsActivity.this)
- .load(feed.getImageLocation())
- .apply(new RequestOptions()
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate())
- .into(imgvCover);
- Glide.with(FeedSettingsActivity.this)
- .load(feed.getImageLocation())
- .apply(new RequestOptions()
- .placeholder(R.color.image_readability_tint)
- .error(R.color.image_readability_tint)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .transform(new FastBlurTransformation())
- .dontAnimate())
- .into(imgvBackground);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- if (disposable != null) {
- disposable.dispose();
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java
index 9795c1240..f85a1cd77 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java
@@ -7,10 +7,10 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
-import android.support.design.widget.Snackbar;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
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 339ce01c2..6a38f8f0a 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -2,6 +2,7 @@ package de.danoeh.antennapod.activity;
import android.annotation.TargetApi;
import android.app.ProgressDialog;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -10,15 +11,16 @@ import android.database.DataSetObserver;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.support.annotation.VisibleForTesting;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.widget.DrawerLayout;
-import android.support.v7.app.ActionBarDrawerToggle;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.Toolbar;
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
+import androidx.drawerlayout.widget.DrawerLayout;
+import androidx.appcompat.app.ActionBarDrawerToggle;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.widget.Toolbar;
import android.util.Log;
import android.util.TypedValue;
import android.view.ContextMenu;
@@ -32,9 +34,11 @@ import android.widget.Toast;
import com.bumptech.glide.Glide;
-import de.danoeh.antennapod.preferences.PreferenceUpgrader;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.Validate;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
@@ -43,7 +47,6 @@ import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.MessageEvent;
-import de.danoeh.antennapod.core.event.ProgressEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
@@ -66,14 +69,13 @@ import de.danoeh.antennapod.fragment.FeedItemlistFragment;
import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
import de.danoeh.antennapod.fragment.QueueFragment;
import de.danoeh.antennapod.fragment.SubscriptionFragment;
+import de.danoeh.antennapod.fragment.TransitionEffect;
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
+import de.danoeh.antennapod.preferences.PreferenceUpgrader;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
/**
* The activity that is shown when the user launches the app.
@@ -93,7 +95,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
public static final String EXTRA_NAV_INDEX = "nav_index";
public static final String EXTRA_FRAGMENT_TAG = "fragment_tag";
public static final String EXTRA_FRAGMENT_ARGS = "fragment_args";
- public static final String EXTRA_FEED_ID = "fragment_feed_id";
+ private static final String EXTRA_FEED_ID = "fragment_feed_id";
private static final String SAVE_BACKSTACK_COUNT = "backstackCount";
private static final String SAVE_TITLE = "title";
@@ -127,6 +129,14 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
private long lastBackButtonPressTime = 0;
+ @NonNull
+ public static Intent getIntentToOpenFeed(@NonNull Context context, long feedId) {
+ Intent intent = new Intent(context.getApplicationContext(), MainActivity.class);
+ intent.putExtra(MainActivity.EXTRA_FEED_ID, feedId);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ return intent;
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(UserPreferences.getNoTitleTheme());
@@ -240,7 +250,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(PREF_IS_FIRST_LAUNCH, false);
- edit.commit();
+ edit.apply();
}
}
@@ -368,15 +378,34 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
}
}
- public void loadChildFragment(Fragment fragment) {
+ public void loadChildFragment(Fragment fragment, TransitionEffect transition) {
Validate.notNull(fragment);
- FragmentManager fm = getSupportFragmentManager();
- fm.beginTransaction()
- .replace(R.id.main_view, fragment, "main")
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+
+ switch (transition) {
+ case FADE:
+ transaction.setCustomAnimations(R.anim.fade_in, R.anim.fade_out);
+ break;
+ case FLIP:
+ transaction.setCustomAnimations(
+ R.anim.card_flip_left_in,
+ R.anim.card_flip_left_out,
+ R.anim.card_flip_right_in,
+ R.anim.card_flip_right_out);
+ break;
+ }
+
+ transaction
+ .hide(getSupportFragmentManager().findFragmentByTag("main"))
+ .add(R.id.main_view, fragment, "main")
.addToBackStack(null)
.commit();
}
+ public void loadChildFragment(Fragment fragment) {
+ loadChildFragment(fragment, TransitionEffect.NONE);
+ }
+
public void dismissChildFragment() {
getSupportFragmentManager().popBackStack();
}
@@ -778,25 +807,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
}
@Subscribe(threadMode = ThreadMode.MAIN)
- public void onEventMainThread(ProgressEvent event) {
- Log.d(TAG, "onEvent(" + event + ")");
- switch(event.action) {
- case START:
- pd = new ProgressDialog(this);
- pd.setMessage(event.message);
- pd.setIndeterminate(true);
- pd.setCancelable(false);
- pd.show();
- break;
- case END:
- if(pd != null) {
- pd.dismiss();
- }
- break;
- }
- }
-
- @Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(MessageEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
View parentLayout = findViewById(R.id.drawer_layout);
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 a907c738a..7bfdc6fc6 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -9,14 +9,13 @@ import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PixelFormat;
-import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.app.ActivityOptionsCompat;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.app.AlertDialog;
+import androidx.annotation.Nullable;
+import androidx.core.app.ActivityCompat;
+import androidx.core.app.ActivityOptionsCompat;
+import androidx.core.content.ContextCompat;
+import androidx.appcompat.app.AlertDialog;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@@ -34,6 +33,7 @@ import com.joanzapata.iconify.IconDrawable;
import com.joanzapata.iconify.fonts.FontAwesomeIcons;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
@@ -63,6 +63,9 @@ import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
import static de.danoeh.antennapod.core.feed.FeedPreferences.SPEED_USE_GLOBAL;
@@ -196,6 +199,11 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
};
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(PlaybackPositionEvent event) {
+ onPositionObserverUpdate();
+ }
+
private static TextView getTxtvFFFromActivity(MediaplayerActivity activity) {
return activity.txtvFF;
}
@@ -276,6 +284,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
controller.init();
loadMediaInfo();
onPositionObserverUpdate();
+ EventBus.getDefault().register(this);
}
@Override
@@ -288,6 +297,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
if (disposable != null) {
disposable.dispose();
}
+ EventBus.getDefault().unregister(this);
super.onStop();
}
@@ -324,6 +334,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
Playable media = controller.getMedia();
boolean isFeedMedia = media != null && (media instanceof FeedMedia);
+ menu.findItem(R.id.open_feed_item).setVisible(isFeedMedia); // FeedMedia implies it belongs to a Feed
+
boolean hasWebsiteLink = ( getWebsiteLinkWithFallback(media) != null );
menu.findItem(R.id.visit_website_item).setVisible(hasWebsiteLink);
@@ -391,29 +403,24 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
return true;
} else {
if (media != null) {
+ final @Nullable FeedItem feedItem = getFeedItem(media); // some options option requires FeedItem
switch (item.getItemId()) {
case R.id.add_to_favorites_item:
- if(media instanceof FeedMedia) {
- FeedItem feedItem = ((FeedMedia)media).getItem();
- if(feedItem != null) {
- DBWriter.addFavoriteItem(feedItem);
- isFavorite = true;
- invalidateOptionsMenu();
- Toast.makeText(this, R.string.added_to_favorites, Toast.LENGTH_SHORT)
- .show();
- }
+ if (feedItem != null) {
+ DBWriter.addFavoriteItem(feedItem);
+ isFavorite = true;
+ invalidateOptionsMenu();
+ Toast.makeText(this, R.string.added_to_favorites, Toast.LENGTH_SHORT)
+ .show();
}
break;
case R.id.remove_from_favorites_item:
- if(media instanceof FeedMedia) {
- FeedItem feedItem = ((FeedMedia)media).getItem();
- if(feedItem != null) {
- DBWriter.removeFavoriteItem(feedItem);
- isFavorite = false;
- invalidateOptionsMenu();
- Toast.makeText(this, R.string.removed_from_favorites, Toast.LENGTH_SHORT)
- .show();
- }
+ if (feedItem != null) {
+ DBWriter.removeFavoriteItem(feedItem);
+ isFavorite = false;
+ invalidateOptionsMenu();
+ Toast.makeText(this, R.string.removed_from_favorites, Toast.LENGTH_SHORT)
+ .show();
}
break;
case R.id.disable_sleeptimer_item:
@@ -450,28 +457,33 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance(isPlayingVideo);
dialog.show(getSupportFragmentManager(), "playback_controls");
break;
+ case R.id.open_feed_item:
+ if (feedItem != null) {
+ Intent intent = MainActivity.getIntentToOpenFeed(this, feedItem.getFeedId());
+ startActivity(intent);
+ }
+ break;
case R.id.visit_website_item:
- Uri uri = Uri.parse(getWebsiteLinkWithFallback(media));
- startActivity(new Intent(Intent.ACTION_VIEW, uri));
+ IntentUtils.openInBrowser(MediaplayerActivity.this, getWebsiteLinkWithFallback(media));
break;
case R.id.share_link_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem());
+ if (feedItem != null) {
+ ShareUtils.shareFeedItemLink(this, feedItem);
}
break;
case R.id.share_download_url_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem());
+ if (feedItem != null) {
+ ShareUtils.shareFeedItemDownloadLink(this, feedItem);
}
break;
case R.id.share_link_with_position_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem(), true);
+ if (feedItem != null) {
+ ShareUtils.shareFeedItemLink(this, feedItem, true);
}
break;
case R.id.share_download_url_with_position_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem(), true);
+ if (feedItem != null) {
+ ShareUtils.shareFeedItemDownloadLink(this, feedItem, true);
}
break;
case R.id.share_file:
@@ -637,7 +649,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
}
}
- static public void showSkipPreference(Activity activity, SkipDirection direction) {
+ public static void showSkipPreference(Activity activity, SkipDirection direction) {
int checked = 0;
int skipSecs = direction.getPrefSkipSeconds();
final int[] values = activity.getResources().getIntArray(R.array.seek_delta_values);
@@ -815,11 +827,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
}
private void checkFavorite() {
- Playable playable = controller.getMedia();
- if (!(playable instanceof FeedMedia)) {
- return;
- }
- FeedItem feedItem = ((FeedMedia) playable).getItem();
+ FeedItem feedItem = getFeedItem(controller.getMedia());
if (feedItem == null) {
return;
}
@@ -874,4 +882,13 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
}
}
}
+
+ @Nullable
+ private static FeedItem getFeedItem(@Nullable Playable playable) {
+ if ((playable != null) && (playable instanceof FeedMedia)) {
+ return ((FeedMedia)playable).getItem();
+ } else {
+ return null;
+ }
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
index 4fec1cfc5..016168b45 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
@@ -7,15 +7,15 @@ import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
-import android.support.design.widget.AppBarLayout;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.support.v4.widget.DrawerLayout;
-import android.support.v7.app.ActionBarDrawerToggle;
-import android.support.v7.widget.Toolbar;
+import com.google.android.material.appbar.AppBarLayout;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+import androidx.drawerlayout.widget.DrawerLayout;
+import androidx.appcompat.app.ActionBarDrawerToggle;
+import androidx.appcompat.widget.Toolbar;
import android.util.Log;
import android.util.TypedValue;
import android.view.ContextMenu;
@@ -23,9 +23,9 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
-import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ListView;
+import android.widget.TextView;
import android.widget.Toast;
import com.viewpagerindicator.CirclePageIndicator;
@@ -63,7 +63,6 @@ import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
@@ -92,7 +91,8 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
NavListAdapter.SUBSCRIPTION_LIST_TAG
};
- Button butPlaybackSpeed;
+ ImageButton butPlaybackSpeed;
+ TextView txtvPlaybackSpeed;
ImageButton butCastDisconnect;
private DrawerLayout drawerLayout;
private NavListAdapter navAdapter;
@@ -120,7 +120,6 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
disposable.dispose();
}
EventDistributor.getInstance().unregister(contentUpdate);
- EventBus.getDefault().unregister(this);
saveCurrentFragment();
}
@@ -173,7 +172,6 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
protected void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
- EventBus.getDefault().register(this);
loadData();
}
@@ -258,6 +256,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
});
butPlaybackSpeed = findViewById(R.id.butPlaybackSpeed);
+ txtvPlaybackSpeed = findViewById(R.id.txtvPlaybackSpeed);
butCastDisconnect = findViewById(R.id.butCastDisconnect);
pager = findViewById(R.id.pager);
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
index ea7687bc9..39715495a 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -7,12 +7,12 @@ import android.content.Intent;
import android.graphics.LightingColorFilter;
import android.os.Build;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.UiThread;
-import android.support.v4.app.NavUtils;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.NonNull;
+import androidx.annotation.UiThread;
+import androidx.core.app.NavUtils;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
@@ -32,7 +32,6 @@ import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
-import de.danoeh.antennapod.core.glide.FastBlurTransformation;
import org.apache.commons.lang3.StringUtils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
@@ -55,6 +54,7 @@ import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedPreferences;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
+import de.danoeh.antennapod.core.glide.FastBlurTransformation;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadRequest;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
@@ -442,11 +442,9 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
subscribeButton.setOnClickListener(v -> {
if(feedInFeedlist(feed)) {
- Intent intent = new Intent(OnlineFeedViewActivity.this, MainActivity.class);
// feed.getId() is always 0, we have to retrieve the id from the feed list from
// the database
- intent.putExtra(MainActivity.EXTRA_FEED_ID, getFeedId(feed));
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ Intent intent = MainActivity.getIntentToOpenFeed(this, getFeedId(feed));
startActivity(intent);
} else {
Feed f = new Feed(selectedDownloadUrl, null, feed.getTitle());
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
index 72759c59c..376074525 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.activity;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.SparseBooleanArray;
import android.view.Menu;
import android.view.MenuInflater;
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 c04ae051e..9caff0fc0 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
@@ -5,9 +5,9 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
-import android.support.annotation.Nullable;
-import android.support.v4.app.ActivityCompat;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.Nullable;
+import androidx.core.app.ActivityCompat;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import com.afollestad.materialdialogs.MaterialDialog;
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 7e0ae173f..a0f9bf6d8 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -1,9 +1,9 @@
package de.danoeh.antennapod.activity;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.preference.PreferenceFragmentCompat;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java
index 52102eee1..bd1ccaea4 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java
@@ -5,9 +5,9 @@ import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.Nullable;
+import androidx.core.graphics.drawable.DrawableCompat;
+import androidx.appcompat.app.AppCompatActivity;
import android.widget.ProgressBar;
import de.danoeh.antennapod.R;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
index 20e34cc52..c9c9a0e2c 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
@@ -9,9 +9,9 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
-import android.support.v4.app.ActivityCompat;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Button;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
index 78cc15b2c..2d28ea561 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
@@ -6,8 +6,8 @@ import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.support.v4.view.WindowCompat;
-import android.support.v7.app.ActionBar;
+import androidx.core.view.WindowCompat;
+import androidx.appcompat.app.ActionBar;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
index 2d7898d5b..c79c611ce 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
@@ -2,11 +2,10 @@ package de.danoeh.antennapod.activity.gpoddernet;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Configuration;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
index 2eff33339..5b735cd1f 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
@@ -1,10 +1,11 @@
package de.danoeh.antennapod.adapter;
import android.os.Build;
-import android.support.annotation.Nullable;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.ItemTouchHelper;
import android.text.Layout;
import android.util.Log;
import android.view.ContextMenu;
@@ -23,10 +24,12 @@ import android.widget.TextView;
import com.joanzapata.iconify.Iconify;
import java.lang.ref.WeakReference;
+import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.storage.DownloadRequester;
@@ -50,6 +53,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
private final boolean showOnlyNewEpisodes;
private FeedItem selectedItem;
+ private Holder currentlyPlayingItem = null;
private final int playingBackGroundColor;
private final int normalBackGroundColor;
@@ -165,8 +169,9 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.progress.setVisibility(View.INVISIBLE);
}
- if(media.isCurrentlyPlaying()) {
+ if (media.isCurrentlyPlaying()) {
holder.container.setBackgroundColor(playingBackGroundColor);
+ currentlyPlayingItem = holder;
} else {
holder.container.setBackgroundColor(normalBackGroundColor);
}
@@ -196,6 +201,22 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
.load();
}
+ @Override
+ public void onBindViewHolder(@NonNull Holder holder, int pos, List<Object> payload) {
+ onBindViewHolder(holder, pos);
+
+ if (holder == currentlyPlayingItem && payload.size() == 1 && payload.get(0) instanceof PlaybackPositionEvent) {
+ PlaybackPositionEvent event = (PlaybackPositionEvent) payload.get(0);
+ holder.progress.setProgress((int) (100.0 * event.getPosition() / event.getDuration()));
+ }
+ }
+
+ public void notifyCurrentlyPlayingItemChanged(PlaybackPositionEvent event) {
+ if (currentlyPlayingItem != null && currentlyPlayingItem.getAdapterPosition() != RecyclerView.NO_POSITION) {
+ notifyItemChanged(currentlyPlayingItem.getAdapterPosition(), event);
+ }
+ }
+
@Nullable
public FeedItem getSelectedItem() {
return selectedItem;
@@ -262,7 +283,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
FeedItem item = itemAccess.getItem(getAdapterPosition());
MenuInflater inflater = mainActivityRef.get().getMenuInflater();
- inflater.inflate(R.menu.allepisodes_context, menu);
+ inflater.inflate(R.menu.feeditemlist_context, menu);
if (item != null) {
menu.setHeaderTitle(item.getTitle());
@@ -277,9 +298,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
item1.setVisible(visible);
}
};
- FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, null);
-
- contextMenuInterface.setItemVisibility(R.id.remove_new_flag_item, item.isNew());
+ FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
index c3fac7e18..f6e6da8b4 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java b/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
index 33f925e3f..098e9a616 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
@@ -1,9 +1,8 @@
package de.danoeh.antennapod.adapter;
import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java
index 74bc84878..9014de525 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java
@@ -2,9 +2,9 @@ package de.danoeh.antennapod.adapter;
import android.app.Dialog;
import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.widget.RecyclerView;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
index 789c01a26..b8764c2ae 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.adapter;
import android.content.Context;
import android.os.Build;
-import android.support.v4.content.ContextCompat;
+import androidx.core.content.ContextCompat;
import android.text.Layout;
import android.text.format.DateUtils;
import android.util.Log;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
index d090bc4b1..aec0f0c91 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
@@ -3,7 +3,7 @@ package de.danoeh.antennapod.adapter;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
-import android.support.v4.content.ContextCompat;
+import androidx.core.content.ContextCompat;
import android.text.Layout;
import android.view.LayoutInflater;
import android.view.View;
@@ -13,15 +13,18 @@ import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
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.storage.DownloadRequester;
+import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.DateUtils;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.ThemeUtils;
@@ -39,6 +42,8 @@ public class FeedItemlistAdapter extends BaseAdapter {
private final int playingBackGroundColor;
private final int normalBackGroundColor;
+ private int currentlyPlayingItem = -1;
+
public FeedItemlistAdapter(Context context,
ItemAccess itemAccess,
boolean showFeedtitle,
@@ -176,8 +181,9 @@ public class FeedItemlistAdapter extends BaseAdapter {
}
typeDrawables.recycle();
- if(media.isCurrentlyPlaying()) {
+ if (media.isCurrentlyPlaying()) {
holder.container.setBackgroundColor(playingBackGroundColor);
+ currentlyPlayingItem = position;
} else {
holder.container.setBackgroundColor(normalBackGroundColor);
}
@@ -195,6 +201,20 @@ public class FeedItemlistAdapter extends BaseAdapter {
return convertView;
}
+ public void notifyCurrentlyPlayingItemChanged(PlaybackPositionEvent event, ListView listView) {
+ if (currentlyPlayingItem != -1 && currentlyPlayingItem < getCount()) {
+ View view = listView.getChildAt(currentlyPlayingItem
+ - listView.getFirstVisiblePosition() + listView.getHeaderViewsCount());
+ if (view == null) {
+ return;
+ }
+ Holder holder = (Holder) view.getTag();
+ holder.episodeProgress.setVisibility(View.VISIBLE);
+ holder.episodeProgress.setProgress((int) (100.0 * event.getPosition() / event.getDuration()));
+ holder.lenSize.setText(Converter.getDurationStringLong(event.getDuration() - event.getPosition()));
+ }
+ }
+
static class Holder {
LinearLayout container;
TextView title;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
index c10bb7638..8d469c7a6 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
+import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -51,6 +52,17 @@ public class FeedItemlistDescriptionAdapter extends ArrayAdapter<FeedItem> {
.replaceAll("\\s+", " ")
.trim();
holder.description.setText(description);
+
+ final int MAX_LINES_COLLAPSED = 3;
+ holder.description.setMaxLines(MAX_LINES_COLLAPSED);
+ holder.description.setOnClickListener(v -> {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
+ && holder.description.getMaxLines() > MAX_LINES_COLLAPSED) {
+ holder.description.setMaxLines(MAX_LINES_COLLAPSED);
+ } else {
+ holder.description.setMaxLines(2000);
+ }
+ });
}
return convertView;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
index be8e52cfc..50b11a15b 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -7,7 +7,7 @@ import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.preference.PreferenceManager;
-import android.support.v7.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
index 382abfb32..fcdcb4ba6 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
@@ -1,12 +1,12 @@
package de.danoeh.antennapod.adapter;
-import android.content.Context;
import android.os.Build;
-import android.support.annotation.Nullable;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+import androidx.core.view.MotionEventCompat;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.ItemTouchHelper;
import android.text.Layout;
import android.text.TextUtils;
import android.util.Log;
@@ -25,9 +25,11 @@ import android.widget.TextView;
import com.joanzapata.iconify.Iconify;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import org.apache.commons.lang3.ArrayUtils;
import java.lang.ref.WeakReference;
+import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
@@ -58,6 +60,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
private boolean locked;
private FeedItem selectedItem;
+ private ViewHolder currentlyPlayingItem = null;
private final int playingBackGroundColor;
private final int normalBackGroundColor;
@@ -94,6 +97,18 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
});
}
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int pos, List<Object> payload) {
+ onBindViewHolder(holder, pos);
+
+ if (holder == currentlyPlayingItem && payload.size() == 1 && payload.get(0) instanceof PlaybackPositionEvent) {
+ PlaybackPositionEvent event = (PlaybackPositionEvent) payload.get(0);
+ holder.progressBar.setProgress((int) (100.0 * event.getPosition() / event.getDuration()));
+ holder.progressLeft.setText(Converter.getDurationStringLong(event.getPosition()));
+ holder.progressRight.setText(Converter.getDurationStringLong(event.getDuration()));
+ }
+ }
+
@Nullable
public FeedItem getSelectedItem() {
return selectedItem;
@@ -109,6 +124,12 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
return itemAccess.getCount();
}
+ public void notifyCurrentlyPlayingItemChanged(PlaybackPositionEvent event) {
+ if (currentlyPlayingItem != null && currentlyPlayingItem.getAdapterPosition() != RecyclerView.NO_POSITION) {
+ notifyItemChanged(currentlyPlayingItem.getAdapterPosition(), event);
+ }
+ }
+
public class ViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener,
View.OnCreateContextMenuListener,
@@ -169,7 +190,8 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
FeedItem item = itemAccess.getItem(getAdapterPosition());
MenuInflater inflater = mainActivity.get().getMenuInflater();
- inflater.inflate(R.menu.queue_context, menu);
+ inflater.inflate(R.menu.queue_context, menu); // queue-specific menu items
+ inflater.inflate(R.menu.feeditemlist_context, menu); // generic menu items for item feeds
if (item != null) {
menu.setHeaderTitle(item.getTitle());
@@ -184,7 +206,18 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
item1.setVisible(visible);
}
};
- FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, itemAccess.getQueueIds());
+
+ FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item,
+ R.id.skip_episode_item); // Skip Episode is not useful in Queue, so hide it.
+ // Queue-specific menu preparation
+ final boolean keepSorted = UserPreferences.isQueueKeepSorted();
+ final LongList queueAccess = itemAccess.getQueueIds();
+ if (queueAccess.size() == 0 || queueAccess.get(0) == item.getId() || keepSorted) {
+ contextMenuInterface.setItemVisibility(R.id.move_to_top_item, false);
+ }
+ if (queueAccess.size() == 0 || queueAccess.get(queueAccess.size()-1) == item.getId() || keepSorted) {
+ contextMenuInterface.setItemVisibility(R.id.move_to_bottom_item, false);
+ }
}
@Override
@@ -276,6 +309,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
if(media.isCurrentlyPlaying()) {
container.setBackgroundColor(playingBackGroundColor);
+ currentlyPlayingItem = this;
} else {
container.setBackgroundColor(normalBackGroundColor);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java
index 31e82dbe0..f013f2a49 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java
@@ -1,31 +1,30 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
-
import com.bumptech.glide.Glide;
-
-import java.util.ArrayList;
-import java.util.List;
-
import com.bumptech.glide.request.RequestOptions;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.view.PieChartView;
/**
* Adapter for the statistics list
*/
-public class StatisticsListAdapter extends BaseAdapter {
+public class StatisticsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ private static final int TYPE_HEADER = 0;
+ private static final int TYPE_FEED = 1;
private final Context context;
- private List<DBReader.StatisticsItem> feedTime = new ArrayList<>();
+ private DBReader.StatisticsData statisticsData;
private boolean countAll = true;
public StatisticsListAdapter(Context context) {
@@ -37,66 +36,102 @@ public class StatisticsListAdapter extends BaseAdapter {
}
@Override
- public int getCount() {
- return feedTime.size();
+ public int getItemCount() {
+ return statisticsData.feedTime.size() + 1;
}
- @Override
public DBReader.StatisticsItem getItem(int position) {
- return feedTime.get(position);
+ if (position == 0) {
+ return null;
+ }
+ return statisticsData.feedTime.get(position - 1);
}
@Override
- public long getItemId(int position) {
- return feedTime.get(position).feed.getId();
+ public int getItemViewType(int position) {
+ return position == 0 ? TYPE_HEADER : TYPE_FEED;
}
+ @NonNull
@Override
- public View getView(int position, View convertView, ViewGroup parent) {
- StatisticsHolder holder;
- Feed feed = feedTime.get(position).feed;
-
- if (convertView == null) {
- holder = new StatisticsHolder();
- LayoutInflater inflater = (LayoutInflater) context
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- convertView = inflater.inflate(R.layout.statistics_listitem, parent, false);
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ LayoutInflater inflater = LayoutInflater.from(context);
+ if (viewType == TYPE_HEADER) {
+ return new HeaderHolder(inflater.inflate(R.layout.statistics_listitem_total_time, parent, false));
+ }
+ return new StatisticsHolder(inflater.inflate(R.layout.statistics_listitem, parent, false));
+ }
- holder.image = convertView.findViewById(R.id.imgvCover);
- holder.title = convertView.findViewById(R.id.txtvTitle);
- holder.time = convertView.findViewById(R.id.txtvTime);
- convertView.setTag(holder);
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder h, int position) {
+ if (getItemViewType(position) == TYPE_HEADER) {
+ HeaderHolder holder = (HeaderHolder) h;
+ long time = countAll ? statisticsData.totalTimeCountAll : statisticsData.totalTime;
+ holder.totalTime.setText(Converter.shortLocalizedDuration(context, time));
+ float[] dataValues = new float[statisticsData.feedTime.size()];
+ for (int i = 0; i < statisticsData.feedTime.size(); i++) {
+ DBReader.StatisticsItem item = statisticsData.feedTime.get(i);
+ dataValues[i] = countAll ? item.timePlayedCountAll : item.timePlayed;
+ }
+ holder.pieChart.setData(dataValues);
} else {
- holder = (StatisticsHolder) convertView.getTag();
+ StatisticsHolder holder = (StatisticsHolder) h;
+ DBReader.StatisticsItem statsItem = statisticsData.feedTime.get(position - 1);
+ Glide.with(context)
+ .load(statsItem.feed.getImageLocation())
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate())
+ .into(holder.image);
+
+ holder.title.setText(statsItem.feed.getTitle());
+ long time = countAll ? statsItem.timePlayedCountAll : statsItem.timePlayed;
+ holder.time.setText(Converter.shortLocalizedDuration(context, time));
+
+ holder.itemView.setOnClickListener(v -> {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(context);
+ dialog.setTitle(statsItem.feed.getTitle());
+ dialog.setMessage(context.getString(R.string.statistics_details_dialog,
+ countAll ? statsItem.episodesStartedIncludingMarked : statsItem.episodesStarted,
+ statsItem.episodes, Converter.shortLocalizedDuration(context,
+ countAll ? statsItem.timePlayedCountAll : statsItem.timePlayed),
+ Converter.shortLocalizedDuration(context, statsItem.time)));
+ dialog.setPositiveButton(android.R.string.ok, null);
+ dialog.show();
+ });
}
-
- Glide.with(context)
- .load(feed.getImageLocation())
- .apply(new RequestOptions()
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate())
- .into(holder.image);
-
- holder.title.setText(feed.getTitle());
- holder.time.setText(Converter.shortLocalizedDuration(context,
- countAll ? feedTime.get(position).timePlayedCountAll
- : feedTime.get(position).timePlayed));
- return convertView;
}
- public void update(List<DBReader.StatisticsItem> feedTime) {
- this.feedTime = feedTime;
+ public void update(DBReader.StatisticsData statistics) {
+ this.statisticsData = statistics;
notifyDataSetChanged();
}
- static class StatisticsHolder {
+ static class HeaderHolder extends RecyclerView.ViewHolder {
+ TextView totalTime;
+ PieChartView pieChart;
+
+ HeaderHolder(View itemView) {
+ super(itemView);
+ totalTime = itemView.findViewById(R.id.total_time);
+ pieChart = itemView.findViewById(R.id.pie_chart);
+ }
+ }
+
+ static class StatisticsHolder extends RecyclerView.ViewHolder {
ImageView image;
TextView title;
TextView time;
+
+ StatisticsHolder(View itemView) {
+ super(itemView);
+ image = itemView.findViewById(R.id.imgvCover);
+ title = itemView.findViewById(R.id.txtvTitle);
+ time = itemView.findViewById(R.id.txtvTime);
+ }
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java
index e0fb65c61..230b7ee31 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
-import android.support.v4.app.Fragment;
+import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java
index 3299db3ab..a8001eeb1 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.adapter.actionbutton;
import android.content.Context;
-import android.support.annotation.AttrRes;
-import android.support.annotation.StringRes;
+import androidx.annotation.AttrRes;
+import androidx.annotation.StringRes;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java
index 1275a799b..10458ed46 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.adapter.actionbutton;
import android.content.Context;
-import android.support.annotation.AttrRes;
-import android.support.annotation.StringRes;
+import androidx.annotation.AttrRes;
+import androidx.annotation.StringRes;
import android.widget.Toast;
import de.danoeh.antennapod.R;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java
index c1559528e..55ca5471b 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java
@@ -1,9 +1,9 @@
package de.danoeh.antennapod.adapter.actionbutton;
import android.content.Context;
-import android.support.annotation.AttrRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringRes;
+import androidx.annotation.AttrRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
import android.widget.Toast;
import de.danoeh.antennapod.R;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java
index da5ebf6e1..31e9fccb5 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java
@@ -2,9 +2,9 @@ package de.danoeh.antennapod.adapter.actionbutton;
import android.content.Context;
import android.content.res.TypedArray;
-import android.support.annotation.AttrRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringRes;
+import androidx.annotation.AttrRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
import android.view.View;
import android.widget.ImageButton;
@@ -20,12 +20,12 @@ public abstract class ItemActionButton {
}
@StringRes
- abstract public int getLabel();
+ public abstract int getLabel();
@AttrRes
- abstract public int getDrawable();
+ public abstract int getDrawable();
- abstract public void onClick(Context context);
+ public abstract void onClick(Context context);
public int getVisibility() {
return View.VISIBLE;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java
index 4d906cee5..354ded73d 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.adapter.actionbutton;
import android.content.Context;
-import android.support.annotation.AttrRes;
-import android.support.annotation.StringRes;
+import androidx.annotation.AttrRes;
+import androidx.annotation.StringRes;
import android.view.View;
import de.danoeh.antennapod.R;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java
index 3992c7240..23a7e03ad 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.adapter.actionbutton;
import android.content.Context;
-import android.support.annotation.AttrRes;
-import android.support.annotation.StringRes;
+import androidx.annotation.AttrRes;
+import androidx.annotation.StringRes;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
index f5213e4ab..cc3b6fba0 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.adapter.itunes;
import android.content.Context;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java
new file mode 100644
index 000000000..339a98dfa
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java
@@ -0,0 +1,72 @@
+package de.danoeh.antennapod.asynctask;
+
+import android.content.Context;
+import android.net.Uri;
+import androidx.annotation.NonNull;
+import androidx.documentfile.provider.DocumentFile;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+import de.danoeh.antennapod.core.export.ExportWriter;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.util.LangUtils;
+import io.reactivex.Observable;
+
+/**
+ * Writes an OPML file into the user selected export directory in the background.
+ */
+public class DocumentFileExportWorker {
+
+ private final @NonNull ExportWriter exportWriter;
+ private @NonNull Context context;
+ private @NonNull Uri outputFileUri;
+
+ public DocumentFileExportWorker(@NonNull ExportWriter exportWriter, @NonNull Context context, @NonNull Uri outputFileUri) {
+ this.exportWriter = exportWriter;
+ this.context = context;
+ this.outputFileUri = outputFileUri;
+ }
+
+ public Observable<DocumentFile> exportObservable() {
+ DocumentFile output = DocumentFile.fromSingleUri(context, outputFileUri);
+ return Observable.create(subscriber -> {
+ OutputStream outputStream = null;
+ OutputStreamWriter writer = null;
+ try {
+ Uri uri = output.getUri();
+ if (uri == null) {
+ throw new FileNotFoundException("Export file not found.");
+ }
+ outputStream = context.getContentResolver().openOutputStream(uri);
+ if (outputStream == null) {
+ throw new IOException();
+ }
+ writer = new OutputStreamWriter(outputStream, LangUtils.UTF_8);
+ exportWriter.writeDocument(DBReader.getFeedList(), writer);
+ subscriber.onNext(output);
+ } catch (IOException e) {
+ subscriber.onError(e);
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch (IOException e) {
+ subscriber.onError(e);
+ }
+ }
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ subscriber.onError(e);
+ }
+ }
+ subscriber.onComplete();
+ }
+ });
+ }
+
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
index 219725b01..40b101ddf 100644
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.asynctask;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import java.io.File;
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
index 13b95907f..b88b58537 100644
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
@@ -3,7 +3,7 @@ package de.danoeh.antennapod.asynctask;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
-import android.support.v7.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog;
import android.util.Log;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java
index eb70d8e0b..c3f5d898c 100644
--- a/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java
+++ b/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java
@@ -35,6 +35,6 @@ public class PlaybackServiceCallbacksImpl implements PlaybackServiceCallbacks {
@Override
public int getNotificationIconResource(Context context) {
- return R.drawable.ic_stat_antenna_default;
+ return R.drawable.ic_antenna;
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java
index c185a5557..4cfa7e870 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java
@@ -9,7 +9,7 @@ import de.danoeh.antennapod.adapter.DataFolderAdapter;
public class ChooseDataFolderDialog {
- public static abstract class RunnableWithString implements Runnable {
+ public abstract static class RunnableWithString implements Runnable {
public RunnableWithString() {
super();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
index ed35495fa..f6d08b7bf 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
@@ -4,16 +4,16 @@ import android.app.AlertDialog;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.support.annotation.IdRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.PluralsRes;
-import android.support.annotation.StringRes;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.app.Fragment;
-import android.support.v4.util.ArrayMap;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.IdRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.PluralsRes;
+import androidx.annotation.StringRes;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.core.app.ActivityCompat;
+import androidx.fragment.app.Fragment;
+import androidx.collection.ArrayMap;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java
index 607084c42..d2912f90f 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.dialog;
import android.content.Context;
-import android.support.v7.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog;
import android.text.TextUtils;
import java.util.Arrays;
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java
index 933ced0f9..17668586b 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.dialog;
import android.content.Context;
-import android.support.v7.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog;
import android.text.Editable;
import android.text.InputType;
import android.view.View;
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
index 3dc8abbbe..2f0caa982 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
@@ -2,8 +2,8 @@ package de.danoeh.antennapod.dialog;
import android.app.Dialog;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.SeekBar;
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
index c1008a380..0499d02f1 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
@@ -4,7 +4,7 @@ import android.app.Dialog;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
-import android.support.v4.content.ContextCompat;
+import androidx.core.content.ContextCompat;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java
index 24656ed29..c49e9153e 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java
@@ -2,11 +2,9 @@ package de.danoeh.antennapod.dialog;
import android.app.Dialog;
import android.content.Context;
-import android.content.Intent;
import android.content.SharedPreferences;
-import android.net.Uri;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import android.util.Log;
import com.afollestad.materialdialogs.MaterialDialog;
@@ -15,6 +13,7 @@ import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.util.IntentUtils;
public class RatingDialog {
@@ -59,14 +58,10 @@ public class RatingDialog {
private static void rateNow() {
Context context = mContext.get();
- if(context == null) {
+ if (context == null) {
return;
}
- final String appPackage = "de.danoeh.antennapod";
- final Uri uri = Uri.parse("https://play.google.com/store/apps/details?id=" + appPackage);
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(intent);
+ IntentUtils.openInBrowser(context, "https://play.google.com/store/apps/details?id=de.danoeh.antennapod");
saveRated();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
index bf3faf89a..1cf34b2b3 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
@@ -5,7 +5,7 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
-import android.support.v7.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog;
import android.util.Log;
import android.view.View;
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
index ca9ed83d7..6535df5ef 100644
--- a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.discovery;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetPodcast;
import de.mfietz.fyydlin.SearchHit;
import org.json.JSONArray;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
index 3ef010f88..b7bfe3438 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -2,20 +2,15 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
-import android.provider.MediaStore;
-import android.support.v4.app.Fragment;
+import androidx.fragment.app.Fragment;
import android.view.ContextMenu;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.TextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
index bb52b26b7..3949a03a9 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
@@ -1,9 +1,9 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
index 4bebfe4c9..2df28b262 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.support.v4.app.ListFragment;
+import androidx.fragment.app.ListFragment;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
@@ -87,11 +87,10 @@ public class ChaptersFragment extends ListFragment {
controller = null;
}
- private void scrollTo(int position) {
- getListView().setSelection(position);
- }
-
private int getCurrentChapter(Playable media) {
+ if (media == null || media.getChapters() == null || media.getChapters().size() == 0 || controller == null) {
+ return -1;
+ }
int currentPosition = controller.getPosition();
List<Chapter> chapters = media.getChapters();
@@ -126,8 +125,10 @@ public class ChaptersFragment extends ListFragment {
if (adapter != null) {
adapter.setMedia(media);
adapter.notifyDataSetChanged();
- if (media != null && media.getChapters() != null && media.getChapters().size() != 0) {
- scrollTo(getCurrentChapter(media));
+
+ int positionOfCurrentChapter = getCurrentChapter(media);
+ if (positionOfCurrentChapter != -1) {
+ getListView().setSelection(positionOfCurrentChapter);
}
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java
index 1d9020f0d..5ab781fe3 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java
@@ -2,9 +2,9 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
+import androidx.fragment.app.Fragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.widget.SearchView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
index 705151062..1917e4c75 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.ListFragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.ListFragment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
index db9dd9530..cf9ee6c41 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.Fragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
index 26b115b4b..528c50747 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
@@ -4,8 +4,8 @@ import android.app.AlertDialog;
import android.app.Dialog;
import android.content.res.TypedArray;
import android.os.Bundle;
-import android.support.v4.app.ListFragment;
-import android.support.v4.view.MenuItemCompat;
+import androidx.fragment.app.ListFragment;
+import androidx.core.view.MenuItemCompat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
index aa6029c84..b1bcdf404 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
@@ -4,11 +4,11 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
-import android.support.design.widget.TabLayout;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentPagerAdapter;
-import android.support.v4.view.ViewPager;
+import com.google.android.material.tabs.TabLayout;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentPagerAdapter;
+import androidx.viewpager.widget.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java
index ca21df661..8cdec9f38 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java
@@ -4,11 +4,11 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
-import android.support.design.widget.TabLayout;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentPagerAdapter;
-import android.support.v4.view.ViewPager;
+import com.google.android.material.tabs.TabLayout;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentPagerAdapter;
+import androidx.viewpager.widget.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
index 1cedb5a91..3fc67f795 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
@@ -4,15 +4,13 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.os.Handler;
-import android.support.annotation.NonNull;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.Fragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.SearchView;
-import android.support.v7.widget.SimpleItemAnimator;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.appcompat.widget.SearchView;
+import androidx.recyclerview.widget.SimpleItemAnimator;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -23,8 +21,17 @@ import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
-import com.joanzapata.iconify.Iconify;
+
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
+
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import java.util.ArrayList;
+import java.util.List;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter;
@@ -33,21 +40,16 @@ import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
-import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.feed.FeedItemFilter;
import de.danoeh.antennapod.core.feed.FeedMedia;
-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.service.download.Downloader;
-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.DownloadRequester;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
-import de.danoeh.antennapod.dialog.FilterDialog;
+import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.view.EmptyViewHandler;
@@ -55,13 +57,6 @@ import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
/**
* Shows unread or recently published episodes
@@ -149,7 +144,7 @@ public abstract class EpisodesListFragment extends Fragment {
SharedPreferences.Editor editor = prefs.edit();
editor.putInt(PREF_SCROLL_POSITION, firstItem);
editor.putFloat(PREF_SCROLL_OFFSET, topOffset);
- editor.commit();
+ editor.apply();
}
private void restoreScrollPosition() {
@@ -162,7 +157,7 @@ public abstract class EpisodesListFragment extends Fragment {
SharedPreferences.Editor editor = prefs.edit();
editor.putInt(PREF_SCROLL_POSITION, 0);
editor.putFloat(PREF_SCROLL_OFFSET, 0.0f);
- editor.commit();
+ editor.apply();
}
}
@@ -202,10 +197,7 @@ public abstract class EpisodesListFragment extends Fragment {
if (!super.onOptionsItemSelected(item)) {
switch (item.getItemId()) {
case R.id.refresh_item:
- List<Feed> feeds = ((MainActivity) getActivity()).getFeeds();
- if (feeds != null) {
- DBTasks.refreshAllFeeds(getActivity(), feeds);
- }
+ AutoUpdateManager.runImmediate(requireContext());
return true;
case R.id.mark_all_read_item:
ConfirmationDialog markAllReadConfirmationDialog = new ConfirmationDialog(getActivity(),
@@ -262,17 +254,7 @@ public abstract class EpisodesListFragment extends Fragment {
}
FeedItem selectedItem = listAdapter.getSelectedItem();
- // Remove new flag contains UI logic specific to All/New/FavoriteSegments,
- // e.g., Undo with Snackbar,
- // and is handled by this class rather than the generic FeedItemMenuHandler
- // Undo is useful for Remove new flag, given there is no UI to undo it otherwise,
- // i.e., there is context menu item for Mark as new
- if (R.id.remove_new_flag_item == item.getItemId()) {
- removeNewFlagWithUndo(selectedItem);
- return true;
- }
-
- return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
+ return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem);
}
@NonNull
@@ -403,6 +385,13 @@ public abstract class EpisodesListFragment extends Fragment {
}
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(PlaybackPositionEvent event) {
+ if (listAdapter != null) {
+ listAdapter.notifyCurrentlyPlayingItemChanged(event);
+ }
+ }
+
protected boolean shouldUpdatedItemRemainInList(FeedItem item) {
return true;
}
@@ -412,7 +401,7 @@ public abstract class EpisodesListFragment extends Fragment {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
- if (isMenuInvalidationAllowed && isUpdatingFeeds != update.feedIds.length > 0) {
+ if (isMenuInvalidationAllowed && event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) {
requireActivity().invalidateOptionsMenu();
}
if (update.mediaIds.length > 0) {
@@ -453,36 +442,4 @@ public abstract class EpisodesListFragment extends Fragment {
@NonNull
protected abstract List<FeedItem> loadData();
-
- void removeNewFlagWithUndo(FeedItem item) {
- if (item == null) {
- return;
- }
-
- Log.d(TAG, "removeNewFlagWithUndo(" + item.getId() + ")");
- if (disposable != null) {
- disposable.dispose();
- }
- // we're marking it as unplayed since the user didn't actually play it
- // but they don't want it considered 'NEW' anymore
- DBWriter.markItemPlayed(FeedItem.UNPLAYED, item.getId());
-
- final Handler h = new Handler(getActivity().getMainLooper());
- final Runnable r = () -> {
- FeedMedia media = item.getMedia();
- if (media != null && media.hasAlmostEnded() && UserPreferences.isAutoDelete()) {
- DBWriter.deleteFeedMediaOfItem(getActivity(), media.getId());
- }
- };
-
- Snackbar snackbar = Snackbar.make(getView(), getString(R.string.removed_new_flag_label),
- Snackbar.LENGTH_LONG);
- snackbar.setAction(getString(R.string.undo), v -> {
- DBWriter.markItemPlayed(FeedItem.NEW, item.getId());
- // don't forget to cancel the thing that's going to remove the media
- h.removeCallbacks(r);
- });
- snackbar.show();
- h.postDelayed(r, (int) Math.ceil(snackbar.getDuration() * 1.05f));
- }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
index 348c73b92..bbc33c6ca 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -3,8 +3,8 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
-import android.support.v4.app.ActivityOptionsCompat;
-import android.support.v4.app.Fragment;
+import androidx.core.app.ActivityOptionsCompat;
+import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -18,7 +18,7 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.event.ServiceEvent;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
@@ -28,6 +28,9 @@ import io.reactivex.Maybe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
/**
* Fragment which is supposed to be displayed outside of the MediaplayerActivity
@@ -138,6 +141,7 @@ public class ExternalPlayerFragment extends Fragment {
controller = setupPlaybackController();
controller.init();
loadMediaInfo();
+ EventBus.getDefault().register(this);
}
@Override
@@ -147,6 +151,12 @@ public class ExternalPlayerFragment extends Fragment {
controller.release();
controller = null;
}
+ EventBus.getDefault().unregister(this);
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(PlaybackPositionEvent event) {
+ onPositionObserverUpdate();
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
index 536ebd468..5282a6bb2 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
@@ -1,13 +1,12 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.design.widget.Snackbar;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
+import androidx.annotation.NonNull;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.ItemTouchHelper;
import android.util.Log;
import android.view.LayoutInflater;
-import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java
new file mode 100644
index 000000000..6b270e220
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java
@@ -0,0 +1,234 @@
+package de.danoeh.antennapod.fragment;
+
+import android.content.ClipData;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.LightingColorFilter;
+import android.net.Uri;
+import android.os.Bundle;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
+import com.joanzapata.iconify.Iconify;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
+import de.danoeh.antennapod.core.glide.FastBlurTransformation;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DownloadRequestException;
+import de.danoeh.antennapod.core.util.IntentUtils;
+import de.danoeh.antennapod.core.util.LangUtils;
+import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText;
+import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
+import io.reactivex.Maybe;
+import io.reactivex.MaybeOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+import org.apache.commons.lang3.StringUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+
+/**
+ * Displays information about a feed.
+ */
+public class FeedInfoFragment extends Fragment {
+
+ private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
+ private static final String TAG = "FeedInfoActivity";
+
+ private Feed feed;
+ private Disposable disposable;
+ private ImageView imgvCover;
+ private TextView txtvTitle;
+ private TextView txtvDescription;
+ private TextView lblLanguage;
+ private TextView txtvLanguage;
+ private TextView lblAuthor;
+ private TextView txtvAuthor;
+ private TextView txtvUrl;
+ private TextView txtvAuthorHeader;
+ private ImageView imgvBackground;
+
+ public static FeedInfoFragment newInstance(Feed feed) {
+ FeedInfoFragment fragment = new FeedInfoFragment();
+ Bundle arguments = new Bundle();
+ arguments.putLong(EXTRA_FEED_ID, feed.getId());
+ fragment.setArguments(arguments);
+ return fragment;
+ }
+
+ private final View.OnClickListener copyUrlToClipboard = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if(feed != null && feed.getDownload_url() != null) {
+ String url = feed.getDownload_url();
+ ClipData clipData = ClipData.newPlainText(url, url);
+ android.content.ClipboardManager cm = (android.content.ClipboardManager) getContext()
+ .getSystemService(Context.CLIPBOARD_SERVICE);
+ cm.setPrimaryClip(clipData);
+ Toast t = Toast.makeText(getContext(), R.string.copied_url_msg, Toast.LENGTH_SHORT);
+ t.show();
+ }
+ }
+ };
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ ((MainActivity)getActivity()).getSupportActionBar().setTitle(R.string.feed_info_label);
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View root = inflater.inflate(R.layout.feedinfo, null);
+ setHasOptionsMenu(true);
+
+ imgvCover = root.findViewById(R.id.imgvCover);
+ txtvTitle = root.findViewById(R.id.txtvTitle);
+ txtvAuthorHeader = root.findViewById(R.id.txtvAuthor);
+ imgvBackground = root.findViewById(R.id.imgvBackground);
+ root.findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE);
+ root.findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE);
+ // https://github.com/bumptech/glide/issues/529
+ imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
+
+
+ txtvDescription = root.findViewById(R.id.txtvDescription);
+ lblLanguage = root.findViewById(R.id.lblLanguage);
+ txtvLanguage = root.findViewById(R.id.txtvLanguage);
+ lblAuthor = root.findViewById(R.id.lblAuthor);
+ txtvAuthor = root.findViewById(R.id.txtvDetailsAuthor);
+ txtvUrl = root.findViewById(R.id.txtvUrl);
+
+ txtvUrl.setOnClickListener(copyUrlToClipboard);
+ postponeEnterTransition();
+ return root;
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ long feedId = getArguments().getLong(EXTRA_FEED_ID);
+ disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
+ Feed feed = DBReader.getFeed(feedId);
+ if (feed != null) {
+ emitter.onSuccess(feed);
+ } else {
+ emitter.onComplete();
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(result -> {
+ feed = result;
+ showFeed();
+ }, error -> Log.d(TAG, Log.getStackTraceString(error)),
+ this::startPostponedEnterTransition);
+ }
+
+ private void showFeed() {
+ Log.d(TAG, "Language is " + feed.getLanguage());
+ Log.d(TAG, "Author is " + feed.getAuthor());
+ Log.d(TAG, "URL is " + feed.getDownload_url());
+ Glide.with(getContext())
+ .load(feed.getImageLocation())
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate())
+ .into(imgvCover);
+ Glide.with(getContext())
+ .load(feed.getImageLocation())
+ .apply(new RequestOptions()
+ .placeholder(R.color.image_readability_tint)
+ .error(R.color.image_readability_tint)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .transform(new FastBlurTransformation())
+ .dontAnimate())
+ .into(imgvBackground);
+
+ txtvTitle.setText(feed.getTitle());
+
+ String description = feed.getDescription();
+ if(description != null) {
+ if(Feed.TYPE_ATOM1.equals(feed.getType())) {
+ HtmlToPlainText formatter = new HtmlToPlainText();
+ Document feedDescription = Jsoup.parse(feed.getDescription());
+ description = StringUtils.trim(formatter.getPlainText(feedDescription));
+ }
+ } else {
+ description = "";
+ }
+ txtvDescription.setText(description);
+
+ if (!TextUtils.isEmpty(feed.getAuthor())) {
+ txtvAuthor.setText(feed.getAuthor());
+ txtvAuthorHeader.setText(feed.getAuthor());
+ } else {
+ lblAuthor.setVisibility(View.GONE);
+ txtvAuthor.setVisibility(View.GONE);
+ }
+ if (!TextUtils.isEmpty(feed.getLanguage())) {
+ txtvLanguage.setText(LangUtils.getLanguageString(feed.getLanguage()));
+ } else {
+ lblLanguage.setVisibility(View.GONE);
+ txtvLanguage.setVisibility(View.GONE);
+ }
+ txtvUrl.setText(feed.getDownload_url() + " {fa-paperclip}");
+ Iconify.addIcons(txtvUrl);
+
+ getActivity().invalidateOptionsMenu();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.feedinfo, menu);
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ menu.findItem(R.id.share_link_item).setVisible(feed != null && feed.getLink() != null);
+ menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null &&
+ IntentUtils.isCallable(getContext(), new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink()))));
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ boolean handled = false;
+ try {
+ handled = FeedMenuHandler.onOptionsItemClicked(getContext(), item, feed);
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DownloadRequestErrorDialogCreator.newRequestErrorDialog(getContext(), e.getMessage());
+ }
+ return handled || super.onOptionsItemSelected(item);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
index f8ef7f7a3..0c33dce5a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
@@ -3,13 +3,12 @@ package de.danoeh.antennapod.fragment;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.Intent;
import android.graphics.LightingColorFilter;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.ListFragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.ListFragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.widget.SearchView;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
@@ -17,7 +16,6 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ImageView;
@@ -30,6 +28,7 @@ import com.bumptech.glide.request.RequestOptions;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconTextView;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import org.apache.commons.lang3.Validate;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
@@ -38,8 +37,6 @@ import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.FeedInfoActivity;
-import de.danoeh.antennapod.activity.FeedSettingsActivity;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
@@ -141,44 +138,33 @@ public class FeedItemlistFragment extends ListFragment {
}
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View view = super.onCreateView(inflater, container, savedInstanceState);
- ((ListView) view.findViewById(android.R.id.list)).setFastScrollEnabled(true);
- return view;
+ public void onHiddenChanged(boolean hidden) {
+ super.onHiddenChanged(hidden);
+ if (!hidden && getActivity() != null) {
+ ((MainActivity) getActivity()).getSupportActionBar().setTitle("");
+ }
}
@Override
- public void onStart() {
- super.onStart();
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ registerForContextMenu(getListView());
+
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
loadItems();
}
@Override
- public void onResume() {
- super.onResume();
- ((MainActivity)getActivity()).getSupportActionBar().setTitle("");
- updateProgressBarVisibility();
- }
+ public void onDestroyView() {
+ super.onDestroyView();
- @Override
- public void onStop() {
- super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
- if(disposable != null) {
+ if (disposable != null) {
disposable.dispose();
}
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- resetViewState();
- }
-
- private void resetViewState() {
adapter = null;
listFooter = null;
}
@@ -331,7 +317,7 @@ public class FeedItemlistFragment extends ListFragment {
contextMenu = menu;
lastMenuInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
- FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, null);
+ FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item);
}
@Override
@@ -348,14 +334,7 @@ public class FeedItemlistFragment extends ListFragment {
return super.onContextItemSelected(item);
}
- return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- registerForContextMenu(getListView());
+ return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem);
}
@Override
@@ -398,14 +377,21 @@ public class FeedItemlistFragment extends ListFragment {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
- if (isUpdatingFeed != event.update.feedIds.length > 0) {
+ if (event.hasChangedFeedUpdateStatus(isUpdatingFeed)) {
updateProgressBarVisibility();
}
- if(adapter != null && update.mediaIds.length > 0) {
+ if (adapter != null && update.mediaIds.length > 0) {
adapter.notifyDataSetChanged();
}
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(PlaybackPositionEvent event) {
+ if (adapter != null) {
+ adapter.notifyCurrentlyPlayingItemChanged(event, getListView());
+ }
+ }
+
private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
@@ -429,8 +415,9 @@ public class FeedItemlistFragment extends ListFragment {
}
- private void onFragmentLoaded() {
- if(!isVisible()) {
+ private void displayList() {
+ if (getView() == null) {
+ Log.e(TAG, "Required root view is not yet created. Stop binding data to UI.");
return;
}
if (adapter == null) {
@@ -514,10 +501,8 @@ public class FeedItemlistFragment extends ListFragment {
imgvCover.setOnClickListener(v -> showFeedInfo());
butShowSettings.setOnClickListener(v -> {
if (feed != null) {
- Intent startIntent = new Intent(getActivity(), FeedSettingsActivity.class);
- startIntent.putExtra(FeedSettingsActivity.EXTRA_FEED_ID,
- feed.getId());
- startActivity(startIntent);
+ FeedSettingsFragment fragment = FeedSettingsFragment.newInstance(feed);
+ ((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.FLIP);
}
});
headerCreated = true;
@@ -525,10 +510,8 @@ public class FeedItemlistFragment extends ListFragment {
private void showFeedInfo() {
if (feed != null) {
- Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class);
- startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID,
- feed.getId());
- startActivity(startIntent);
+ FeedInfoFragment fragment = FeedInfoFragment.newInstance(feed);
+ ((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.FLIP);
}
}
@@ -634,7 +617,7 @@ public class FeedItemlistFragment extends ListFragment {
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
feed = result.orElse(null);
- onFragmentLoaded();
+ displayList();
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
index 8eb5ecd6b..b745313aa 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
@@ -1,46 +1,73 @@
package de.danoeh.antennapod.fragment;
-import android.arch.lifecycle.ViewModelProviders;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
-import android.support.v14.preference.SwitchPreference;
-import android.support.v7.preference.ListPreference;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import androidx.preference.SwitchPreference;
+import androidx.preference.ListPreference;
+import androidx.preference.PreferenceFragmentCompat;
+import android.util.Log;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedFilter;
import de.danoeh.antennapod.core.feed.FeedPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.dialog.AuthenticationDialog;
import de.danoeh.antennapod.dialog.EpisodeFilterDialog;
-import de.danoeh.antennapod.viewmodel.FeedSettingsViewModel;
-
+import io.reactivex.Maybe;
+import io.reactivex.MaybeOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
-import static de.danoeh.antennapod.activity.FeedSettingsActivity.EXTRA_FEED_ID;
import static de.danoeh.antennapod.core.feed.FeedPreferences.SPEED_USE_GLOBAL;
public class FeedSettingsFragment extends PreferenceFragmentCompat {
private static final CharSequence PREF_EPISODE_FILTER = "episodeFilter";
private static final String PREF_FEED_PLAYBACK_SPEED = "feedPlaybackSpeed";
private static final DecimalFormat decimalFormat = new DecimalFormat("0.00", DecimalFormatSymbols.getInstance(Locale.US));
+ private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
+ private static final String TAG = "FeedSettingsFragment";
+
private Feed feed;
+ private Disposable disposable;
private FeedPreferences feedPreferences;
+ public static FeedSettingsFragment newInstance(Feed feed) {
+ FeedSettingsFragment fragment = new FeedSettingsFragment();
+ Bundle arguments = new Bundle();
+ arguments.putLong(EXTRA_FEED_ID, feed.getId());
+ fragment.setArguments(arguments);
+ return fragment;
+ }
+
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.feed_settings);
+ postponeEnterTransition();
long feedId = getArguments().getLong(EXTRA_FEED_ID);
- ViewModelProviders.of(getActivity()).get(FeedSettingsViewModel.class).getFeed(feedId)
+ disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
+ Feed feed = DBReader.getFeed(feedId);
+ if (feed != null) {
+ emitter.onSuccess(feed);
+ } else {
+ emitter.onComplete();
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
feed = result;
feedPreferences = feed.getPreferences();
+ ((MainActivity) getActivity()).getSupportActionBar().setSubtitle(feed.getTitle());
setupAutoDownloadPreference();
setupKeepUpdatedPreference();
@@ -52,11 +79,35 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat {
updateAutoDeleteSummary();
updateAutoDownloadEnabled();
updatePlaybackSpeedPreference();
- }).dispose();
+ }, error -> Log.d(TAG, Log.getStackTraceString(error)),
+ this::startPostponedEnterTransition);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.feed_settings_label);
+ if (feed != null) {
+ ((MainActivity) getActivity()).getSupportActionBar().setSubtitle(feed.getTitle());
+ }
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ ((MainActivity) getActivity()).getSupportActionBar().setSubtitle(null);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (disposable != null) {
+ disposable.dispose();
+ }
}
private void setupPlaybackSpeedPreference() {
- ListPreference feedPlaybackSpeedPreference = (ListPreference) findPreference(PREF_FEED_PLAYBACK_SPEED);
+ ListPreference feedPlaybackSpeedPreference = findPreference(PREF_FEED_PLAYBACK_SPEED);
String[] speeds = UserPreferences.getPlaybackSpeedArray();
@@ -130,14 +181,14 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat {
}
private void updatePlaybackSpeedPreference() {
- ListPreference feedPlaybackSpeedPreference = (ListPreference) findPreference(PREF_FEED_PLAYBACK_SPEED);
+ ListPreference feedPlaybackSpeedPreference = findPreference(PREF_FEED_PLAYBACK_SPEED);
float speedValue = feedPreferences.getFeedPlaybackSpeed();
feedPlaybackSpeedPreference.setValue(decimalFormat.format(speedValue));
}
private void updateAutoDeleteSummary() {
- ListPreference autoDeletePreference = (ListPreference) findPreference("autoDelete");
+ ListPreference autoDeletePreference = findPreference("autoDelete");
switch (feedPreferences.getAutoDeleteAction()) {
case GLOBAL:
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java
index 9c16cfe56..a3c3df340 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java
@@ -2,9 +2,9 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
+import androidx.fragment.app.Fragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.widget.SearchView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
index 5cf2c5eeb..a97d60099 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -2,7 +2,6 @@ package de.danoeh.antennapod.fragment;
import android.annotation.SuppressLint;
import android.app.Activity;
-import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
@@ -12,8 +11,8 @@ import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.Fragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
@@ -96,13 +95,7 @@ public class ItemDescriptionFragment extends Fragment {
if (Timeline.isTimecodeLink(url)) {
onTimecodeLinkSelected(url);
} else {
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- try {
- startActivity(intent);
- } catch (ActivityNotFoundException e) {
- e.printStackTrace();
- return true;
- }
+ IntentUtils.openInBrowser(getContext(), url);
}
return true;
}
@@ -159,11 +152,7 @@ public class ItemDescriptionFragment extends Fragment {
if (selectedURL != null) {
switch (item.getItemId()) {
case R.id.open_in_browser_item:
- Uri uri = Uri.parse(selectedURL);
- final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- if(IntentUtils.isCallable(getActivity(), intent)) {
- getActivity().startActivity(intent);
- }
+ IntentUtils.openInBrowser(getContext(), selectedURL);
break;
case R.id.share_url_item:
ShareUtils.shareLink(getActivity(), selectedURL);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
index 3a48c5431..f17f8c645 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -6,10 +6,10 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v4.app.Fragment;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.view.GestureDetectorCompat;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.core.content.ContextCompat;
+import androidx.core.view.GestureDetectorCompat;
import android.text.Layout;
import android.text.TextUtils;
import android.util.Log;
@@ -55,7 +55,6 @@ import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.Downloader;
-import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
@@ -211,10 +210,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
webvDescription.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- if(IntentUtils.isCallable(getActivity(), intent)) {
- startActivity(intent);
- }
+ IntentUtils.openInBrowser(getContext(), url);
return true;
}
});
@@ -336,10 +332,10 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
inflater.inflate(R.menu.feeditem_options, menu);
popupMenu = menu;
if (item.hasMedia()) {
- FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, null);
+ FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item);
} else {
// these are already available via button1 and button2
- FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, null,
+ FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item,
R.id.mark_read_item, R.id.visit_website_item);
}
}
@@ -351,7 +347,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
openPodcast();
return true;
default:
- return FeedItemMenuHandler.onMenuItemClicked(getActivity(), menuItem.getItemId(), item);
+ return FeedItemMenuHandler.onMenuItemClicked(this, menuItem.getItemId(), item);
}
}
@@ -485,11 +481,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
if (selectedURL != null) {
switch (item.getItemId()) {
case R.id.open_in_browser_item:
- Uri uri = Uri.parse(selectedURL);
- final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- if(IntentUtils.isCallable(getActivity(), intent)) {
- getActivity().startActivity(intent);
- }
+ IntentUtils.openInBrowser(getContext(), selectedURL);
break;
case R.id.share_url_item:
ShareUtils.shareLink(getActivity(), selectedURL);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
index 80767bef2..673b58901 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
@@ -2,10 +2,10 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
-import android.support.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.widget.SearchView;
+import androidx.annotation.NonNull;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -23,29 +23,15 @@ import com.afollestad.materialdialogs.MaterialDialog;
import de.danoeh.antennapod.discovery.ItunesPodcastSearcher;
import de.danoeh.antennapod.discovery.ItunesTopListLoader;
import de.danoeh.antennapod.discovery.PodcastSearchResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import java.util.Locale;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
-import de.danoeh.antennapod.core.ClientConfig;
-import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
-import io.reactivex.Single;
-import io.reactivex.SingleOnSubscribe;
-import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
-import io.reactivex.schedulers.Schedulers;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.Response;
//Searches iTunes store for given string and displays results in a list
public class ItunesSearchFragment extends Fragment {
@@ -167,7 +153,7 @@ public class ItunesSearchFragment extends Fragment {
final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
MenuItemUtils.adjustTextColor(getActivity(), sv);
sv.setQueryHint(getString(R.string.search_itunes_label));
- sv.setOnQueryTextListener(new android.support.v7.widget.SearchView.OnQueryTextListener() {
+ sv.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
sv.clearFocus();
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 adae4f2a5..5dbb84bc7 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
@@ -1,12 +1,11 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.Menu;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -16,6 +15,7 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
/**
* Like 'EpisodesFragment' except that it only shows new episodes and
@@ -63,7 +63,7 @@ public class NewEpisodesFragment extends EpisodesListFragment {
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder) viewHolder;
- removeNewFlagWithUndo(holder.getFeedItem());
+ FeedItemMenuHandler.removeNewFlagWithUndo(NewEpisodesFragment.this, holder.getFeedItem());
}
@Override
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 e2060481f..f9fca87fc 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -2,9 +2,9 @@ package de.danoeh.antennapod.fragment;
import android.content.res.TypedArray;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.ListFragment;
-import android.support.v4.view.MenuItemCompat;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.ListFragment;
+import androidx.core.view.MenuItemCompat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
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 423e8b17b..dcb16d192 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -4,14 +4,15 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.Fragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.SearchView;
-import android.support.v7.widget.SimpleItemAnimator;
-import android.support.v7.widget.helper.ItemTouchHelper;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.fragment.app.Fragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.app.AlertDialog;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.appcompat.widget.SearchView;
+import androidx.recyclerview.widget.SimpleItemAnimator;
+import androidx.recyclerview.widget.ItemTouchHelper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -19,11 +20,17 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.CheckBox;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
import java.util.List;
import de.danoeh.antennapod.R;
@@ -42,7 +49,6 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.service.download.Downloader;
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.DownloadRequester;
import de.danoeh.antennapod.core.util.Converter;
@@ -50,18 +56,15 @@ import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.QueueSorter;
import de.danoeh.antennapod.core.util.SortOrder;
+import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
-
import de.danoeh.antennapod.view.EmptyViewHandler;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
import static de.danoeh.antennapod.core.feed.FeedPreferences.SPEED_USE_GLOBAL;
import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_DELETE;
@@ -92,10 +95,12 @@ public class QueueFragment extends Fragment {
private static final String PREFS = "QueueFragment";
private static final String PREF_SCROLL_POSITION = "scroll_position";
private static final String PREF_SCROLL_OFFSET = "scroll_offset";
+ private static final String PREF_SHOW_LOCK_WARNING = "show_lock_warning";
private Disposable disposable;
private LinearLayoutManager layoutManager;
private ItemTouchHelper itemTouchHelper;
+ private SharedPreferences prefs;
@Override
@@ -103,6 +108,7 @@ public class QueueFragment extends Fragment {
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
+ prefs = getActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
}
@Override
@@ -197,8 +203,8 @@ public class QueueFragment extends Fragment {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
- if (isUpdatingFeeds != update.feedIds.length > 0) {
- getActivity().supportInvalidateOptionsMenu();
+ if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) {
+ getActivity().invalidateOptionsMenu();
}
if (recyclerAdapter != null && update.mediaIds.length > 0) {
for (long mediaId : update.mediaIds) {
@@ -210,6 +216,13 @@ public class QueueFragment extends Fragment {
}
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(PlaybackPositionEvent event) {
+ if (recyclerAdapter != null) {
+ recyclerAdapter.notifyCurrentlyPlayingItemChanged(event);
+ }
+ }
+
private void saveScrollPosition() {
int firstItem = layoutManager.findFirstVisibleItemPosition();
View firstItemView = layoutManager.findViewByPosition(firstItem);
@@ -220,15 +233,13 @@ public class QueueFragment extends Fragment {
topOffset = firstItemView.getTop();
}
- SharedPreferences prefs = getActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putInt(PREF_SCROLL_POSITION, firstItem);
- editor.putFloat(PREF_SCROLL_OFFSET, topOffset);
- editor.commit();
+ prefs.edit()
+ .putInt(PREF_SCROLL_POSITION, firstItem)
+ .putFloat(PREF_SCROLL_OFFSET, topOffset)
+ .apply();
}
private void restoreScrollPosition() {
- SharedPreferences prefs = getActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
int position = prefs.getInt(PREF_SCROLL_POSITION, 0);
float offset = prefs.getFloat(PREF_SCROLL_OFFSET, 0.0f);
if (position > 0 || offset > 0) {
@@ -300,25 +311,10 @@ public class QueueFragment extends Fragment {
if (!super.onOptionsItemSelected(item)) {
switch (item.getItemId()) {
case R.id.queue_lock:
- boolean newLockState = !UserPreferences.isQueueLocked();
- UserPreferences.setQueueLocked(newLockState);
- getActivity().supportInvalidateOptionsMenu();
- if (recyclerAdapter != null) {
- recyclerAdapter.setLocked(newLockState);
- }
- if (newLockState) {
- Snackbar.make(getActivity().findViewById(R.id.content), R.string
- .queue_locked, Snackbar.LENGTH_SHORT).show();
- } else {
- Snackbar.make(getActivity().findViewById(R.id.content), R.string
- .queue_unlocked, Snackbar.LENGTH_SHORT).show();
- }
+ toggleQueueLock();
return true;
case R.id.refresh_item:
- List<Feed> feeds = ((MainActivity) getActivity()).getFeeds();
- if (feeds != null) {
- DBTasks.refreshAllFeeds(getActivity(), feeds);
- }
+ AutoUpdateManager.runImmediate(requireContext());
return true;
case R.id.clear_queue:
// make sure the user really wants to clear the queue
@@ -395,6 +391,48 @@ public class QueueFragment extends Fragment {
}
}
+ private void toggleQueueLock() {
+ boolean isLocked = UserPreferences.isQueueLocked();
+ if (isLocked) {
+ setQueueLocked(false);
+ } else {
+ boolean shouldShowLockWarning = prefs.getBoolean(PREF_SHOW_LOCK_WARNING, true);
+ if (!shouldShowLockWarning) {
+ setQueueLocked(true);
+ } else {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ builder.setTitle(R.string.lock_queue);
+ builder.setMessage(R.string.queue_lock_warning);
+
+ View view = View.inflate(getContext(), R.layout.checkbox_do_not_show_again, null);
+ CheckBox checkDoNotShowAgain = view.findViewById(R.id.checkbox_do_not_show_again);
+ builder.setView(view);
+
+ builder.setPositiveButton(R.string.lock_queue, (dialog, which) -> {
+ prefs.edit().putBoolean(PREF_SHOW_LOCK_WARNING, !checkDoNotShowAgain.isChecked()).apply();
+ setQueueLocked(true);
+ });
+ builder.setNegativeButton(R.string.cancel_label, null);
+ builder.show();
+ }
+ }
+ }
+
+ private void setQueueLocked(boolean locked) {
+ UserPreferences.setQueueLocked(locked);
+ getActivity().supportInvalidateOptionsMenu();
+ if (recyclerAdapter != null) {
+ recyclerAdapter.setLocked(locked);
+ }
+ if (locked) {
+ Snackbar.make(getActivity().findViewById(R.id.content), R.string
+ .queue_locked, Snackbar.LENGTH_SHORT).show();
+ } else {
+ Snackbar.make(getActivity().findViewById(R.id.content), R.string
+ .queue_unlocked, Snackbar.LENGTH_SHORT).show();
+ }
+ }
+
/**
* This method is called if the user clicks on a sort order menu item.
*
@@ -431,7 +469,7 @@ public class QueueFragment extends Fragment {
DBWriter.moveQueueItemToBottom(selectedItem.getId(), true);
return true;
default:
- return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
+ return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem);
}
}
@@ -614,7 +652,7 @@ public class QueueFragment extends Fragment {
/ playbackSpeed);
}
}
- info += " \u2022 ";
+ info += " • ";
info += getString(R.string.time_left_label);
info += Converter.getDurationStringLocalized(getActivity(), timeLeft);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
index e4213cc6b..226209740 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
+import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
index 2a7f7d12b..528fa7c32 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.support.v4.app.ListFragment;
+import androidx.fragment.app.ListFragment;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
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 0892bce0a..7f3c60e5d 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -2,11 +2,11 @@ package de.danoeh.antennapod.fragment;
import android.content.Context;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.ListFragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.SearchView;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.ListFragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.SearchView;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
index 15c6052a9..21c744727 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
@@ -5,8 +5,8 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.support.annotation.StringRes;
-import android.support.v4.app.Fragment;
+import androidx.annotation.StringRes;
+import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
@@ -25,19 +25,27 @@ import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.SubscriptionsAdapter;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
+import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
+import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.IntentUtils;
+import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.dialog.RenameFeedDialog;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
/**
* Fragment for displaying feed subscriptions
@@ -56,6 +64,7 @@ public class SubscriptionFragment extends Fragment {
private SubscriptionsAdapter subscriptionAdapter;
private int mPosition = -1;
+ private boolean isUpdatingFeeds = false;
private Disposable disposable;
private SharedPreferences prefs;
@@ -89,6 +98,8 @@ public class SubscriptionFragment extends Fragment {
menu.findItem(R.id.subscription_num_columns_3).setChecked(columns == 3);
menu.findItem(R.id.subscription_num_columns_4).setChecked(columns == 4);
menu.findItem(R.id.subscription_num_columns_5).setChecked(columns == 5);
+
+ isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
}
@Override
@@ -97,6 +108,9 @@ public class SubscriptionFragment extends Fragment {
return true;
}
switch (item.getItemId()) {
+ case R.id.refresh_item:
+ AutoUpdateManager.runImmediate(requireContext());
+ return true;
case R.id.subscription_num_columns_2:
setColumnNumber(2);
return true;
@@ -136,6 +150,7 @@ public class SubscriptionFragment extends Fragment {
public void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
+ EventBus.getDefault().register(this);
loadSubscriptions();
}
@@ -143,6 +158,7 @@ public class SubscriptionFragment extends Fragment {
public void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
+ EventBus.getDefault().unregister(this);
if(disposable != null) {
disposable.dispose();
}
@@ -278,6 +294,17 @@ public class SubscriptionFragment extends Fragment {
}
};
+ @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(DownloadEvent event) {
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) {
+ getActivity().invalidateOptionsMenu();
+ }
+ }
+
+ private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker =
+ () -> DownloadService.isRunning && DownloadRequester.getInstance().isDownloadingFeeds();
+
private final SubscriptionsAdapter.ItemAccess itemAccess = new SubscriptionsAdapter.ItemAccess() {
@Override
public int getCount() {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java b/app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java
new file mode 100644
index 000000000..461fa9da3
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java
@@ -0,0 +1,5 @@
+package de.danoeh.antennapod.fragment;
+
+public enum TransitionEffect {
+ NONE, FLIP, FADE
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java
index 4dc114f9b..380f6741a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java
@@ -4,11 +4,11 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
-import android.support.design.widget.TabLayout;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentPagerAdapter;
-import android.support.v4.view.ViewPager;
+import com.google.android.material.tabs.TabLayout;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentPagerAdapter;
+import androidx.viewpager.widget.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
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 49851ebb4..1d6debbfe 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
@@ -4,9 +4,9 @@ import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
+import androidx.fragment.app.Fragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.widget.SearchView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -56,7 +56,7 @@ public abstract class PodcastListFragment extends Fragment {
final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
MenuItemUtils.adjustTextColor(getActivity(), sv);
sv.setQueryHint(getString(R.string.gpodnet_search_hint));
- sv.setOnQueryTextListener(new android.support.v7.widget.SearchView.OnQueryTextListener() {
+ sv.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
sv.clearFocus();
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 10bd636dd..60fc1f446 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
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.fragment.gpodnet;
import android.os.Bundle;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.widget.SearchView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
index d39829260..92cd4ca84 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.fragment.gpodnet;
import android.os.Bundle;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import org.apache.commons.lang3.Validate;
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 1e46b1ac5..b5a95bc33 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
@@ -4,9 +4,9 @@ import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.support.v4.app.ListFragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
+import androidx.fragment.app.ListFragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.widget.SearchView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java
index a04615a00..121b7fef8 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java
@@ -1,29 +1,42 @@
package de.danoeh.antennapod.fragment.preferences;
+import android.Manifest;
import android.app.Activity;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
+import android.os.Build;
import android.os.Bundle;
-import android.support.v7.preference.CheckBoxPreference;
-import android.support.v7.preference.ListPreference;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceFragmentCompat;
-import android.support.v7.preference.PreferenceScreen;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+import androidx.preference.CheckBoxPreference;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceScreen;
import android.util.Log;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+
public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat {
private static final String TAG = "AutoDnldPrefFragment";
+
+ private static final int LOCATION_PERMISSION_REQUEST_CODE = 1;
+ private static final String PREF_KEY_LOCATION_PERMISSION_REQUEST_PROMPT = "prefAutoDownloadWifiFilterAndroid10PermissionPrompt";
+
private CheckBoxPreference[] selectedNetworks;
+ private Preference prefPermissionRequestPromptOnAndroid10 = null;
+
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences_autodownload);
@@ -35,6 +48,12 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat {
}
@Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.auto_download_label);
+ }
+
+ @Override
public void onResume() {
super.onResume();
checkAutodownloadItemVisibility(UserPreferences.isEnableAutodownload());
@@ -175,10 +194,65 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat {
}
private void setSelectedNetworksEnabled(boolean b) {
+ if (showPermissionRequestPromptOnAndroid10IfNeeded(b)) {
+ return;
+ }
+
if (selectedNetworks != null) {
for (Preference p : selectedNetworks) {
p.setEnabled(b);
}
}
}
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) {
+ return;
+ }
+ if (permissions.length > 0 && permissions[0].equals(Manifest.permission.ACCESS_FINE_LOCATION) &&
+ grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ buildAutodownloadSelectedNetworksPreference();
+ }
+ }
+
+ private boolean showPermissionRequestPromptOnAndroid10IfNeeded(boolean wifiFilterEnabled) {
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
+ return false;
+ }
+
+ // Cases Android 10(Q) or later
+ if (prefPermissionRequestPromptOnAndroid10 != null) {
+ getPreferenceScreen().removePreference(prefPermissionRequestPromptOnAndroid10);
+ prefPermissionRequestPromptOnAndroid10 = null;
+ }
+
+ if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+
+ // Case location permission not yet granted, permission-specific UI is needed
+ if (!wifiFilterEnabled) {
+ // Don't show the UI when WiFi filter disabled.
+ // it still return true, so that the caller knows
+ // it does not have required permission, and will not invoke codes that require so.
+ return true;
+ }
+
+ Preference pref = new Preference(requireActivity());
+ pref.setKey(PREF_KEY_LOCATION_PERMISSION_REQUEST_PROMPT);
+ pref.setTitle(R.string.autodl_wifi_filter_permission_title);
+ pref.setSummary(R.string.autodl_wifi_filter_permission_message);
+ pref.setIcon(R.drawable.ic_warning_red);
+ pref.setOnPreferenceClickListener(preference -> {
+ requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE);
+ return true;
+ });
+ pref.setPersistent(false);
+ getPreferenceScreen().addPreference(pref);
+ prefPermissionRequestPromptOnAndroid10 = pref;
+ return true;
+ }
+
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
index 491922056..c6ae8e20c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
@@ -3,12 +3,13 @@ package de.danoeh.antennapod.fragment.preferences;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
import android.text.Html;
import android.text.format.DateUtils;
import android.widget.Toast;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.service.GpodnetSyncService;
import de.danoeh.antennapod.dialog.AuthenticationDialog;
@@ -30,6 +31,12 @@ public class GpodderPreferencesFragment extends PreferenceFragmentCompat {
}
@Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.gpodnet_main_label);
+ }
+
+ @Override
public void onResume() {
super.onResume();
GpodnetPreferences.registerOnSharedPreferenceChangeListener(gpoddernetListener);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java
index 229274b76..51f31eb92 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.fragment.preferences;
import android.os.Bundle;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceFragmentCompat;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.PreferenceActivity;
@@ -14,6 +14,12 @@ public class IntegrationsPreferencesFragment extends PreferenceFragmentCompat {
setupIntegrationsScreen();
}
+ @Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.integrations_label);
+ }
+
private void setupIntegrationsScreen() {
findPreference(PREF_SCREEN_GPODDER).setOnPreferenceClickListener(preference -> {
((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_gpodder);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
index dcba5fe89..00e69f1db 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
@@ -1,27 +1,16 @@
package de.danoeh.antennapod.fragment.preferences;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
-import android.support.v4.content.FileProvider;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.preference.PreferenceFragmentCompat;
-import android.util.Log;
-import android.widget.Toast;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.preference.PreferenceFragmentCompat;
import com.bytehamster.lib.preferencesearch.SearchConfiguration;
import com.bytehamster.lib.preferencesearch.SearchPreference;
-import de.danoeh.antennapod.CrashReportWriter;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.AboutActivity;
+import de.danoeh.antennapod.activity.BugReportActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
-import de.danoeh.antennapod.activity.StatisticsActivity;
-
-import java.util.List;
+import de.danoeh.antennapod.core.util.IntentUtils;
public class MainPreferencesFragment extends PreferenceFragmentCompat {
private static final String TAG = "MainPreferencesFragment";
@@ -31,9 +20,9 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
private static final String PREF_SCREEN_NETWORK = "prefScreenNetwork";
private static final String PREF_SCREEN_INTEGRATIONS = "prefScreenIntegrations";
private static final String PREF_SCREEN_STORAGE = "prefScreenStorage";
- private static final String PREF_KNOWN_ISSUES = "prefKnownIssues";
private static final String PREF_FAQ = "prefFaq";
- private static final String PREF_SEND_CRASH_REPORT = "prefSendCrashReport";
+ private static final String PREF_VIEW_MAILING_LIST = "prefViewMailingList";
+ private static final String PREF_SEND_BUG_REPORT = "prefSendBugReport";
private static final String STATISTICS = "statistics";
private static final String PREF_ABOUT = "prefAbout";
@@ -44,6 +33,12 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
setupSearch();
}
+ @Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.settings_label);
+ }
+
private void setupMainScreen() {
findPreference(PREF_SCREEN_USER_INTERFACE).setOnPreferenceClickListener(preference -> {
((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_user_interface);
@@ -74,53 +69,25 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
);
findPreference(STATISTICS).setOnPreferenceClickListener(
preference -> {
- startActivity(new Intent(getActivity(), StatisticsActivity.class));
+ getFragmentManager().beginTransaction().replace(R.id.content, new StatisticsFragment())
+ .addToBackStack(getString(R.string.statistics_label)).commit();
return true;
}
);
- findPreference(PREF_KNOWN_ISSUES).setOnPreferenceClickListener(preference -> {
- openInBrowser("https://github.com/AntennaPod/AntennaPod/labels/bug");
+ findPreference(PREF_FAQ).setOnPreferenceClickListener(preference -> {
+ IntentUtils.openInBrowser(getContext(), "https://antennapod.org/faq.html");
return true;
});
- findPreference(PREF_FAQ).setOnPreferenceClickListener(preference -> {
- openInBrowser("https://antennapod.org/faq.html");
+ findPreference(PREF_VIEW_MAILING_LIST).setOnPreferenceClickListener(preference -> {
+ IntentUtils.openInBrowser(getContext(), "https://groups.google.com/forum/#!forum/antennapod");
return true;
});
- findPreference(PREF_SEND_CRASH_REPORT).setOnPreferenceClickListener(preference -> {
- Context context = getActivity().getApplicationContext();
- Intent emailIntent = new Intent(Intent.ACTION_SEND);
- emailIntent.setType("text/plain");
- emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"Martin.Fietz@gmail.com"});
- emailIntent.putExtra(Intent.EXTRA_SUBJECT, "AntennaPod Crash Report");
- emailIntent.putExtra(Intent.EXTRA_TEXT, "Please describe what you were doing when the app crashed");
- // the attachment
- Uri fileUri = FileProvider.getUriForFile(context, context.getString(R.string.provider_authority),
- CrashReportWriter.getFile());
- emailIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
- emailIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- String intentTitle = getActivity().getString(R.string.send_email);
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
- List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(emailIntent, PackageManager.MATCH_DEFAULT_ONLY);
- for (ResolveInfo resolveInfo : resInfoList) {
- String packageName = resolveInfo.activityInfo.packageName;
- context.grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
- }
- }
- getActivity().startActivity(Intent.createChooser(emailIntent, intentTitle));
+ findPreference(PREF_SEND_BUG_REPORT).setOnPreferenceClickListener(preference -> {
+ startActivity(new Intent(getActivity(), BugReportActivity.class));
return true;
});
}
- private void openInBrowser(String url) {
- try {
- Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- startActivity(myIntent);
- } catch (ActivityNotFoundException e) {
- Toast.makeText(getActivity(), R.string.pref_no_browser_found, Toast.LENGTH_LONG).show();
- Log.e(TAG, Log.getStackTraceString(e));
- }
- }
-
private void setupSearch() {
SearchPreference searchPreference = (SearchPreference) findPreference("searchPreference");
SearchConfiguration config = searchPreference.getSearchConfiguration();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java
index ac2436e25..440660942 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java
@@ -4,10 +4,10 @@ import android.app.TimePickerDialog;
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
import android.text.format.DateFormat;
import com.afollestad.materialdialogs.MaterialDialog;
import de.danoeh.antennapod.R;
@@ -31,6 +31,12 @@ public class NetworkPreferencesFragment extends PreferenceFragmentCompat {
}
@Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.network_pref);
+ }
+
+ @Override
public void onResume() {
super.onResume();
setUpdateIntervalText();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java
index e1714d4bd..1795dfc29 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java
@@ -4,10 +4,11 @@ import android.app.Activity;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
-import android.support.v7.preference.ListPreference;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import androidx.preference.ListPreference;
+import androidx.preference.PreferenceFragmentCompat;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MediaplayerActivity;
+import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
@@ -28,6 +29,12 @@ public class PlaybackPreferencesFragment extends PreferenceFragmentCompat {
}
@Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.playback_pref);
+ }
+
+ @Override
public void onResume() {
super.onResume();
checkSonicItemVisibility();
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java
index 37199ccf7..2b5310837 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java
@@ -1,25 +1,27 @@
-package de.danoeh.antennapod.activity;
+package de.danoeh.antennapod.fragment.preferences;
+import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.appcompat.app.AlertDialog;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
+import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ListView;
+import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.RadioButton;
-import android.widget.TextView;
-
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.adapter.StatisticsListAdapter;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.util.Converter;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
@@ -28,70 +30,63 @@ import io.reactivex.schedulers.Schedulers;
/**
* Displays the 'statistics' screen
*/
-public class StatisticsActivity extends AppCompatActivity
- implements AdapterView.OnItemClickListener {
-
- private static final String TAG = StatisticsActivity.class.getSimpleName();
+public class StatisticsFragment extends Fragment {
+ private static final String TAG = StatisticsFragment.class.getSimpleName();
private static final String PREF_NAME = "StatisticsActivityPrefs";
private static final String PREF_COUNT_ALL = "countAll";
private Disposable disposable;
- private TextView totalTimeTextView;
- private ListView feedStatisticsList;
+ private RecyclerView feedStatisticsList;
private ProgressBar progressBar;
private StatisticsListAdapter listAdapter;
private boolean countAll = false;
private SharedPreferences prefs;
@Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
+ public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- getSupportActionBar().setDisplayShowHomeEnabled(true);
- setContentView(R.layout.statistics_activity);
-
- prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
+ prefs = getContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
countAll = prefs.getBoolean(PREF_COUNT_ALL, false);
+ setHasOptionsMenu(true);
+ }
- totalTimeTextView = findViewById(R.id.total_time);
- feedStatisticsList = findViewById(R.id.statistics_list);
- progressBar = findViewById(R.id.progressBar);
- listAdapter = new StatisticsListAdapter(this);
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View root = inflater.inflate(R.layout.statistics_activity, container, false);
+ feedStatisticsList = root.findViewById(R.id.statistics_list);
+ progressBar = root.findViewById(R.id.progressBar);
+ listAdapter = new StatisticsListAdapter(getContext());
listAdapter.setCountAll(countAll);
+ feedStatisticsList.setLayoutManager(new LinearLayoutManager(getContext()));
feedStatisticsList.setAdapter(listAdapter);
- feedStatisticsList.setOnItemClickListener(this);
+ return root;
}
@Override
- public void onResume() {
- super.onResume();
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.statistics_label);
refreshStatistics();
}
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- MenuInflater inflater = getMenuInflater();
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.statistics, menu);
- return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- finish();
- return true;
- } else if (item.getItemId() == R.id.statistics_mode) {
+ if (item.getItemId() == R.id.statistics_mode) {
selectStatisticsMode();
return true;
- } else {
- return super.onOptionsItemSelected(item);
}
+ return super.onOptionsItemSelected(item);
}
private void selectStatisticsMode() {
- View contentView = View.inflate(this, R.layout.statistics_mode_select_dialog, null);
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ View contentView = View.inflate(getContext(), R.layout.statistics_mode_select_dialog, null);
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(contentView);
builder.setTitle(R.string.statistics_mode);
@@ -113,7 +108,6 @@ public class StatisticsActivity extends AppCompatActivity
private void refreshStatistics() {
progressBar.setVisibility(View.VISIBLE);
- totalTimeTextView.setVisibility(View.GONE);
feedStatisticsList.setVisibility(View.GONE);
loadStatistics();
}
@@ -126,28 +120,9 @@ public class StatisticsActivity extends AppCompatActivity
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
- totalTimeTextView.setText(Converter
- .shortLocalizedDuration(this, countAll ? result.totalTimeCountAll : result.totalTime));
- listAdapter.update(result.feedTime);
+ listAdapter.update(result);
progressBar.setVisibility(View.GONE);
- totalTimeTextView.setVisibility(View.VISIBLE);
feedStatisticsList.setVisibility(View.VISIBLE);
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- DBReader.StatisticsItem stats = listAdapter.getItem(position);
-
- AlertDialog.Builder dialog = new AlertDialog.Builder(this);
- dialog.setTitle(stats.feed.getTitle());
- dialog.setMessage(getString(R.string.statistics_details_dialog,
- countAll ? stats.episodesStartedIncludingMarked : stats.episodesStarted,
- stats.episodes,
- Converter.shortLocalizedDuration(this, countAll ?
- stats.timePlayedCountAll : stats.timePlayed),
- Converter.shortLocalizedDuration(this, stats.time)));
- dialog.setPositiveButton(android.R.string.ok, null);
- dialog.show();
- }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
index b4226b546..2c1590c47 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
@@ -4,6 +4,7 @@ import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -11,15 +12,19 @@ import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.FileProvider;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.FileProvider;
+import androidx.documentfile.provider.DocumentFile;
+import androidx.appcompat.app.AlertDialog;
+import androidx.preference.PreferenceFragmentCompat;
import android.util.Log;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.DirectoryChooserActivity;
import de.danoeh.antennapod.activity.ImportExportActivity;
import de.danoeh.antennapod.activity.OpmlImportFromPathActivity;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.asynctask.DocumentFileExportWorker;
import de.danoeh.antennapod.asynctask.ExportWorker;
import de.danoeh.antennapod.core.export.ExportWriter;
import de.danoeh.antennapod.core.export.html.HtmlWriter;
@@ -45,6 +50,12 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE };
private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 41;
+ private static final int CHOOSE_OPML_EXPORT_PATH = 1;
+ private static final String DEFAULT_OPML_OUTPUT_NAME = "antennapod-feeds.opml";
+ private static final String CONTENT_TYPE_OPML = "text/x-opml";
+ private static final int CHOOSE_HTML_EXPORT_PATH = 2;
+ private static final String DEFAULT_HTML_OUTPUT_NAME = "antennapod-feeds.html";
+ private static final String CONTENT_TYPE_HTML = "text/html";
private Disposable disposable;
@Override
@@ -54,11 +65,25 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
}
@Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.storage_pref);
+ }
+
+ @Override
public void onResume() {
super.onResume();
setDataFolderText();
}
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+
private void setupStorageScreen() {
final Activity activity = getActivity();
@@ -69,9 +94,16 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
}
);
findPreference(PREF_OPML_EXPORT).setOnPreferenceClickListener(
- preference -> export(new OpmlWriter()));
+ preference -> {
+ openOpmlExportPathPicker();
+ return true;
+ }
+ );
findPreference(PREF_HTML_EXPORT).setOnPreferenceClickListener(
- preference -> export(new HtmlWriter()));
+ preference -> {
+ openHtmlExportPathPicker();
+ return true;
+ });
findPreference(PREF_OPML_IMPORT).setOnPreferenceClickListener(
preference -> {
activity.startActivity(new Intent(activity, OpmlImportFromPathActivity.class));
@@ -129,52 +161,65 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
}
private boolean export(ExportWriter exportWriter) {
+ return export(exportWriter, null);
+ }
+
+ private boolean export(ExportWriter exportWriter, final Uri uri) {
Context context = getActivity();
final ProgressDialog progressDialog = new ProgressDialog(context);
progressDialog.setMessage(context.getString(R.string.exporting_label));
progressDialog.setIndeterminate(true);
progressDialog.show();
- final AlertDialog.Builder alert = new AlertDialog.Builder(context)
- .setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
- Observable<File> observable = new ExportWorker(exportWriter).exportObservable();
- disposable = observable.subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(output -> {
- alert.setTitle(R.string.export_success_title);
- String message = context.getString(R.string.export_success_sum, output.toString());
- alert.setMessage(message);
- alert.setPositiveButton(R.string.send_label, (dialog, which) -> {
+ if (uri == null) {
+ Observable<File> observable = new ExportWorker(exportWriter).exportObservable();
+ disposable = observable.subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(output -> {
Uri fileUri = FileProvider.getUriForFile(context.getApplicationContext(),
context.getString(R.string.provider_authority), output);
- Intent sendIntent = new Intent(Intent.ACTION_SEND);
- sendIntent.putExtra(Intent.EXTRA_SUBJECT,
- context.getResources().getText(R.string.opml_export_label));
- sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
- sendIntent.setType("text/plain");
- sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
- List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(sendIntent, PackageManager.MATCH_DEFAULT_ONLY);
- for (ResolveInfo resolveInfo : resInfoList) {
- String packageName = resolveInfo.activityInfo.packageName;
- context.grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
- }
- }
- context.startActivity(Intent.createChooser(sendIntent,
- context.getResources().getText(R.string.send_label)));
- });
- alert.create().show();
- }, error -> {
- alert.setTitle(R.string.export_error_label);
- alert.setMessage(error.getMessage());
- alert.show();
- }, progressDialog::dismiss);
+ showExportSuccessDialog(context.getString(R.string.export_success_sum, output.toString()), fileUri);
+ }, this::showExportErrorDialog, progressDialog::dismiss);
+ } else {
+ Observable<DocumentFile> observable = new DocumentFileExportWorker(exportWriter, context, uri).exportObservable();
+ disposable = observable.subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(output -> {
+ showExportSuccessDialog(context.getString(R.string.export_success_sum, output.getUri()), output.getUri());
+ }, this::showExportErrorDialog, progressDialog::dismiss);
+ }
return true;
}
- public void unsubscribeExportSubscription() {
- if (disposable != null) {
- disposable.dispose();
- }
+ private void showExportSuccessDialog(final String message, final Uri streamUri) {
+ final AlertDialog.Builder alert = new AlertDialog.Builder(getContext())
+ .setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
+ alert.setTitle(R.string.export_success_title);
+ alert.setMessage(message);
+ alert.setPositiveButton(R.string.send_label, (dialog, which) -> {
+ Intent sendIntent = new Intent(Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.opml_export_label));
+ sendIntent.putExtra(Intent.EXTRA_STREAM, streamUri);
+ sendIntent.setType("text/plain");
+ sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
+ List<ResolveInfo> resInfoList = getContext().getPackageManager()
+ .queryIntentActivities(sendIntent, PackageManager.MATCH_DEFAULT_ONLY);
+ for (ResolveInfo resolveInfo : resInfoList) {
+ String packageName = resolveInfo.activityInfo.packageName;
+ getContext().grantUriPermission(packageName, streamUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+ }
+ getContext().startActivity(Intent.createChooser(sendIntent, getString(R.string.send_label)));
+ });
+ alert.create().show();
+ }
+
+ private void showExportErrorDialog(final Throwable error) {
+ final AlertDialog.Builder alert = new AlertDialog.Builder(getContext())
+ .setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
+ alert.setTitle(R.string.export_error_label);
+ alert.setMessage(error.getMessage());
+ alert.show();
}
@SuppressLint("NewApi")
@@ -184,22 +229,22 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
File path;
- if(dir != null) {
+ if (dir != null) {
path = new File(dir);
} else {
path = getActivity().getExternalFilesDir(null);
}
String message = null;
- final Context context= getActivity().getApplicationContext();
- if(!path.exists()) {
+ final Context context = getActivity().getApplicationContext();
+ if (!path.exists()) {
message = String.format(context.getString(R.string.folder_does_not_exist_error), dir);
- } else if(!path.canRead()) {
+ } else if (!path.canRead()) {
message = String.format(context.getString(R.string.folder_not_readable_error), dir);
- } else if(!path.canWrite()) {
+ } else if (!path.canWrite()) {
message = String.format(context.getString(R.string.folder_not_writable_error), dir);
}
- if(message == null) {
+ if (message == null) {
Log.d(TAG, "Setting data folder: " + dir);
UserPreferences.setDataFolder(dir);
setDataFolderText();
@@ -210,6 +255,16 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
ab.show();
}
}
+
+ if (resultCode == Activity.RESULT_OK && requestCode == CHOOSE_OPML_EXPORT_PATH) {
+ Uri uri = data.getData();
+ export(new OpmlWriter(), uri);
+ }
+
+ if (resultCode == Activity.RESULT_OK && requestCode == CHOOSE_HTML_EXPORT_PATH) {
+ Uri uri = data.getData();
+ export(new HtmlWriter(), uri);
+ }
}
private void setDataFolderText() {
@@ -231,6 +286,50 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
activity.startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
}
+ private void openOpmlExportPathPicker() {
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ Intent intentPickAction = new Intent(Intent.ACTION_CREATE_DOCUMENT)
+ .addCategory(Intent.CATEGORY_OPENABLE)
+ .setType(CONTENT_TYPE_OPML)
+ .putExtra(Intent.EXTRA_TITLE, DEFAULT_OPML_OUTPUT_NAME);
+
+ // Creates an implicit intent to launch a file manager which lets
+ // the user choose a specific directory to export to.
+ try {
+ startActivityForResult(intentPickAction, CHOOSE_OPML_EXPORT_PATH);
+ return;
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "No activity found. Should never happen...");
+ }
+ }
+
+ // If we are using a SDK lower than API 21 or the implicit intent failed
+ // fallback to the legacy export process
+ export(new OpmlWriter());
+ }
+
+ private void openHtmlExportPathPicker() {
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ Intent intentPickAction = new Intent(Intent.ACTION_CREATE_DOCUMENT)
+ .addCategory(Intent.CATEGORY_OPENABLE)
+ .setType(CONTENT_TYPE_HTML)
+ .putExtra(Intent.EXTRA_TITLE, DEFAULT_HTML_OUTPUT_NAME);
+
+ // Creates an implicit intent to launch a file manager which lets
+ // the user choose a specific directory to export to.
+ try {
+ startActivityForResult(intentPickAction, CHOOSE_HTML_EXPORT_PATH);
+ return;
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "No activity found. Should never happen...");
+ }
+ }
+
+ // If we are using a SDK lower than API 21 or the implicit intent failed
+ // fallback to the legacy export process
+ export(new HtmlWriter());
+ }
+
private void showChooseDataFolderDialog() {
ChooseDataFolderDialog.showDialog(
getActivity(), new ChooseDataFolderDialog.RunnableWithString() {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
index e1d44f7d3..191999cf7 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
@@ -4,13 +4,14 @@ import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
-import android.support.design.widget.Snackbar;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.appcompat.app.AlertDialog;
+import androidx.preference.PreferenceFragmentCompat;
import android.widget.ListView;
import android.widget.Toast;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import org.apache.commons.lang3.ArrayUtils;
@@ -25,6 +26,12 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat {
setupInterfaceScreen();
}
+ @Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.user_interface_label);
+ }
+
private void setupInterfaceScreen() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
index 156657a00..fb2675db9 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
@@ -1,11 +1,11 @@
package de.danoeh.antennapod.menuhandler;
import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.support.annotation.Nullable;
+import android.os.Handler;
+import androidx.annotation.NonNull;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.fragment.app.Fragment;
import android.util.Log;
-import android.widget.Toast;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -18,7 +18,6 @@ import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.ShareUtils;
/**
@@ -51,35 +50,21 @@ public class FeedItemMenuHandler {
* @param mi An instance of MenuInterface that the method uses to change a
* MenuItem's visibility
* @param selectedItem The FeedItem for which the menu is supposed to be prepared
- * @param showExtendedMenu True if MenuItems that let the user share information about
- * the FeedItem and visit its website should be set visible. This
- * parameter should be set to false if the menu space is limited.
- * @param queueAccess Used for testing if the queue contains the selected item; only used for
- * move to top/bottom in the queue
* @return Returns true if selectedItem is not null.
*/
public static boolean onPrepareMenu(MenuInterface mi,
- FeedItem selectedItem,
- boolean showExtendedMenu,
- @Nullable LongList queueAccess) {
+ FeedItem selectedItem) {
if (selectedItem == null) {
return false;
}
boolean hasMedia = selectedItem.getMedia() != null;
boolean isPlaying = hasMedia && selectedItem.getState() == FeedItem.State.PLAYING;
- boolean keepSorted = UserPreferences.isQueueKeepSorted();
if (!isPlaying) {
mi.setItemVisibility(R.id.skip_episode_item, false);
}
boolean isInQueue = selectedItem.isTagged(FeedItem.TAG_QUEUE);
- if (queueAccess == null || queueAccess.size() == 0 || queueAccess.get(0) == selectedItem.getId() || keepSorted) {
- mi.setItemVisibility(R.id.move_to_top_item, false);
- }
- if (queueAccess == null || queueAccess.size() == 0 || queueAccess.get(queueAccess.size()-1) == selectedItem.getId() || keepSorted) {
- mi.setItemVisibility(R.id.move_to_bottom_item, false);
- }
if (!isInQueue) {
mi.setItemVisibility(R.id.remove_from_queue_item, false);
}
@@ -87,12 +72,12 @@ public class FeedItemMenuHandler {
mi.setItemVisibility(R.id.add_to_queue_item, false);
}
- if (!showExtendedMenu || !ShareUtils.hasLinkToShare(selectedItem)) {
+ if (!ShareUtils.hasLinkToShare(selectedItem)) {
mi.setItemVisibility(R.id.visit_website_item, false);
mi.setItemVisibility(R.id.share_link_item, false);
mi.setItemVisibility(R.id.share_link_with_position_item, false);
}
- if (!showExtendedMenu || !hasMedia || selectedItem.getMedia().getDownload_url() == null) {
+ if (!hasMedia || selectedItem.getMedia().getDownload_url() == null) {
mi.setItemVisibility(R.id.share_download_url_item, false);
mi.setItemVisibility(R.id.share_download_url_with_position_item, false);
}
@@ -104,6 +89,7 @@ public class FeedItemMenuHandler {
boolean fileDownloaded = hasMedia && selectedItem.getMedia().fileExists();
mi.setItemVisibility(R.id.share_file, fileDownloaded);
+ mi.setItemVisibility(R.id.remove_new_flag_item, selectedItem.isNew());
if (selectedItem.isPlayed()) {
mi.setItemVisibility(R.id.mark_read_item, false);
} else {
@@ -114,7 +100,7 @@ public class FeedItemMenuHandler {
mi.setItemVisibility(R.id.reset_position, false);
}
- if(!UserPreferences.isEnableAutodownload()) {
+ if(!UserPreferences.isEnableAutodownload() || fileDownloaded) {
mi.setItemVisibility(R.id.activate_auto_download, false);
mi.setItemVisibility(R.id.deactivate_auto_download, false);
} else if(selectedItem.getAutoDownload()) {
@@ -141,10 +127,8 @@ public class FeedItemMenuHandler {
*/
public static boolean onPrepareMenu(MenuInterface mi,
FeedItem selectedItem,
- boolean showExtendedMenu,
- LongList queueAccess,
int... excludeIds) {
- boolean rc = onPrepareMenu(mi, selectedItem, showExtendedMenu, queueAccess);
+ boolean rc = onPrepareMenu(mi, selectedItem);
if (rc && excludeIds != null) {
for (int id : excludeIds) {
mi.setItemVisibility(id, false);
@@ -153,8 +137,16 @@ public class FeedItemMenuHandler {
return rc;
}
- public static boolean onMenuItemClicked(Context context, int menuItemId,
- FeedItem selectedItem) {
+ /**
+ * Default menu handling for the given FeedItem.
+ *
+ * A Fragment instance, (rather than the more generic Context), is needed as a parameter
+ * to support some UI operations, e.g., creating a Snackbar.
+ */
+ public static boolean onMenuItemClicked(@NonNull Fragment fragment, int menuItemId,
+ @NonNull FeedItem selectedItem) {
+
+ @NonNull Context context = fragment.requireContext();
switch (menuItemId) {
case R.id.skip_episode_item:
IntentUtils.sendLocalBroadcast(context, PlaybackService.ACTION_SKIP_CURRENT_EPISODE);
@@ -162,6 +154,9 @@ public class FeedItemMenuHandler {
case R.id.remove_item:
DBWriter.deleteFeedMediaOfItem(context, selectedItem.getMedia().getId());
break;
+ case R.id.remove_new_flag_item:
+ removeNewFlagWithUndo(fragment, selectedItem);
+ break;
case R.id.mark_read_item:
selectedItem.setPlayed(true);
DBWriter.markItemPlayed(selectedItem, FeedItem.PLAYED, false);
@@ -216,14 +211,7 @@ public class FeedItemMenuHandler {
DBWriter.setFeedItemAutoDownload(selectedItem, false);
break;
case R.id.visit_website_item:
- Uri uri = Uri.parse(FeedItemUtil.getLinkWithFallback(selectedItem));
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- if(IntentUtils.isCallable(context, intent)) {
- context.startActivity(intent);
- } else {
- Toast.makeText(context, context.getString(R.string.download_error_malformed_url),
- Toast.LENGTH_SHORT).show();
- }
+ IntentUtils.openInBrowser(context, FeedItemUtil.getLinkWithFallback(selectedItem));
break;
case R.id.share_link_item:
ShareUtils.shareFeedItemLink(context, selectedItem);
@@ -249,4 +237,39 @@ public class FeedItemMenuHandler {
return true;
}
+ /**
+ * Remove new flag with additional UI logic to allow undo with Snackbar.
+ *
+ * Undo is useful for Remove new flag, given there is no UI to undo it otherwise
+ * ,i.e., there is (context) menu item for add new flag
+ */
+ public static void removeNewFlagWithUndo(@NonNull Fragment fragment, FeedItem item) {
+ if (item == null) {
+ return;
+ }
+
+ Log.d(TAG, "removeNewFlagWithUndo(" + item.getId() + ")");
+ // we're marking it as unplayed since the user didn't actually play it
+ // but they don't want it considered 'NEW' anymore
+ DBWriter.markItemPlayed(FeedItem.UNPLAYED, item.getId());
+
+ final Handler h = new Handler(fragment.requireContext().getMainLooper());
+ final Runnable r = () -> {
+ FeedMedia media = item.getMedia();
+ if (media != null && media.hasAlmostEnded() && UserPreferences.isAutoDelete()) {
+ DBWriter.deleteFeedMediaOfItem(fragment.requireContext(), media.getId());
+ }
+ };
+
+ Snackbar snackbar = Snackbar.make(fragment.getView(), fragment.getString(R.string.removed_new_flag_label),
+ Snackbar.LENGTH_LONG);
+ snackbar.setAction(fragment.getString(R.string.undo), v -> {
+ DBWriter.markItemPlayed(FeedItem.NEW, item.getId());
+ // don't forget to cancel the thing that's going to remove the media
+ h.removeCallbacks(r);
+ });
+ snackbar.show();
+ h.postDelayed(r, (int) Math.ceil(snackbar.getDuration() * 1.05f));
+ }
+
}
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
index 3949119fc..5d012168e 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
@@ -2,25 +2,17 @@ package de.danoeh.antennapod.menuhandler;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.Uri;
-import android.support.v7.app.AlertDialog;
-import android.text.TextUtils;
+import androidx.appcompat.app.AlertDialog;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-import android.widget.Toast;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.Set;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedItemFilter;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
@@ -86,14 +78,7 @@ public class FeedMenuHandler {
conDialog.createNewDialog().show();
break;
case R.id.visit_website_item:
- Uri uri = Uri.parse(selectedFeed.getLink());
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- if(IntentUtils.isCallable(context, intent)) {
- context.startActivity(intent);
- } else {
- Toast.makeText(context, context.getString(R.string.download_error_malformed_url),
- Toast.LENGTH_SHORT).show();
- }
+ IntentUtils.openInBrowser(context, selectedFeed.getLink());
break;
case R.id.share_link_item:
ShareUtils.shareFeedlink(context, selectedFeed);
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
index 7b9fcad9b..4a57726b1 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
@@ -4,7 +4,7 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Build;
-import android.support.v7.widget.SearchView;
+import androidx.appcompat.widget.SearchView;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.EditText;
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java b/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java
index b810cbfa6..007457c24 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java
@@ -4,8 +4,8 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Build;
-import android.support.v14.preference.SwitchPreference;
-import android.support.v7.preference.PreferenceViewHolder;
+import androidx.preference.SwitchPreference;
+import androidx.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java b/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java
index 50e76838c..a58986241 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.preferences;
import android.app.AlertDialog;
import android.content.Context;
-import android.support.v7.preference.Preference;
+import androidx.preference.Preference;
import android.text.InputFilter;
import android.util.AttributeSet;
import android.view.View;
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
index 4d6fbcb7b..6392d0535 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
@@ -3,8 +3,11 @@ package de.danoeh.antennapod.preferences;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
+
import de.danoeh.antennapod.BuildConfig;
+import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
public class PreferenceUpgrader {
@@ -21,7 +24,7 @@ public class PreferenceUpgrader {
if (oldVersion != newVersion) {
NotificationUtils.createChannels(context);
- UserPreferences.restartUpdateAlarm();
+ AutoUpdateManager.restartUpdateAlarm();
upgrade(oldVersion);
upgraderPrefs.edit().putInt(PREF_CONFIGURED_VERSION, newVersion).apply();
@@ -42,10 +45,8 @@ public class PreferenceUpgrader {
}
}
if (oldVersion < 1070300) {
- if (UserPreferences.getMediaPlayer().equals("builtin")) {
- prefs.edit().putString(UserPreferences.PREF_MEDIA_PLAYER,
- UserPreferences.PREF_MEDIA_PLAYER_EXOPLAYER).apply();
- }
+ prefs.edit().putString(UserPreferences.PREF_MEDIA_PLAYER,
+ UserPreferences.PREF_MEDIA_PLAYER_EXOPLAYER).apply();
if (prefs.getBoolean("prefEnableAutoDownloadOnMobile", false)) {
UserPreferences.setAllowMobileAutoDownload(true);
@@ -64,5 +65,13 @@ public class PreferenceUpgrader {
break;
}
}
+ if (oldVersion < 1070400) {
+ int theme = UserPreferences.getTheme();
+ if (theme == R.style.Theme_AntennaPod_Light) {
+ prefs.edit().putString(UserPreferences.PREF_THEME, "system").apply();
+ }
+
+ UserPreferences.setQueueLocked(false);
+ }
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java b/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java
index 03958508d..5fa6588d9 100644
--- a/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java
+++ b/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java
@@ -46,7 +46,7 @@ public class SPAUtil {
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(PREF_HAS_QUERIED_SP_APPS, true);
- editor.commit();
+ editor.apply();
return true;
} else {
@@ -63,7 +63,7 @@ public class SPAUtil {
SharedPreferences.Editor editor = PreferenceManager
.getDefaultSharedPreferences(c.getApplicationContext()).edit();
editor.putBoolean(PREF_HAS_QUERIED_SP_APPS, false);
- editor.commit();
+ editor.apply();
}
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java b/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java
index 8b886e699..1516c4eb6 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java
@@ -2,9 +2,9 @@ package de.danoeh.antennapod.view;
import android.content.Context;
import android.graphics.drawable.Drawable;
-import android.support.annotation.AttrRes;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.widget.RecyclerView;
+import androidx.annotation.AttrRes;
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.RecyclerView;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
diff --git a/app/src/main/java/de/danoeh/antennapod/view/PieChartView.java b/app/src/main/java/de/danoeh/antennapod/view/PieChartView.java
new file mode 100644
index 000000000..ada5401d8
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/view/PieChartView.java
@@ -0,0 +1,121 @@
+package de.danoeh.antennapod.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import androidx.annotation.NonNull;
+import androidx.appcompat.widget.AppCompatImageView;
+import io.reactivex.annotations.Nullable;
+
+public class PieChartView extends AppCompatImageView {
+ private PieChartDrawable drawable;
+
+ public PieChartView(Context context) {
+ super(context);
+ setup();
+ }
+
+ public PieChartView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ setup();
+ }
+
+ public PieChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setup();
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ private void setup() {
+ drawable = new PieChartDrawable();
+ setImageDrawable(drawable);
+ }
+
+ /**
+ * Set array od names, array of values and array of colors.
+ */
+ public void setData(float[] dataValues) {
+ drawable.dataValues = dataValues;
+ drawable.valueSum = 0;
+ for (float datum : dataValues) {
+ drawable.valueSum += datum;
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int width = getMeasuredWidth();
+ setMeasuredDimension(width, width / 2);
+ }
+
+ private static class PieChartDrawable extends Drawable {
+ private static final float MIN_DEGREES = 10f;
+ private static final float PADDING_DEGREES = 3f;
+ private static final float STROKE_SIZE = 15f;
+ private static final int[] COLOR_VALUES = new int[]{0xFF3775E6, 0xffe51c23, 0xffff9800, 0xff259b24, 0xff9c27b0,
+ 0xff0099c6, 0xffdd4477, 0xff66aa00, 0xffb82e2e, 0xff316395,
+ 0xff994499, 0xff22aa99, 0xffaaaa11, 0xff6633cc, 0xff0073e6};
+ private float[] dataValues;
+ private float valueSum;
+ private final Paint paint;
+
+ private PieChartDrawable() {
+ paint = new Paint();
+ paint.setFlags(Paint.ANTI_ALIAS_FLAG);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeJoin(Paint.Join.ROUND);
+ paint.setStrokeCap(Paint.Cap.ROUND);
+ paint.setStrokeWidth(STROKE_SIZE);
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ if (valueSum == 0) {
+ return;
+ }
+ float radius = getBounds().height() - STROKE_SIZE;
+ float center = getBounds().width() / 2.f;
+ RectF arcBounds = new RectF(center - radius, STROKE_SIZE, center + radius, STROKE_SIZE + radius * 2);
+
+ float startAngle = 180;
+ for (int i = 0; i < dataValues.length; i++) {
+ float datum = dataValues[i];
+ float sweepAngle = 180 * datum / valueSum;
+ if (sweepAngle < MIN_DEGREES) {
+ break;
+ }
+ paint.setColor(COLOR_VALUES[i % COLOR_VALUES.length]);
+ float padding = i == 0 ? PADDING_DEGREES / 2 : PADDING_DEGREES;
+ canvas.drawArc(arcBounds, startAngle + padding, sweepAngle - padding, false, paint);
+ startAngle = startAngle + sweepAngle;
+ }
+
+ paint.setColor(Color.GRAY);
+ float sweepAngle = 360 - startAngle - PADDING_DEGREES / 2;
+ if (sweepAngle > PADDING_DEGREES) {
+ canvas.drawArc(arcBounds, startAngle + PADDING_DEGREES, sweepAngle - PADDING_DEGREES, false, paint);
+ }
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java b/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java
index 45c3a35bd..5bd335532 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.view;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
/**
* AdapterDataObserver that relays all events to the method anythingChanged().
diff --git a/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java b/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java
index 7ce33e11f..f82309c4a 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.view;
import android.content.Context;
-import android.support.v7.widget.AppCompatImageView;
+import androidx.appcompat.widget.AppCompatImageView;
import android.util.AttributeSet;
/**
diff --git a/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java b/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java
deleted file mode 100644
index fe11a645c..000000000
--- a/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package de.danoeh.antennapod.viewmodel;
-
-import android.arch.lifecycle.ViewModel;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.storage.DBReader;
-import io.reactivex.Maybe;
-
-public class FeedSettingsViewModel extends ViewModel {
- private Feed feed;
-
- public Maybe<Feed> getFeed(long feedId) {
- if (feed == null) {
- return loadFeed(feedId);
- } else {
- return Maybe.just(feed);
- }
- }
-
- private Maybe<Feed> loadFeed(long feedId) {
- return Maybe.create(emitter -> {
- Feed feed = DBReader.getFeed(feedId);
- if (feed != null) {
- this.feed = feed;
- emitter.onSuccess(feed);
- } else {
- emitter.onComplete();
- }
- });
- }
-}
diff --git a/app/src/main/res/anim/card_flip_left_in.xml b/app/src/main/res/anim/card_flip_left_in.xml
new file mode 100644
index 000000000..0ffc85aec
--- /dev/null
+++ b/app/src/main/res/anim/card_flip_left_in.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Before rotating, immediately set the alpha to 0. -->
+ <objectAnimator
+ android:valueFrom="1.0"
+ android:valueTo="0.0"
+ android:propertyName="alpha"
+ android:duration="0" />
+
+ <!-- Rotate. -->
+ <objectAnimator
+ android:valueFrom="-180"
+ android:valueTo="0"
+ android:propertyName="rotationY"
+ android:interpolator="@android:interpolator/accelerate_decelerate"
+ android:duration="@integer/card_flip_time_full" />
+
+ <!-- Half-way through the rotation (see startOffset), set the alpha to 1. -->
+ <objectAnimator
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:propertyName="alpha"
+ android:startOffset="@integer/card_flip_time_half"
+ android:duration="1" />
+</set> \ No newline at end of file
diff --git a/app/src/main/res/anim/card_flip_left_out.xml b/app/src/main/res/anim/card_flip_left_out.xml
new file mode 100644
index 000000000..817f0d3fc
--- /dev/null
+++ b/app/src/main/res/anim/card_flip_left_out.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Rotate. -->
+ <objectAnimator
+ android:valueFrom="0"
+ android:valueTo="180"
+ android:propertyName="rotationY"
+ android:interpolator="@android:interpolator/accelerate_decelerate"
+ android:duration="@integer/card_flip_time_full" />
+
+ <!-- Half-way through the rotation (see startOffset), set the alpha to 0. -->
+ <objectAnimator
+ android:valueFrom="1.0"
+ android:valueTo="0.0"
+ android:propertyName="alpha"
+ android:startOffset="@integer/card_flip_time_half"
+ android:duration="1" />
+</set> \ No newline at end of file
diff --git a/app/src/main/res/anim/card_flip_right_in.xml b/app/src/main/res/anim/card_flip_right_in.xml
new file mode 100644
index 000000000..31ff1dde5
--- /dev/null
+++ b/app/src/main/res/anim/card_flip_right_in.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Before rotating, immediately set the alpha to 0. -->
+ <objectAnimator
+ android:valueFrom="1.0"
+ android:valueTo="0.0"
+ android:propertyName="alpha"
+ android:duration="0" />
+
+ <!-- Rotate. -->
+ <objectAnimator
+ android:valueFrom="180"
+ android:valueTo="0"
+ android:propertyName="rotationY"
+ android:interpolator="@android:interpolator/accelerate_decelerate"
+ android:duration="@integer/card_flip_time_full" />
+
+ <!-- Half-way through the rotation (see startOffset), set the alpha to 1. -->
+ <objectAnimator
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:propertyName="alpha"
+ android:startOffset="@integer/card_flip_time_half"
+ android:duration="1" />
+</set> \ No newline at end of file
diff --git a/app/src/main/res/anim/card_flip_right_out.xml b/app/src/main/res/anim/card_flip_right_out.xml
new file mode 100644
index 000000000..b57113fea
--- /dev/null
+++ b/app/src/main/res/anim/card_flip_right_out.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Rotate. -->
+ <objectAnimator
+ android:valueFrom="0"
+ android:valueTo="-180"
+ android:propertyName="rotationY"
+ android:interpolator="@android:interpolator/accelerate_decelerate"
+ android:duration="@integer/card_flip_time_full" />
+
+ <!-- Half-way through the rotation (see startOffset), set the alpha to 0. -->
+ <objectAnimator
+ android:valueFrom="1.0"
+ android:valueTo="0.0"
+ android:propertyName="alpha"
+ android:startOffset="@integer/card_flip_time_half"
+ android:duration="1" />
+</set> \ No newline at end of file
diff --git a/app/src/main/res/layout/addfeed.xml b/app/src/main/res/layout/addfeed.xml
index a7f7d9f12..99fa1c3f9 100644
--- a/app/src/main/res/layout/addfeed.xml
+++ b/app/src/main/res/layout/addfeed.xml
@@ -13,7 +13,7 @@
android:focusableInTouchMode="true"
android:padding="8dp">
- <android.support.v7.widget.CardView
+ <androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp"
@@ -53,7 +53,7 @@
</LinearLayout>
- </android.support.v7.widget.CardView>
+ </androidx.cardview.widget.CardView>
<fragment
android:id="@+id/quickFeedDiscovery"
@@ -62,7 +62,7 @@
android:layout_height="wrap_content"
android:layout_margin="8dp"/>
- <android.support.v7.widget.CardView
+ <androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp"
@@ -102,9 +102,9 @@
</LinearLayout>
- </android.support.v7.widget.CardView>
+ </androidx.cardview.widget.CardView>
- <android.support.v7.widget.CardView
+ <androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp"
@@ -170,7 +170,7 @@
</LinearLayout>
- </android.support.v7.widget.CardView>
+ </androidx.cardview.widget.CardView>
</LinearLayout>
diff --git a/app/src/main/res/layout/all_episodes_fragment.xml b/app/src/main/res/layout/all_episodes_fragment.xml
index 53636c2b6..9160998ac 100644
--- a/app/src/main/res/layout/all_episodes_fragment.xml
+++ b/app/src/main/res/layout/all_episodes_fragment.xml
@@ -17,7 +17,7 @@
android:visibility="gone"
tools:text="(i) Information" />
- <android.support.v7.widget.RecyclerView
+ <androidx.recyclerview.widget.RecyclerView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/app/src/main/res/layout/bug_report.xml b/app/src/main/res/layout/bug_report.xml
new file mode 100644
index 000000000..e97e85265
--- /dev/null
+++ b/app/src/main/res/layout/bug_report.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="16dp">
+ <Button
+ android:id="@+id/btn_open_bug_tracker"
+ android:text="@string/open_bug_tracker"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <Button
+ android:id="@+id/btn_copy_log"
+ android:text="@string/copy_to_clipboard"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <TextView
+ android:layout_marginTop="8dp"
+ android:id="@+id/crash_report_logs"
+ android:textIsSelectable="true"
+ android:textSize="12sp"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/checkbox_do_not_show_again.xml b/app/src/main/res/layout/checkbox_do_not_show_again.xml
new file mode 100644
index 000000000..15f26e8b4
--- /dev/null
+++ b/app/src/main/res/layout/checkbox_do_not_show_again.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp">
+
+ <CheckBox
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/checkbox_do_not_show_again"
+ android:text="@string/checkbox_do_not_show_again"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/choose_data_folder_dialog_entry.xml b/app/src/main/res/layout/choose_data_folder_dialog_entry.xml
index 9a216b36b..f4a2ff703 100644
--- a/app/src/main/res/layout/choose_data_folder_dialog_entry.xml
+++ b/app/src/main/res/layout/choose_data_folder_dialog_entry.xml
@@ -5,7 +5,7 @@
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="@dimen/diag_content_side_padding"
+ android:layout_margin="16dp"
android:background="?attr/selectableItemBackground">
<RadioButton
diff --git a/app/src/main/res/layout/downloaded_episodeslist_item.xml b/app/src/main/res/layout/downloaded_episodeslist_item.xml
index 65a08251f..3f8065466 100644
--- a/app/src/main/res/layout/downloaded_episodeslist_item.xml
+++ b/app/src/main/res/layout/downloaded_episodeslist_item.xml
@@ -17,7 +17,7 @@
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
android:contentDescription="@string/cover_label"
android:scaleType="centerCrop"
- tools:src="@drawable/ic_stat_antenna_default"
+ tools:src="@drawable/ic_antenna"
tools:background="@android:color/holo_green_dark"/>
diff --git a/app/src/main/res/layout/feedinfo.xml b/app/src/main/res/layout/feedinfo.xml
index 50061c4d8..416fc3aec 100644
--- a/app/src/main/res/layout/feedinfo.xml
+++ b/app/src/main/res/layout/feedinfo.xml
@@ -24,7 +24,7 @@
android:layout_height="wrap_content"
android:orientation="vertical">
- <android.support.v7.widget.GridLayout
+ <androidx.gridlayout.widget.GridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
@@ -107,7 +107,7 @@
tools:text="http://www.example.com/feed"
tools:background="@android:color/holo_green_dark"/>
- </android.support.v7.widget.GridLayout>
+ </androidx.gridlayout.widget.GridLayout>
<TextView
style="@style/AntennaPod.TextView.Heading"
diff --git a/app/src/main/res/layout/feeditem_fragment.xml b/app/src/main/res/layout/feeditem_fragment.xml
index 78c0b3b16..b047b3da0 100644
--- a/app/src/main/res/layout/feeditem_fragment.xml
+++ b/app/src/main/res/layout/feeditem_fragment.xml
@@ -36,7 +36,8 @@
android:layout_marginBottom="16dp"
android:contentDescription="@string/cover_label"
android:gravity="center_vertical"
- tools:src="@drawable/ic_stat_antenna_default"
+ android:foreground="?attr/selectableItemBackground"
+ tools:src="@drawable/ic_antenna"
tools:background="@android:color/holo_green_dark" />
<TextView
@@ -47,6 +48,7 @@
android:layout_alignTop="@id/imgvCover"
android:layout_toRightOf="@id/imgvCover"
android:layout_toEndOf="@id/imgvCover"
+ android:foreground="?attr/selectableItemBackground"
tools:text="Podcast title"
tools:background="@android:color/holo_green_dark" />
diff --git a/app/src/main/res/layout/feeditemlist_header.xml b/app/src/main/res/layout/feeditemlist_header.xml
index ba39307b0..596135d88 100644
--- a/app/src/main/res/layout/feeditemlist_header.xml
+++ b/app/src/main/res/layout/feeditemlist_header.xml
@@ -27,7 +27,7 @@
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:contentDescription="@string/cover_label"
- tools:src="@drawable/ic_stat_antenna_default"
+ tools:src="@drawable/ic_antenna"
tools:background="@android:color/holo_green_dark"/>
<ImageButton
@@ -37,11 +37,9 @@
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
- android:layout_marginLeft="8dp"
- android:layout_marginStart="8dp"
- android:layout_marginTop="16dp"
- android:layout_marginRight="16dp"
- android:layout_marginEnd="16dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="8dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/show_info_label"
android:src="@drawable/ic_info_white_24dp"
@@ -57,8 +55,6 @@
tools:background="@android:color/holo_green_dark"
android:layout_below="@+id/butShowInfo"
android:layout_marginBottom="16dp"
- android:layout_marginRight="16dp"
- android:layout_marginEnd="16dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
@@ -92,8 +88,8 @@
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
- android:layout_marginRight="8dp"
- android:layout_marginEnd="8dp"
+ android:layout_marginRight="16dp"
+ android:layout_marginEnd="16dp"
android:layout_toLeftOf="@id/butShowSettings"
android:layout_toStartOf="@id/butShowSettings"
android:layout_toRightOf="@id/imgvCover"
diff --git a/app/src/main/res/layout/gpodnet_podcast_listitem.xml b/app/src/main/res/layout/gpodnet_podcast_listitem.xml
index 27a8bbdca..6e02fa090 100644
--- a/app/src/main/res/layout/gpodnet_podcast_listitem.xml
+++ b/app/src/main/res/layout/gpodnet_podcast_listitem.xml
@@ -23,7 +23,7 @@
android:contentDescription="@string/cover_label"
android:cropToPadding="true"
android:scaleType="fitXY"
- tools:src="@drawable/ic_stat_antenna_default"
+ tools:src="@drawable/ic_antenna"
tools:background="@android:color/holo_green_dark" />
<LinearLayout
diff --git a/app/src/main/res/layout/itunes_podcast_listitem.xml b/app/src/main/res/layout/itunes_podcast_listitem.xml
index 4848563b1..b2411c5df 100644
--- a/app/src/main/res/layout/itunes_podcast_listitem.xml
+++ b/app/src/main/res/layout/itunes_podcast_listitem.xml
@@ -25,7 +25,7 @@
android:cropToPadding="true"
android:scaleType="fitXY"
tools:background="@android:color/holo_green_dark"
- tools:src="@drawable/ic_stat_antenna_default" />
+ tools:src="@drawable/ic_antenna" />
<LinearLayout
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/main.xml b/app/src/main/res/layout/main.xml
index 6cabcdff2..a226e482f 100644
--- a/app/src/main/res/layout/main.xml
+++ b/app/src/main/res/layout/main.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<android.support.v4.widget.DrawerLayout
+<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
@@ -19,7 +19,7 @@
tools:layout_height="64dp"
tools:background="@android:color/holo_green_light" />
- <android.support.v7.widget.Toolbar
+ <androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -48,4 +48,4 @@
<include layout="@layout/nav_list" />
-</android.support.v4.widget.DrawerLayout> \ No newline at end of file
+</androidx.drawerlayout.widget.DrawerLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/mediaplayerinfo_activity.xml b/app/src/main/res/layout/mediaplayerinfo_activity.xml
index a6427e985..b759b0092 100644
--- a/app/src/main/res/layout/mediaplayerinfo_activity.xml
+++ b/app/src/main/res/layout/mediaplayerinfo_activity.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<android.support.v4.widget.DrawerLayout
+<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
@@ -12,12 +12,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.design.widget.AppBarLayout
+ <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
- <android.support.v7.widget.Toolbar
+ <androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -37,7 +37,7 @@
app:strokeColor="?android:attr/textColorSecondary"
app:radius="4dp" />
- </android.support.design.widget.AppBarLayout>
+ </com.google.android.material.appbar.AppBarLayout>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
@@ -155,11 +155,11 @@
android:layout_marginTop="-8dp"
android:gravity="center"
android:text="30"
- android:textSize="10sp"
+ android:textSize="12sp"
android:textColor="?android:attr/textColorSecondary"
android:clickable="false"/>
- <Button
+ <ImageButton
android:id="@+id/butPlaybackSpeed"
android:layout_width="@dimen/audioplayer_playercontrols_length"
android:layout_height="@dimen/audioplayer_playercontrols_length"
@@ -167,13 +167,28 @@
android:layout_toStartOf="@id/butRev"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/set_playback_speed_label"
- android:src="?attr/av_fast_forward"
- android:textSize="@dimen/text_size_medium"
- android:textAllCaps="false"
- android:maxLines="1"
+ android:src="?attr/av_speed"
+ android:scaleType="fitCenter"
+ tools:src="@drawable/ic_playback_speed_white"
tools:visibility="gone"
tools:background="@android:color/holo_green_dark" />
+ <TextView
+ android:id="@+id/txtvPlaybackSpeed"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/butPlaybackSpeed"
+ android:layout_alignLeft="@id/butPlaybackSpeed"
+ android:layout_alignStart="@id/butPlaybackSpeed"
+ android:layout_alignRight="@id/butPlaybackSpeed"
+ android:layout_alignEnd="@id/butPlaybackSpeed"
+ android:layout_marginTop="-8dp"
+ android:gravity="center"
+ android:text="1.00"
+ android:textSize="12sp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:clickable="false"/>
+
<ImageButton
android:id="@+id/butCastDisconnect"
android:layout_width="@dimen/audioplayer_playercontrols_length"
@@ -216,7 +231,7 @@
android:layout_marginTop="-8dp"
android:gravity="center"
android:text="30"
- android:textSize="10sp"
+ android:textSize="12sp"
android:textColor="?android:attr/textColorSecondary"
android:clickable="false"/>
@@ -236,7 +251,7 @@
</LinearLayout>
- <android.support.v4.view.ViewPager
+ <androidx.viewpager.widget.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
@@ -257,4 +272,4 @@
<include layout="@layout/nav_list" />
-</android.support.v4.widget.DrawerLayout> \ No newline at end of file
+</androidx.drawerlayout.widget.DrawerLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/nav_feedlistitem.xml b/app/src/main/res/layout/nav_feedlistitem.xml
index 816870d1c..52833b3cd 100644
--- a/app/src/main/res/layout/nav_feedlistitem.xml
+++ b/app/src/main/res/layout/nav_feedlistitem.xml
@@ -25,7 +25,7 @@
android:scaleType="centerCrop"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
- tools:src="@drawable/ic_stat_antenna_default"
+ tools:src="@drawable/ic_antenna"
tools:background="@android:color/holo_green_dark"/>
<TextView
diff --git a/app/src/main/res/layout/pager_fragment.xml b/app/src/main/res/layout/pager_fragment.xml
index 54b711b1c..492743239 100644
--- a/app/src/main/res/layout/pager_fragment.xml
+++ b/app/src/main/res/layout/pager_fragment.xml
@@ -7,14 +7,14 @@
android:orientation="vertical">
- <android.support.design.widget.TabLayout
+ <com.google.android.material.tabs.TabLayout
android:id="@+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabGravity="fill"
app:tabMode="fixed" />
- <android.support.v4.view.ViewPager
+ <androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0px"
diff --git a/app/src/main/res/layout/queue_fragment.xml b/app/src/main/res/layout/queue_fragment.xml
index 85b0df58c..63da6a315 100644
--- a/app/src/main/res/layout/queue_fragment.xml
+++ b/app/src/main/res/layout/queue_fragment.xml
@@ -20,7 +20,7 @@
android:layout_below="@id/info_bar"
android:background="?android:attr/listDivider"/>
- <android.support.v7.widget.RecyclerView
+ <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/app/src/main/res/layout/queue_listitem.xml b/app/src/main/res/layout/queue_listitem.xml
index 6b41b68d5..1dcc34bce 100644
--- a/app/src/main/res/layout/queue_listitem.xml
+++ b/app/src/main/res/layout/queue_listitem.xml
@@ -51,7 +51,7 @@
android:layout_height="@dimen/thumbnail_length_queue_item"
android:layout_centerVertical="true"
android:contentDescription="@string/cover_label"
- tools:src="@drawable/ic_stat_antenna_default"
+ tools:src="@drawable/ic_antenna"
tools:background="@android:color/holo_green_dark"/>
</RelativeLayout>
diff --git a/app/src/main/res/layout/quick_feed_discovery.xml b/app/src/main/res/layout/quick_feed_discovery.xml
index ce5cfa65b..e791d19d7 100644
--- a/app/src/main/res/layout/quick_feed_discovery.xml
+++ b/app/src/main/res/layout/quick_feed_discovery.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<android.support.v7.widget.CardView
+<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
@@ -79,5 +79,5 @@
</LinearLayout>
-</android.support.v7.widget.CardView>
+</androidx.cardview.widget.CardView>
diff --git a/app/src/main/res/layout/searchlist_item.xml b/app/src/main/res/layout/searchlist_item.xml
index 50374c737..4a055fea9 100644
--- a/app/src/main/res/layout/searchlist_item.xml
+++ b/app/src/main/res/layout/searchlist_item.xml
@@ -18,7 +18,7 @@
android:layout_marginStart="@dimen/listitem_threeline_horizontalpadding"
android:contentDescription="@string/cover_label"
android:scaleType="centerCrop"
- tools:src="@drawable/ic_stat_antenna_default"
+ tools:src="@drawable/ic_antenna"
tools:background="@android:color/holo_green_dark"/>
<LinearLayout
diff --git a/app/src/main/res/layout/statistics_activity.xml b/app/src/main/res/layout/statistics_activity.xml
index 4a72dc7de..9d9cad438 100644
--- a/app/src/main/res/layout/statistics_activity.xml
+++ b/app/src/main/res/layout/statistics_activity.xml
@@ -1,41 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:paddingTop="8dp"
- android:paddingBottom="8dp">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/total_time_listened_to_podcasts"
- android:gravity="center_horizontal"/>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
<ProgressBar
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/progressBar"
- android:layout_gravity="center_horizontal"
- style="?android:attr/progressBarStyleLarge"/>
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/total_time"
- android:gravity="center_horizontal"
- android:textSize="45sp"/>
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/progressBar"
+ android:layout_gravity="center"/>
- <ListView
- android:id="@+id/statistics_list"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:choiceMode="singleChoice"
- android:clipToPadding="false"
- android:divider="@android:color/transparent"
- android:dividerHeight="0dp"
- android:paddingBottom="@dimen/list_vertical_padding"
- android:paddingTop="@dimen/list_vertical_padding"
- android:scrollbarStyle="outsideOverlay" />
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/statistics_list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:paddingBottom="@dimen/list_vertical_padding"
+ android:paddingTop="@dimen/list_vertical_padding"
+ android:scrollbarStyle="outsideOverlay"
+ tools:listitem="@layout/statistics_listitem"/>
-</LinearLayout>
+</FrameLayout>
diff --git a/app/src/main/res/layout/statistics_listitem.xml b/app/src/main/res/layout/statistics_listitem.xml
index b186add9e..6bd2a907e 100644
--- a/app/src/main/res/layout/statistics_listitem.xml
+++ b/app/src/main/res/layout/statistics_listitem.xml
@@ -3,63 +3,55 @@
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="@dimen/listitem_iconwithtext_height"
- android:paddingLeft="@dimen/listitem_threeline_verticalpadding"
- android:paddingStart="@dimen/listitem_threeline_verticalpadding"
- android:paddingRight="@dimen/listitem_threeline_verticalpadding"
- android:paddingEnd="@dimen/listitem_threeline_verticalpadding"
- tools:background="@android:color/darker_gray">
+ android:layout_height="wrap_content"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:background="?android:attr/selectableItemBackground">
<ImageView
- android:id="@+id/imgvCover"
- android:contentDescription="@string/cover_label"
- android:layout_width="@dimen/thumbnail_length_navlist"
- android:layout_height="@dimen/thumbnail_length_navlist"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_centerVertical="true"
- android:adjustViewBounds="true"
- android:cropToPadding="true"
- android:scaleType="centerCrop"
- android:layout_marginTop="4dp"
- android:layout_marginBottom="4dp"
- tools:src="@drawable/ic_stat_antenna_default"
- tools:background="@android:color/holo_green_dark"/>
+ android:id="@+id/imgvCover"
+ android:contentDescription="@string/cover_label"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:adjustViewBounds="true"
+ android:cropToPadding="true"
+ android:scaleType="centerCrop"
+ tools:src="@drawable/ic_antenna"
+ tools:background="@android:color/holo_green_dark"/>
<TextView
- android:id="@+id/txtvTime"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/list_vertical_padding"
- android:layout_marginStart="@dimen/list_vertical_padding"
- android:lines="1"
- android:textColor="?android:attr/textColorTertiary"
- android:textSize="@dimen/text_size_navdrawer"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"
- android:layout_centerVertical="true"
- tools:text="23"
- tools:background="@android:color/holo_green_dark"/>
+ android:id="@+id/txtvTitle"
+ android:lines="1"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="16sp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
+ android:layout_toRightOf="@id/imgvCover"
+ android:layout_alignTop="@id/imgvCover"
+ android:layout_alignWithParentIfMissing="true"
+ tools:text="Feed title"/>
<TextView
- android:id="@+id/txtvTitle"
- android:lines="1"
- android:ellipsize="end"
- android:singleLine="true"
- android:layout_centerVertical="true"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="@dimen/text_size_navdrawer"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/listitem_iconwithtext_textleftpadding"
- android:layout_marginStart="@dimen/listitem_iconwithtext_textleftpadding"
- android:layout_toRightOf="@id/imgvCover"
- android:layout_toEndOf="@id/imgvCover"
- android:layout_toLeftOf="@id/txtvTime"
- android:layout_toStartOf="@id/txtvTime"
- android:layout_alignWithParentIfMissing="true"
- tools:text="Navigation feed item title"
- tools:background="@android:color/holo_green_dark"/>
-
+ android:id="@+id/txtvTime"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:lines="1"
+ android:textColor="?android:attr/textColorTertiary"
+ android:textSize="14sp"
+ android:layout_toEndOf="@+id/imgvCover"
+ android:layout_toRightOf="@+id/imgvCover"
+ android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
+ android:layout_below="@+id/txtvTitle"
+ tools:text="23 hours"/>
</RelativeLayout>
diff --git a/app/src/main/res/layout/statistics_listitem_total_time.xml b/app/src/main/res/layout/statistics_listitem_total_time.xml
new file mode 100644
index 000000000..2e0ae54d6
--- /dev/null
+++ b/app/src/main/res/layout/statistics_listitem_total_time.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="16dp">
+
+ <de.danoeh.antennapod.view.PieChartView
+ android:id="@+id/pie_chart"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/total_time_description"
+ android:textSize="14sp"
+ android:text="@string/total_time_listened_to_podcasts"
+ android:gravity="center_horizontal"
+ android:layout_above="@+id/total_time"/>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/total_time"
+ android:textColor="?android:attr/textColorPrimary"
+ android:gravity="center_horizontal"
+ android:textSize="28sp"
+ android:layout_marginBottom="16dp"
+ android:layout_alignBottom="@id/pie_chart"
+ tools:text="10.0 hours"/>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_marginTop="16dp"
+ android:background="?android:attr/dividerVertical"
+ android:layout_below="@+id/pie_chart"/>
+
+</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/menu/allepisodes_context.xml b/app/src/main/res/menu/allepisodes_context.xml
deleted file mode 100644
index 907bc9334..000000000
--- a/app/src/main/res/menu/allepisodes_context.xml
+++ /dev/null
@@ -1,86 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item
- android:id="@id/skip_episode_item"
- android:menuCategory="container"
- android:title="@string/skip_episode_label" />
-
-
- <item
- android:id="@+id/remove_new_flag_item"
- android:menuCategory="container"
- android:title="@string/remove_new_flag_label" />
-
- <item
- android:id="@+id/mark_read_item"
- android:menuCategory="container"
- android:title="@string/mark_read_label" />
- <item
- android:id="@+id/mark_unread_item"
- android:menuCategory="container"
- android:title="@string/mark_unread_label" />
-
- <item
- android:id="@+id/add_to_queue_item"
- android:menuCategory="container"
- android:title="@string/add_to_queue_label" />
- <item
- android:id="@+id/remove_from_queue_item"
- android:menuCategory="container"
- android:title="@string/remove_from_queue_label" />
- <item
- android:id="@+id/add_to_favorites_item"
- android:menuCategory="container"
- android:title="@string/add_to_favorite_label" />
- <item
- android:id="@+id/remove_from_favorites_item"
- android:menuCategory="container"
- android:title="@string/remove_from_favorite_label" />
- <item
- android:id="@+id/reset_position"
- android:menuCategory="container"
- android:title="@string/reset_position" />
-
- <item
- android:id="@+id/activate_auto_download"
- android:menuCategory="container"
- android:title="@string/activate_auto_download" />
- <item
- android:id="@+id/deactivate_auto_download"
- android:menuCategory="container"
- android:title="@string/deactivate_auto_download" />
-
- <item
- android:id="@+id/visit_website_item"
- android:menuCategory="container"
- android:title="@string/visit_website_label" />
- <item
- android:id="@+id/share_item"
- android:menuCategory="container"
- android:title="@string/share_label">
- <menu>
- <item
- android:id="@+id/share_link_item"
- android:menuCategory="container"
- android:title="@string/share_link_label" />
- <item
- android:id="@+id/share_link_with_position_item"
- android:menuCategory="container"
- android:title="@string/share_link_with_position_label" />
- <item
- android:id="@+id/share_download_url_item"
- android:menuCategory="container"
- android:title="@string/share_item_url_label" />
- <item
- android:id="@+id/share_download_url_with_position_item"
- android:menuCategory="container"
- android:title="@string/share_item_url_with_position_label" />
- <item
- android:id="@+id/share_file"
- android:menuCategory="container"
- android:title="@string/share_file_label" />
- </menu>
- </item>
-</menu> \ No newline at end of file
diff --git a/app/src/main/res/menu/episodes.xml b/app/src/main/res/menu/episodes.xml
index 1e1aa8f56..7398754e5 100644
--- a/app/src/main/res/menu/episodes.xml
+++ b/app/src/main/res/menu/episodes.xml
@@ -7,7 +7,7 @@
android:id="@+id/action_search"
android:icon="?attr/action_search"
custom:showAsAction="collapseActionView|ifRoom"
- custom:actionViewClass="android.support.v7.widget.SearchView"
+ custom:actionViewClass="androidx.appcompat.widget.SearchView"
android:title="@string/search_label"/>
<item
diff --git a/app/src/main/res/menu/feedinfo.xml b/app/src/main/res/menu/feedinfo.xml
index 300068007..f20d679a5 100644
--- a/app/src/main/res/menu/feedinfo.xml
+++ b/app/src/main/res/menu/feedinfo.xml
@@ -11,7 +11,7 @@
<item
android:id="@+id/share_link_item"
custom:showAsAction="collapseActionView"
- android:title="@string/share_link_label">
+ android:title="@string/share_website_url_label">
</item>
<item
android:id="@+id/share_download_url_item"
diff --git a/app/src/main/res/menu/feeditem_options.xml b/app/src/main/res/menu/feeditem_options.xml
index 0801b79a1..e415ff85a 100644
--- a/app/src/main/res/menu/feeditem_options.xml
+++ b/app/src/main/res/menu/feeditem_options.xml
@@ -9,6 +9,11 @@
</item>
<item
+ android:id="@+id/remove_new_flag_item"
+ custom:showAsAction="collapseActionView"
+ android:title="@string/remove_new_flag_label" />
+
+ <item
android:id="@+id/mark_read_item"
custom:showAsAction="collapseActionView"
android:title="@string/mark_read_label">
diff --git a/app/src/main/res/menu/feeditemlist_context.xml b/app/src/main/res/menu/feeditemlist_context.xml
index df13cb027..6e4966206 100644
--- a/app/src/main/res/menu/feeditemlist_context.xml
+++ b/app/src/main/res/menu/feeditemlist_context.xml
@@ -8,6 +8,11 @@
android:title="@string/skip_episode_label" />
<item
+ android:id="@+id/remove_new_flag_item"
+ android:menuCategory="container"
+ android:title="@string/remove_new_flag_label" />
+
+ <item
android:id="@+id/mark_read_item"
android:menuCategory="container"
android:title="@string/mark_read_label" />
diff --git a/app/src/main/res/menu/feedlist.xml b/app/src/main/res/menu/feedlist.xml
index 0cc8addfe..fdd0e01bc 100644
--- a/app/src/main/res/menu/feedlist.xml
+++ b/app/src/main/res/menu/feedlist.xml
@@ -34,7 +34,7 @@
android:id="@+id/action_search"
android:icon="?attr/action_search"
custom:showAsAction="always|collapseActionView"
- custom:actionViewClass="android.support.v7.widget.SearchView"
+ custom:actionViewClass="androidx.appcompat.widget.SearchView"
android:title="@string/search_label"/>
<item
@@ -49,7 +49,7 @@
android:id="@+id/share_link_item"
android:menuCategory="container"
custom:showAsAction="collapseActionView"
- android:title="@string/share_link_label">
+ android:title="@string/share_website_url_label">
</item>
<item
android:id="@+id/share_download_url_item"
diff --git a/app/src/main/res/menu/gpodder_podcasts.xml b/app/src/main/res/menu/gpodder_podcasts.xml
index 88fa36a4a..93d93157a 100644
--- a/app/src/main/res/menu/gpodder_podcasts.xml
+++ b/app/src/main/res/menu/gpodder_podcasts.xml
@@ -7,7 +7,7 @@
android:id="@+id/action_search"
android:icon="?attr/action_search"
custom:showAsAction="collapseActionView|ifRoom"
- custom:actionViewClass="android.support.v7.widget.SearchView"
+ custom:actionViewClass="androidx.appcompat.widget.SearchView"
android:title="@string/search_label"/>
</menu>
diff --git a/app/src/main/res/menu/itunes_search.xml b/app/src/main/res/menu/itunes_search.xml
index 88fa36a4a..93d93157a 100644
--- a/app/src/main/res/menu/itunes_search.xml
+++ b/app/src/main/res/menu/itunes_search.xml
@@ -7,7 +7,7 @@
android:id="@+id/action_search"
android:icon="?attr/action_search"
custom:showAsAction="collapseActionView|ifRoom"
- custom:actionViewClass="android.support.v7.widget.SearchView"
+ custom:actionViewClass="androidx.appcompat.widget.SearchView"
android:title="@string/search_label"/>
</menu>
diff --git a/app/src/main/res/menu/mediaplayer.xml b/app/src/main/res/menu/mediaplayer.xml
index 44d511ee4..055951760 100644
--- a/app/src/main/res/menu/mediaplayer.xml
+++ b/app/src/main/res/menu/mediaplayer.xml
@@ -35,6 +35,14 @@
</item>
<item
+ android:id="@+id/open_feed_item"
+ android:icon="?attr/feed"
+ custom:showAsAction="collapseActionView"
+ android:title="@string/open_podcast"
+ android:visible="false">
+ </item>
+
+ <item
android:id="@+id/visit_website_item"
android:icon="?attr/location_web_site"
custom:showAsAction="collapseActionView"
diff --git a/app/src/main/res/menu/queue.xml b/app/src/main/res/menu/queue.xml
index a4e511eb8..b86ad5d63 100644
--- a/app/src/main/res/menu/queue.xml
+++ b/app/src/main/res/menu/queue.xml
@@ -20,7 +20,7 @@
android:id="@+id/action_search"
android:icon="?attr/action_search"
custom:showAsAction="collapseActionView|ifRoom"
- custom:actionViewClass="android.support.v7.widget.SearchView"
+ custom:actionViewClass="androidx.appcompat.widget.SearchView"
android:title="@string/search_label"/>
<item
diff --git a/app/src/main/res/menu/queue_context.xml b/app/src/main/res/menu/queue_context.xml
index e1c3e6216..522e712e2 100644
--- a/app/src/main/res/menu/queue_context.xml
+++ b/app/src/main/res/menu/queue_context.xml
@@ -11,77 +11,6 @@
android:id="@+id/move_to_bottom_item"
android:menuCategory="container"
android:title="@string/move_to_bottom_label" />
+ <!-- rest of the menu items can be found in the generic feeditemlist_context.xml -->
- <item
- android:id="@+id/mark_read_item"
- android:menuCategory="container"
- android:title="@string/mark_read_label" />
-
- <item
- android:id="@+id/mark_unread_item"
- android:menuCategory="container"
- android:title="@string/mark_unread_label" />
-
- <item
- android:id="@+id/remove_from_queue_item"
- android:menuCategory="container"
- android:title="@string/remove_from_queue_label" />
- <item
- android:id="@+id/remove_item"
- android:menuCategory="container"
- android:title="@string/delete_label" />
-
- <item
- android:id="@+id/add_to_favorites_item"
- android:menuCategory="container"
- android:title="@string/add_to_favorite_label" />
- <item
- android:id="@+id/remove_from_favorites_item"
- android:menuCategory="container"
- android:title="@string/remove_from_favorite_label" />
- <item
- android:id="@+id/reset_position"
- android:menuCategory="container"
- android:title="@string/reset_position" />
-
- <item
- android:id="@+id/activate_auto_download"
- android:menuCategory="container"
- android:title="@string/activate_auto_download" />
- <item
- android:id="@+id/deactivate_auto_download"
- android:menuCategory="container"
- android:title="@string/deactivate_auto_download" />
-
- <item
- android:id="@+id/visit_website_item"
- android:menuCategory="container"
- android:title="@string/visit_website_label" />
- <item
- android:id="@+id/share_item"
- android:menuCategory="container"
- android:title="@string/share_label">
- <menu>
- <item
- android:id="@+id/share_link_item"
- android:menuCategory="container"
- android:title="@string/share_link_label" />
- <item
- android:id="@+id/share_link_with_position_item"
- android:menuCategory="container"
- android:title="@string/share_link_with_position_label" />
- <item
- android:id="@+id/share_download_url_item"
- android:menuCategory="container"
- android:title="@string/share_item_url_label" />
- <item
- android:id="@+id/share_download_url_with_position_item"
- android:menuCategory="container"
- android:title="@string/share_item_url_with_position_label" />
- <item
- android:id="@+id/share_file"
- android:menuCategory="container"
- android:title="@string/share_file_label" />
- </menu>
- </item>
</menu> \ No newline at end of file
diff --git a/app/src/main/res/menu/subscriptions.xml b/app/src/main/res/menu/subscriptions.xml
index f39e0ac97..1780592d5 100644
--- a/app/src/main/res/menu/subscriptions.xml
+++ b/app/src/main/res/menu/subscriptions.xml
@@ -3,6 +3,13 @@
xmlns:custom="http://schemas.android.com/apk/res-auto">
<item
+ android:id="@+id/refresh_item"
+ android:title="@string/refresh_label"
+ android:menuCategory="container"
+ custom:showAsAction="always"
+ android:icon="?attr/navigation_refresh"/>
+
+ <item
android:id="@+id/subscription_num_columns"
android:title="@string/subscription_num_columns"
custom:showAsAction="never">
diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml
new file mode 100644
index 000000000..8c444ee8b
--- /dev/null
+++ b/app/src/main/res/values/integers.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="card_flip_time_full">400</integer>
+ <integer name="card_flip_time_half">200</integer>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 6c1e470c0..37707ead6 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -43,16 +43,14 @@
<Preference
android:key="prefFaq"
android:title="@string/pref_faq"
- android:icon="?attr/ic_question_answer" />
-
+ android:icon="?attr/ic_questionmark" />
<Preference
- android:key="prefKnownIssues"
- android:title="@string/pref_known_issues"
- android:icon="?attr/ic_known_issues" />
+ android:key="prefViewMailingList"
+ android:title="@string/view_mailing_list"
+ android:icon="?attr/ic_chat" />
<Preference
- android:key="prefSendCrashReport"
- android:title="@string/crash_report_title"
- android:summary="@string/crash_report_sum"
+ android:key="prefSendBugReport"
+ android:title="@string/bug_report_title"
android:icon="?attr/ic_bug" />
<Preference
android:key="prefAbout"
diff --git a/app/src/main/res/xml/preferences_user_interface.xml b/app/src/main/res/xml/preferences_user_interface.xml
index 1d970a5f7..c48e9adc8 100644
--- a/app/src/main/res/xml/preferences_user_interface.xml
+++ b/app/src/main/res/xml/preferences_user_interface.xml
@@ -10,7 +10,7 @@
android:title="@string/pref_set_theme_title"
android:key="prefTheme"
android:summary="@string/pref_set_theme_sum"
- android:defaultValue="0"
+ android:defaultValue="system"
app:useStockLayout="true"/>
<Preference
android:key="prefHiddenDrawerItems"
diff --git a/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java b/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java
index 87304b3d6..912571a7e 100644
--- a/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java
+++ b/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java
@@ -4,9 +4,9 @@ import android.content.SharedPreferences;
import android.media.AudioManager;
import android.os.Bundle;
import android.preference.PreferenceManager;
-import android.support.annotation.CallSuper;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.CallSuper;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -29,17 +29,34 @@ public abstract class CastEnabledActivity extends AppCompatActivity
implements SharedPreferences.OnSharedPreferenceChangeListener {
public static final String TAG = "CastEnabledActivity";
- protected CastManager castManager;
- protected SwitchableMediaRouteActionProvider mediaRouteActionProvider;
+ private CastConsumer castConsumer;
+ private CastManager castManager;
+
+ private SwitchableMediaRouteActionProvider mediaRouteActionProvider;
private final CastButtonVisibilityManager castButtonVisibilityManager = new CastButtonVisibilityManager();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ if (!CastManager.isInitialized()) {
+ return;
+ }
+
PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).
registerOnSharedPreferenceChangeListener(this);
+ castConsumer = new DefaultCastConsumer() {
+ @Override
+ public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) {
+ onCastConnectionChanged(true);
+ }
+
+ @Override
+ public void onDisconnected() {
+ onCastConnectionChanged(false);
+ }
+ };
castManager = CastManager.getInstance();
castManager.addCastConsumer(castConsumer);
castButtonVisibilityManager.setPrefEnabled(UserPreferences.isCastEnabled());
@@ -48,6 +65,10 @@ public abstract class CastEnabledActivity extends AppCompatActivity
@Override
protected void onDestroy() {
+ if (!CastManager.isInitialized()) {
+ super.onDestroy();
+ return;
+ }
PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
.unregisterOnSharedPreferenceChangeListener(this);
castManager.removeCastConsumer(castConsumer);
@@ -58,6 +79,9 @@ public abstract class CastEnabledActivity extends AppCompatActivity
@CallSuper
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
+ if (!CastManager.isInitialized()) {
+ return true;
+ }
getMenuInflater().inflate(R.menu.cast_enabled, menu);
castButtonVisibilityManager.setMenu(menu);
return true;
@@ -67,6 +91,10 @@ public abstract class CastEnabledActivity extends AppCompatActivity
@CallSuper
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
+ if (!CastManager.isInitialized()) {
+ return true;
+ }
+
MenuItem mediaRouteButton = menu.findItem(R.id.media_route_menu_item);
if (mediaRouteButton == null) {
Log.wtf(TAG, "MediaRoute item could not be found on the menu!", new Exception());
@@ -83,15 +111,22 @@ public abstract class CastEnabledActivity extends AppCompatActivity
@Override
protected void onResume() {
super.onResume();
+ if (!CastManager.isInitialized()) {
+ return;
+ }
castButtonVisibilityManager.setResumed(true);
}
@Override
protected void onPause() {
super.onPause();
+ if (!CastManager.isInitialized()) {
+ return;
+ }
castButtonVisibilityManager.setResumed(false);
}
+
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (UserPreferences.PREF_CAST_ENABLED.equals(key)) {
@@ -105,18 +140,6 @@ public abstract class CastEnabledActivity extends AppCompatActivity
}
}
- CastConsumer castConsumer = new DefaultCastConsumer() {
- @Override
- public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) {
- onCastConnectionChanged(true);
- }
-
- @Override
- public void onDisconnected() {
- onCastConnectionChanged(false);
- }
- };
-
private void onCastConnectionChanged(boolean connected) {
if (connected) {
castButtonVisibilityManager.onConnected();
@@ -133,6 +156,9 @@ public abstract class CastEnabledActivity extends AppCompatActivity
* @param showAsAction refer to {@link MenuItem#setShowAsAction(int)}
*/
public final void requestCastButton(int showAsAction) {
+ if (!CastManager.isInitialized()) {
+ return;
+ }
castButtonVisibilityManager.requestCastButton(showAsAction);
}
diff --git a/app/src/play/java/de/danoeh/antennapod/config/CastCallbackImpl.java b/app/src/play/java/de/danoeh/antennapod/config/CastCallbackImpl.java
index 916b13a38..2a879c62d 100644
--- a/app/src/play/java/de/danoeh/antennapod/config/CastCallbackImpl.java
+++ b/app/src/play/java/de/danoeh/antennapod/config/CastCallbackImpl.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.config;
-import android.support.annotation.NonNull;
-import android.support.v7.app.MediaRouteControllerDialogFragment;
-import android.support.v7.app.MediaRouteDialogFactory;
+import androidx.annotation.NonNull;
+import androidx.mediarouter.app.MediaRouteControllerDialogFragment;
+import androidx.mediarouter.app.MediaRouteDialogFactory;
import de.danoeh.antennapod.core.CastCallbacks;
import de.danoeh.antennapod.fragment.CustomMRControllerDialogFragment;
diff --git a/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java b/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java
index ae8e20575..bf5b85c82 100644
--- a/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java
+++ b/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java
@@ -8,19 +8,19 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
-import android.support.v4.util.Pair;
-import android.support.v4.view.MarginLayoutParamsCompat;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v7.app.MediaRouteControllerDialog;
-import android.support.v7.graphics.Palette;
-import android.support.v7.media.MediaRouter;
-import android.support.v7.widget.AppCompatImageView;
+import androidx.core.util.Pair;
+import androidx.core.view.MarginLayoutParamsCompat;
+import androidx.core.view.accessibility.AccessibilityEventCompat;
+import androidx.mediarouter.app.MediaRouteControllerDialog;
+import androidx.palette.graphics.Palette;
+import androidx.mediarouter.media.MediaRouter;
+import androidx.appcompat.widget.AppCompatImageView;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
@@ -311,9 +311,7 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
AccessibilityEventCompat.TYPE_ANNOUNCEMENT);
event.setPackageName(getContext().getPackageName());
event.setClassName(getClass().getName());
- int resId = isPlaying ?
- android.support.v7.mediarouter.R.string.mr_controller_pause :
- android.support.v7.mediarouter.R.string.mr_controller_play;
+ int resId = isPlaying ? R.string.mr_controller_pause : R.string.mr_controller_play;
event.getText().add(getContext().getString(resId));
accessibilityManager.sendAccessibilityEvent(event);
}
@@ -359,17 +357,17 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
if (route.getPresentationDisplay() != null &&
route.getPresentationDisplay().getDisplayId() != MediaRouter.RouteInfo.PRESENTATION_DISPLAY_ID_NONE) {
// The user is currently casting screen.
- titleView.setText(android.support.v7.mediarouter.R.string.mr_controller_casting_screen);
+ titleView.setText(R.string.mr_controller_casting_screen);
showTitle = true;
} else if (state == null || state.getState() == PlaybackStateCompat.STATE_NONE) {
// Show "No media selected" as we don't yet know the playback state.
// (Only exception is bluetooth where we don't show anything.)
if (!route.isBluetooth()) {
- titleView.setText(android.support.v7.mediarouter.R.string.mr_controller_no_media_selected);
+ titleView.setText(R.string.mr_controller_no_media_selected);
showTitle = true;
}
} else if (!hasTitle && !hasSubtitle) {
- titleView.setText(android.support.v7.mediarouter.R.string.mr_controller_no_info_available);
+ titleView.setText(R.string.mr_controller_no_info_available);
showTitle = true;
} else {
if (hasTitle) {
@@ -435,16 +433,12 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
| PlaybackStateCompat.ACTION_PLAY_PAUSE)) != 0;
if (isPlaying && supportsPause) {
playPauseButton.setVisibility(View.VISIBLE);
- playPauseButton.setImageResource(getThemeResource(getContext(),
- android.support.v7.mediarouter.R.attr.mediaRoutePauseDrawable));
- playPauseButton.setContentDescription(getContext().getResources()
- .getText(android.support.v7.mediarouter.R.string.mr_controller_pause));
+ playPauseButton.setImageResource(getThemeResource(getContext(), R.attr.mediaRoutePauseDrawable));
+ playPauseButton.setContentDescription(getContext().getResources().getText(R.string.mr_controller_pause));
} else if (!isPlaying && supportsPlay) {
playPauseButton.setVisibility(View.VISIBLE);
- playPauseButton.setImageResource(getThemeResource(getContext(),
- android.support.v7.mediarouter.R.attr.mediaRoutePlayDrawable));
- playPauseButton.setContentDescription(getContext().getResources()
- .getText(android.support.v7.mediarouter.R.string.mr_controller_play));
+ playPauseButton.setImageResource(getThemeResource(getContext(), R.attr.mediaRoutePlayDrawable));
+ playPauseButton.setContentDescription(getContext().getResources().getText(R.string.mr_controller_play));
} else {
playPauseButton.setVisibility(View.GONE);
}
diff --git a/app/src/play/java/de/danoeh/antennapod/fragment/CustomMRControllerDialogFragment.java b/app/src/play/java/de/danoeh/antennapod/fragment/CustomMRControllerDialogFragment.java
index a960ec998..dad7b0bfd 100644
--- a/app/src/play/java/de/danoeh/antennapod/fragment/CustomMRControllerDialogFragment.java
+++ b/app/src/play/java/de/danoeh/antennapod/fragment/CustomMRControllerDialogFragment.java
@@ -2,8 +2,8 @@ package de.danoeh.antennapod.fragment;
import android.content.Context;
import android.os.Bundle;
-import android.support.v7.app.MediaRouteControllerDialog;
-import android.support.v7.app.MediaRouteControllerDialogFragment;
+import androidx.mediarouter.app.MediaRouteControllerDialog;
+import androidx.mediarouter.app.MediaRouteControllerDialogFragment;
import de.danoeh.antennapod.dialog.CustomMRControllerDialog;
diff --git a/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java b/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java
index c9d52df0c..810074bbe 100644
--- a/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java
+++ b/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java
@@ -1,8 +1,13 @@
package de.danoeh.antennapod.preferences;
+import android.content.Context;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
+import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.fragment.preferences.PlaybackPreferencesFragment;
@@ -18,6 +23,7 @@ public class PreferenceControllerFlavorHelper {
final int googlePlayServicesCheck = GoogleApiAvailability.getInstance()
.isGooglePlayServicesAvailable(ui.getActivity());
if (googlePlayServicesCheck == ConnectionResult.SUCCESS) {
+ displayRestartRequiredDialog(ui.requireContext());
return true;
} else {
GoogleApiAvailability.getInstance()
@@ -29,4 +35,13 @@ public class PreferenceControllerFlavorHelper {
return true;
});
}
+
+ private static void displayRestartRequiredDialog(@NonNull Context context) {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(context);
+ dialog.setTitle(android.R.string.dialog_alert_title);
+ dialog.setMessage(R.string.pref_restart_required);
+ dialog.setPositiveButton(android.R.string.ok, null);
+ dialog.setCancelable(false);
+ dialog.show();
+ }
}
diff --git a/build.gradle b/build.gradle
index 2ca680ccb..d8e1a6c32 100644
--- a/build.gradle
+++ b/build.gradle
@@ -44,9 +44,8 @@ project.ext {
minSdkVersion = 14
targetSdkVersion = 28
- supportVersion = "27.1.1"
- lifecycle_version = "1.1.1"
workManagerVersion = "1.0.1"
+ espressoVersion = "3.2.0"
awaitilityVersion = "3.1.2"
commonsioVersion = "2.5"
commonslangVersion = "3.6"
@@ -57,8 +56,8 @@ project.ext {
iconifyVersion = "2.2.2"
jsoupVersion = "1.11.2"
materialDialogsVersion = "0.9.0.2"
- okhttpVersion = "3.9.0"
- okioVersion = "1.14.0"
+ okhttpVersion = "3.12.5"
+ okioVersion = "1.17.4"
recyclerviewFlexibledividerVersion = "1.4.0"
robotiumSoloVersion = "5.6.3"
rxAndroidVersion = "2.1.0"
@@ -71,7 +70,7 @@ project.ext {
castCompanionLibVer = "2.9.1"
playServicesVersion = "8.4.0"
- wearableSupportVersion = "2.2.0"
+ wearableSupportVersion = "2.4.0"
}
wrapper {
@@ -82,3 +81,14 @@ wrapper {
def doFreeBuild() {
return hasProperty("freeBuild")
}
+
+apply plugin: "checkstyle"
+checkstyle {
+ toolVersion '8.24'
+}
+
+task checkstyle(type: Checkstyle) {
+ classpath = files()
+ source "${project.rootDir}"
+ exclude("**/gen/**")
+}
diff --git a/config/checkstyle/checkstyle-best-practice.xml b/config/checkstyle/checkstyle-best-practice.xml
new file mode 100644
index 000000000..66ce0dcc4
--- /dev/null
+++ b/config/checkstyle/checkstyle-best-practice.xml
@@ -0,0 +1,252 @@
+<?xml version="1.0"?>
+<!DOCTYPE module PUBLIC
+ "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
+ "https://checkstyle.org/dtds/configuration_1_3.dtd">
+
+<!--
+ Checkstyle configuration that checks the Google coding conventions from Google Java Style
+ that can be found at https://google.github.io/styleguide/javaguide.html.
+ Checkstyle is very configurable. Be sure to read the documentation at
+ http://checkstyle.sf.net (or in your downloaded distribution).
+ To completely disable a check, just comment it out or delete it from the file.
+ Authors: Max Vetrenko, Ruslan Diachenko, Roman Ivanov.
+ -->
+
+<module name = "Checker">
+ <property name="charset" value="UTF-8"/>
+
+ <property name="severity" value="warning"/>
+
+ <property name="fileExtensions" value="java, properties, xml"/>
+ <!-- Checks for whitespace -->
+ <!-- See http://checkstyle.sf.net/config_whitespace.html -->
+ <module name="FileTabCharacter">
+ <property name="eachLine" value="true"/>
+ </module>
+
+ <module name="TreeWalker">
+ <module name="OuterTypeFilename"/>
+ <module name="IllegalTokenText">
+ <property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
+ <property name="format"
+ value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
+ <property name="message"
+ value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
+ </module>
+ <module name="AvoidEscapedUnicodeCharacters">
+ <property name="allowEscapesForControlCharacters" value="true"/>
+ <property name="allowByTailComment" value="true"/>
+ <property name="allowNonPrintableEscapes" value="true"/>
+ </module>
+ <module name="LineLength">
+ <property name="max" value="120"/>
+ <property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
+ </module>
+ <module name="AvoidStarImport"/>
+ <module name="OneTopLevelClass"/>
+ <module name="NoLineWrap"/>
+ <module name="EmptyBlock">
+ <property name="option" value="TEXT"/>
+ <property name="tokens"
+ value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
+ </module>
+ <module name="NeedBraces"/>
+ <module name="LeftCurly"/>
+ <module name="RightCurly">
+ <property name="id" value="RightCurlySame"/>
+ <property name="tokens"
+ value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE,
+ LITERAL_DO"/>
+ </module>
+ <module name="RightCurly">
+ <property name="id" value="RightCurlyAlone"/>
+ <property name="option" value="alone"/>
+ <property name="tokens"
+ value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT,
+ INSTANCE_INIT"/>
+ </module>
+ <module name="WhitespaceAround">
+ <property name="allowEmptyConstructors" value="true"/>
+ <property name="allowEmptyMethods" value="true"/>
+ <property name="allowEmptyTypes" value="true"/>
+ <property name="allowEmptyLoops" value="true"/>
+ <message key="ws.notFollowed"
+ value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
+ <message key="ws.notPreceded"
+ value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
+ </module>
+ <module name="OneStatementPerLine"/>
+ <module name="MultipleVariableDeclarations"/>
+ <module name="ArrayTypeStyle"/>
+ <module name="MissingSwitchDefault"/>
+ <module name="FallThrough"/>
+ <module name="UpperEll"/>
+ <module name="ModifierOrder"/>
+ <module name="EmptyLineSeparator">
+ <property name="allowNoEmptyLineBetweenFields" value="true"/>
+ </module>
+ <module name="SeparatorWrap">
+ <property name="id" value="SeparatorWrapDot"/>
+ <property name="tokens" value="DOT"/>
+ <property name="option" value="nl"/>
+ </module>
+ <module name="SeparatorWrap">
+ <property name="id" value="SeparatorWrapComma"/>
+ <property name="tokens" value="COMMA"/>
+ <property name="option" value="EOL"/>
+ </module>
+ <module name="SeparatorWrap">
+ <!-- ELLIPSIS is EOL until https://github.com/google/styleguide/issues/258 -->
+ <property name="id" value="SeparatorWrapEllipsis"/>
+ <property name="tokens" value="ELLIPSIS"/>
+ <property name="option" value="EOL"/>
+ </module>
+ <module name="SeparatorWrap">
+ <!-- ARRAY_DECLARATOR is EOL until https://github.com/google/styleguide/issues/259 -->
+ <property name="id" value="SeparatorWrapArrayDeclarator"/>
+ <property name="tokens" value="ARRAY_DECLARATOR"/>
+ <property name="option" value="EOL"/>
+ </module>
+ <module name="SeparatorWrap">
+ <property name="id" value="SeparatorWrapMethodRef"/>
+ <property name="tokens" value="METHOD_REF"/>
+ <property name="option" value="nl"/>
+ </module>
+ <module name="PackageName">
+ <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
+ <message key="name.invalidPattern"
+ value="Package name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="TypeName">
+ <message key="name.invalidPattern"
+ value="Type name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="MemberName">
+ <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
+ <message key="name.invalidPattern"
+ value="Member name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="ParameterName">
+ <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
+ <message key="name.invalidPattern"
+ value="Parameter name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="LambdaParameterName">
+ <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
+ <message key="name.invalidPattern"
+ value="Lambda parameter name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="CatchParameterName">
+ <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
+ <message key="name.invalidPattern"
+ value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="LocalVariableName">
+ <property name="tokens" value="VARIABLE_DEF"/>
+ <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
+ <message key="name.invalidPattern"
+ value="Local variable name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="ClassTypeParameterName">
+ <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
+ <message key="name.invalidPattern"
+ value="Class type name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="MethodTypeParameterName">
+ <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
+ <message key="name.invalidPattern"
+ value="Method type name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="InterfaceTypeParameterName">
+ <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
+ <message key="name.invalidPattern"
+ value="Interface type name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="NoFinalizer"/>
+ <module name="GenericWhitespace">
+ <message key="ws.followed"
+ value="GenericWhitespace ''{0}'' is followed by whitespace."/>
+ <message key="ws.preceded"
+ value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
+ <message key="ws.illegalFollow"
+ value="GenericWhitespace ''{0}'' should followed by whitespace."/>
+ <message key="ws.notPreceded"
+ value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
+ </module>
+ <module name="Indentation">
+ <property name="basicOffset" value="4"/>
+ <property name="braceAdjustment" value="0"/>
+ <property name="caseIndent" value="4"/>
+ <property name="throwsIndent" value="8"/>
+ <property name="lineWrappingIndentation" value="8"/>
+ <property name="arrayInitIndent" value="4"/>
+ </module>
+ <module name="AbbreviationAsWordInName">
+ <property name="ignoreFinal" value="false"/>
+ <property name="allowedAbbreviationLength" value="1"/>
+ </module>
+ <module name="OverloadMethodsDeclarationOrder"/>
+ <module name="VariableDeclarationUsageDistance"/>
+ <module name="CustomImportOrder">
+ <property name="sortImportsInGroupAlphabetically" value="true"/>
+ <property name="separateLineBetweenGroups" value="true"/>
+ <property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE"/>
+ </module>
+ <module name="MethodParamPad"/>
+ <module name="NoWhitespaceBefore">
+ <property name="tokens"
+ value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS, METHOD_REF"/>
+ <property name="allowLineBreaks" value="true"/>
+ </module>
+ <module name="ParenPad"/>
+ <module name="OperatorWrap">
+ <property name="option" value="NL"/>
+ <property name="tokens"
+ value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR,
+ LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF "/>
+ </module>
+ <module name="AnnotationLocation">
+ <property name="id" value="AnnotationLocationMostCases"/>
+ <property name="tokens"
+ value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
+ </module>
+ <module name="AnnotationLocation">
+ <property name="id" value="AnnotationLocationVariables"/>
+ <property name="tokens" value="VARIABLE_DEF"/>
+ <property name="allowSamelineMultipleAnnotations" value="true"/>
+ </module>
+ <module name="NonEmptyAtclauseDescription"/>
+ <module name="JavadocTagContinuationIndentation"/>
+ <module name="SummaryJavadoc">
+ <property name="forbiddenSummaryFragments"
+ value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
+ </module>
+ <module name="JavadocParagraph"/>
+ <module name="AtclauseOrder">
+ <property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
+ <property name="target"
+ value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
+ </module>
+ <module name="JavadocMethod">
+ <property name="scope" value="public"/>
+ <property name="allowMissingParamTags" value="true"/>
+ <property name="allowMissingThrowsTags" value="true"/>
+ <property name="allowMissingReturnTag" value="true"/>
+ <property name="minLineCount" value="2"/>
+ <property name="allowedAnnotations" value="Override, Test"/>
+ <property name="allowThrowsTagsForSubclasses" value="true"/>
+ </module>
+ <module name="MethodName">
+ <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/>
+ <message key="name.invalidPattern"
+ value="Method name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="SingleLineJavadoc">
+ <property name="ignoreInlineTags" value="false"/>
+ </module>
+ <module name="EmptyCatchBlock">
+ <property name="exceptionVariableName" value="expected"/>
+ </module>
+ <module name="CommentsIndentation"/>
+ </module>
+</module>
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
new file mode 100644
index 000000000..0a5b47eb8
--- /dev/null
+++ b/config/checkstyle/checkstyle.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<!DOCTYPE module PUBLIC
+ "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
+ "https://checkstyle.org/dtds/configuration_1_3.dtd">
+<module name = "Checker">
+ <property name="charset" value="UTF-8"/>
+
+ <property name="severity" value="error"/>
+
+ <property name="fileExtensions" value="java, xml"/>
+
+ <module name="TreeWalker">
+ <module name="OuterTypeFilename"/>
+ <module name="AvoidEscapedUnicodeCharacters">
+ <property name="allowEscapesForControlCharacters" value="true"/>
+ <property name="allowByTailComment" value="true"/>
+ <property name="allowNonPrintableEscapes" value="true"/>
+ </module>
+ <module name="AvoidStarImport"/>
+ <module name="OneTopLevelClass"/>
+ <module name="NoLineWrap"/>
+ <module name="EmptyBlock">
+ <property name="option" value="TEXT"/>
+ <property name="tokens"
+ value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
+ </module>
+ <module name="OneStatementPerLine"/>
+ <module name="FallThrough"/>
+ <module name="UpperEll"/>
+ <module name="ModifierOrder"/>
+ <module name="PackageName">
+ <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
+ <message key="name.invalidPattern"
+ value="Package name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="TypeName">
+ <message key="name.invalidPattern"
+ value="Type name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="CatchParameterName">
+ <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
+ <message key="name.invalidPattern"
+ value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="ClassTypeParameterName">
+ <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
+ <message key="name.invalidPattern"
+ value="Class type name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="MethodTypeParameterName">
+ <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
+ <message key="name.invalidPattern"
+ value="Method type name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="InterfaceTypeParameterName">
+ <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
+ <message key="name.invalidPattern"
+ value="Interface type name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="NoFinalizer"/>
+ <module name="GenericWhitespace">
+ <message key="ws.followed"
+ value="GenericWhitespace ''{0}'' is followed by whitespace."/>
+ <message key="ws.preceded"
+ value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
+ <message key="ws.illegalFollow"
+ value="GenericWhitespace ''{0}'' should followed by whitespace."/>
+ <message key="ws.notPreceded"
+ value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
+ </module>
+ <module name="AnnotationLocation">
+ <property name="id" value="AnnotationLocationMostCases"/>
+ <property name="tokens"
+ value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
+ </module>
+ <module name="AnnotationLocation">
+ <property name="id" value="AnnotationLocationVariables"/>
+ <property name="tokens" value="VARIABLE_DEF"/>
+ <property name="allowSamelineMultipleAnnotations" value="true"/>
+ </module>
+ </module>
+</module>
diff --git a/core/build.gradle b/core/build.gradle
index 133f1b262..fe6ed824a 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -10,7 +10,7 @@ android {
versionCode 1
versionName "1.0"
testApplicationId "de.danoeh.antennapod.core.tests"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
javaCompileOptions {
annotationProcessorOptions {
@@ -56,11 +56,11 @@ android {
}
dependencies {
- implementation "com.android.support:support-v4:$supportVersion"
- implementation "com.android.support:appcompat-v7:$supportVersion"
- implementation "com.android.support:preference-v14:$supportVersion"
+ implementation "androidx.appcompat:appcompat:1.1.0"
+ implementation "androidx.preference:preference:1.1.0"
+ annotationProcessor "androidx.annotation:annotation:1.1.0"
implementation "android.arch.work:work-runtime:$workManagerVersion"
-
+ implementation "androidx.media:media:1.1.0"
implementation "org.apache.commons:commons-lang3:$commonslangVersion"
implementation "org.apache.commons:commons-text:$commonstextVersion"
implementation "commons-io:commons-io:$commonsioVersion"
@@ -76,7 +76,6 @@ dependencies {
annotationProcessor "org.greenrobot:eventbus-annotation-processor:$eventbusVersion"
implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
- implementation "org.awaitility:awaitility:$awaitilityVersion"
implementation "com.google.android.exoplayer:exoplayer:$exoPlayerVersion"
implementation "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion"
@@ -85,18 +84,19 @@ dependencies {
// free build hack: skip some dependencies
if (!doFreeBuild()) {
playApi "com.google.android.libraries.cast.companionlibrary:ccl:$castCompanionLibVer"
- api "com.android.support:mediarouter-v7:$supportVersion"
+ api "androidx.mediarouter:mediarouter:1.0.0"
playApi "com.google.android.gms:play-services-cast:$playServicesVersion"
api "com.google.android.support:wearable:$wearableSupportVersion"
} else {
System.out.println("core: free build hack, skipping some dependencies")
}
+ testImplementation "org.awaitility:awaitility:$awaitilityVersion"
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:1.10.19'
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
- androidTestImplementation 'com.android.support.test:runner:1.0.2'
- androidTestImplementation 'com.android.support.test:rules:1.0.2'
+ androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
+ androidTestImplementation 'androidx.test:runner:1.2.0'
+ androidTestImplementation 'androidx.test:rules:1.2.0'
}
diff --git a/core/src/androidTest/java/de/danoeh/antennapod/core/util/DateUtilsTest.java b/core/src/androidTest/java/de/danoeh/antennapod/core/util/DateUtilsTest.java
index ffba4e479..5d98f133c 100644
--- a/core/src/androidTest/java/de/danoeh/antennapod/core/util/DateUtilsTest.java
+++ b/core/src/androidTest/java/de/danoeh/antennapod/core/util/DateUtilsTest.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.util;
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
import org.junit.Test;
import java.util.Calendar;
diff --git a/core/src/free/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java b/core/src/free/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java
index 37109ddca..837cb1bd0 100644
--- a/core/src/free/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java
+++ b/core/src/free/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.service.playback;
import android.content.Context;
-import android.support.annotation.StringRes;
+import androidx.annotation.StringRes;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml
index 3b6edae42..7d84bdddb 100644
--- a/core/src/main/AndroidManifest.xml
+++ b/core/src/main/AndroidManifest.xml
@@ -9,6 +9,11 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.VIBRATE" />
+ <!-- ACCESS_FINE_LOCATION is needed only on Android 10+,
+ for Automatic Download Wifi filter's UI, which uses
+ WifiManager.WifiManager.getConfiguredNetworks()
+ -->
+ <uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
diff --git a/core/src/main/java/android/support/v4/app/SafeJobIntentService.java b/core/src/main/java/androidx/core/app/SafeJobIntentService.java
index c07c409ee..aedc9418b 100644
--- a/core/src/main/java/android/support/v4/app/SafeJobIntentService.java
+++ b/core/src/main/java/androidx/core/app/SafeJobIntentService.java
@@ -1,4 +1,4 @@
-package android.support.v4.app;
+package androidx.core.app;
import android.app.job.JobParameters;
import android.app.job.JobServiceEngine;
@@ -6,7 +6,7 @@ import android.app.job.JobWorkItem;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
-import android.support.annotation.RequiresApi;
+import androidx.annotation.RequiresApi;
import android.util.Log;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java b/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java
index c626a8189..c9fe886fb 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.dialog;
import android.content.Context;
import android.content.DialogInterface;
-import android.support.v7.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog;
import android.util.Log;
import de.danoeh.antennapod.core.R;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/dialog/DownloadRequestErrorDialogCreator.java b/core/src/main/java/de/danoeh/antennapod/core/dialog/DownloadRequestErrorDialogCreator.java
index b1beac315..e38abb990 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/dialog/DownloadRequestErrorDialogCreator.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/dialog/DownloadRequestErrorDialogCreator.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.dialog;
import android.content.Context;
-import android.support.v7.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog;
import de.danoeh.antennapod.core.R;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java
index 124fd3e64..24a71ec96 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java
@@ -25,4 +25,8 @@ public class DownloadEvent {
"update=" + update +
'}';
}
+
+ public boolean hasChangedFeedUpdateStatus(boolean oldStatus) {
+ return oldStatus != update.feedIds.length > 0;
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java b/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java
index 7ca6f78de..9acd7728a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.event;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import java.util.Arrays;
import java.util.List;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
index 9db262857..89ecf271b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.event;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/FeedMediaEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/FeedMediaEvent.java
deleted file mode 100644
index 4a591c996..000000000
--- a/core/src/main/java/de/danoeh/antennapod/core/event/FeedMediaEvent.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package de.danoeh.antennapod.core.event;
-
-import de.danoeh.antennapod.core.feed.FeedMedia;
-
-public class FeedMediaEvent {
-
- public enum Action {
- UPDATE
- }
-
- private final Action action;
- private final FeedMedia media;
-
- private FeedMediaEvent(Action action, FeedMedia media) {
- this.action = action;
- this.media = media;
- }
-
- public static FeedMediaEvent update(FeedMedia media) {
- return new FeedMediaEvent(Action.UPDATE, media);
- }
-
-}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/MessageEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/MessageEvent.java
index 9fc488fbc..9fb22b8ea 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/MessageEvent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/MessageEvent.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.event;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
public class MessageEvent {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/PlaybackPositionEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/PlaybackPositionEvent.java
new file mode 100644
index 000000000..3327d8a02
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/PlaybackPositionEvent.java
@@ -0,0 +1,19 @@
+package de.danoeh.antennapod.core.event;
+
+public class PlaybackPositionEvent {
+ private final int position;
+ private final int duration;
+
+ public PlaybackPositionEvent(int position, int duration) {
+ this.position = position;
+ this.duration = duration;
+ }
+
+ public int getPosition() {
+ return position;
+ }
+
+ public int getDuration() {
+ return duration;
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/ProgressEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/ProgressEvent.java
deleted file mode 100644
index 3769d6bb1..000000000
--- a/core/src/main/java/de/danoeh/antennapod/core/event/ProgressEvent.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package de.danoeh.antennapod.core.event;
-
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-public class ProgressEvent {
-
- public enum Action {
- START, END
- }
-
- public final Action action;
- public final String message;
-
- private ProgressEvent(Action action, String message) {
- this.action = action;
- this.message = message;
- }
-
- public static ProgressEvent start(String message) {
- return new ProgressEvent(Action.START, message);
- }
-
- public static ProgressEvent end() {
- return new ProgressEvent(Action.END, null);
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
- .append("action", action)
- .append("message", message)
- .toString();
- }
-
-}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/QueueEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/QueueEvent.java
index a84e8456f..209dcba4d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/QueueEvent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/QueueEvent.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.event;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java b/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java
index 5718c06c2..6a7c97b7b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.feed;
import android.database.Cursor;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import android.text.TextUtils;
import java.util.ArrayList;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
index 86d8f5294..0f9ca0445 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.feed;
import android.database.Cursor;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import android.text.TextUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
@@ -221,6 +221,8 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, ImageR
return itemIdentifier;
} else if (title != null && !title.isEmpty()) {
return title;
+ } else if (hasMedia() && media.getDownload_url() != null) {
+ return media.getDownload_url();
} else {
return link;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
index 05ca84bac..10cf1f5c8 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
@@ -7,7 +7,7 @@ import android.database.Cursor;
import android.media.MediaMetadataRetriever;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.MediaDescriptionCompat;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java
index b0512d844..8fdf2034f 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.feed;
import android.content.Context;
import android.database.Cursor;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.text.TextUtils;
import de.danoeh.antennapod.core.preferences.UserPreferences;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java
index 552c1b691..b2c809e90 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.glide;
import android.content.Context;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.Registry;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java
index b75e1630c..f02334af5 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.glide;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
@@ -21,8 +21,12 @@ import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
import de.danoeh.antennapod.core.service.download.HttpDownloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.NetworkUtils;
-import okhttp3.*;
-import okhttp3.internal.http.RealResponseBody;
+import okhttp3.Interceptor;
+import okhttp3.OkHttpClient;
+import okhttp3.Protocol;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
/**
* @see com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
@@ -88,11 +92,9 @@ class ApOkHttpUrlLoader implements ModelLoader<String, InputStream> {
@Nullable
@Override
public LoadData<InputStream> buildLoadData(@NonNull String model, int width, int height, @NonNull Options options) {
- Log.d(TAG, "buildLoadData() called with: " + "model = [" + model + "], width = ["
- + width + "], height = [" + height + "]");
- if(TextUtils.isEmpty(model)) {
+ if (TextUtils.isEmpty(model)) {
return null;
- } else if(model.startsWith("/")) {
+ } else if (model.startsWith("/")) {
return new LoadData<>(new ObjectKey(model), new AudioCoverFetcher(model));
} else {
GlideUrl url = new GlideUrl(model);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java b/core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java
index 479846655..6a237573b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.glide;
import android.media.MediaMetadataRetriever;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.data.DataFetcher;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java b/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java
index a740782d6..cbd22ceb0 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.glide;
import android.graphics.Bitmap;
import android.media.ThumbnailUtils;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
index 2588cfdee..9ee8c0fc1 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import org.json.JSONArray;
import org.json.JSONException;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java
index faf4264e5..e86b74164 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
public class GpodnetDevice {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java
index 1e21efcda..7b28bba49 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import java.util.List;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java
index b6efab016..10ea4cd9b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import android.support.v4.util.ArrayMap;
+import androidx.collection.ArrayMap;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java
index 680dc1042..2c2d759c9 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
public class GpodnetPodcast {
private final String url;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java
index 0f1961bef..56a64053f 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import java.util.List;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java
index 40543592e..dec3be7f2 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.gpoddernet.model;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
public class GpodnetTag implements Parcelable {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java
index 9f9c3bd74..ba3db8412 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import android.support.v4.util.ArrayMap;
+import androidx.collection.ArrayMap;
import org.json.JSONArray;
import org.json.JSONException;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
index a4cc22d8b..f2c0c8fe3 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
@@ -4,7 +4,12 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
+import android.util.Log;
import de.danoeh.antennapod.core.feed.EventDistributor;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.feed.MediaType;
+import de.danoeh.antennapod.core.service.playback.PlayerStatus;
+import de.danoeh.antennapod.core.util.playback.Playable;
/**
* Provides access to preferences set by the playback service. A private
@@ -19,35 +24,35 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference
* 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";
+ private 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";
+ private 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";
+ private 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";
+ private 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";
+ private static final String PREF_CURRENT_EPISODE_IS_VIDEO = "de.danoeh.antennapod.preferences.lastIsVideo";
/**
* The current player status as int.
*/
- public static final String PREF_CURRENT_PLAYER_STATUS = "de.danoeh.antennapod.preferences.currentPlayerStatus";
+ private static final String PREF_CURRENT_PLAYER_STATUS = "de.danoeh.antennapod.preferences.currentPlayerStatus";
/**
* Value of PREF_CURRENTLY_PLAYING_MEDIA if no media is playing.
@@ -87,10 +92,6 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference
}
}
- public static long getLastPlayedFeedId() {
- return prefs.getLong(PREF_CURRENTLY_PLAYING_FEED_ID, -1);
- }
-
public static long getCurrentlyPlayingMedia() {
return prefs.getLong(PREF_CURRENTLY_PLAYING_MEDIA, NO_MEDIA_PLAYING);
}
@@ -119,4 +120,52 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference
editor.putInt(PREF_CURRENT_PLAYER_STATUS, PLAYER_STATUS_OTHER);
editor.apply();
}
+
+ public static void writeMediaPlaying(Playable playable, PlayerStatus playerStatus, boolean stream) {
+ Log.d(TAG, "Writing playback preferences");
+ SharedPreferences.Editor editor = prefs.edit();
+
+ if (playable == null) {
+ writeNoMediaPlaying();
+ } else {
+ editor.putLong(PREF_CURRENTLY_PLAYING_MEDIA, playable.getPlayableType());
+ editor.putBoolean(PREF_CURRENT_EPISODE_IS_STREAM, stream);
+ editor.putBoolean(PREF_CURRENT_EPISODE_IS_VIDEO, playable.getMediaType() == MediaType.VIDEO);
+ if (playable instanceof FeedMedia) {
+ FeedMedia fMedia = (FeedMedia) playable;
+ editor.putLong(PREF_CURRENTLY_PLAYING_FEED_ID, fMedia.getItem().getFeed().getId());
+ editor.putLong(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, fMedia.getId());
+ } else {
+ editor.putLong(PREF_CURRENTLY_PLAYING_FEED_ID, NO_MEDIA_PLAYING);
+ editor.putLong(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, NO_MEDIA_PLAYING);
+ }
+ playable.writeToPreferences(editor);
+ }
+ editor.putInt(PREF_CURRENT_PLAYER_STATUS, getCurrentPlayerStatusAsInt(playerStatus));
+
+ editor.apply();
+ }
+
+ public static void writePlayerStatus(PlayerStatus playerStatus) {
+ Log.d(TAG, "Writing player status playback preferences");
+
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(PREF_CURRENT_PLAYER_STATUS, getCurrentPlayerStatusAsInt(playerStatus));
+ editor.apply();
+ }
+
+ private static int getCurrentPlayerStatusAsInt(PlayerStatus playerStatus) {
+ int playerStatusAsInt;
+ switch (playerStatus) {
+ case PLAYING:
+ playerStatusAsInt = PLAYER_STATUS_PLAYING;
+ break;
+ case PAUSED:
+ playerStatusAsInt = PLAYER_STATUS_PAUSED;
+ break;
+ default:
+ playerStatusAsInt = PLAYER_STATUS_OTHER;
+ }
+ return playerStatusAsInt;
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/SleepTimerPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/SleepTimerPreferences.java
index 0f3a9fcb3..eb87acb5f 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/SleepTimerPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/SleepTimerPreferences.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.preferences;
import android.content.Context;
import android.content.SharedPreferences;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import java.util.concurrent.TimeUnit;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
index 80f0fd454..fc4166eb4 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
@@ -2,10 +2,11 @@ package de.danoeh.antennapod.core.preferences;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.res.Configuration;
import android.preference.PreferenceManager;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.support.v4.app.NotificationCompat;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.core.app.NotificationCompat;
import android.text.TextUtils;
import android.util.Log;
@@ -169,7 +170,7 @@ public class UserPreferences {
* @return R.style.Theme_AntennaPod_Light or R.style.Theme_AntennaPod_Dark
*/
public static int getTheme() {
- return readThemeValue(prefs.getString(PREF_THEME, "0"));
+ return readThemeValue(prefs.getString(PREF_THEME, "system"));
}
public static int getNoTitleTheme() {
@@ -645,7 +646,7 @@ public class UserPreferences {
.apply();
// when updating with an interval, we assume the user wants
// to update *now* and then every 'hours' interval thereafter.
- restartUpdateAlarm();
+ AutoUpdateManager.restartUpdateAlarm();
}
/**
@@ -655,7 +656,7 @@ public class UserPreferences {
prefs.edit()
.putString(PREF_UPDATE_INTERVAL, hourOfDay + ":" + minute)
.apply();
- restartUpdateAlarm();
+ AutoUpdateManager.restartUpdateAlarm();
}
public static void disableAutoUpdate() {
@@ -696,14 +697,18 @@ public class UserPreferences {
}
private static int readThemeValue(String valueFromPrefs) {
- switch (Integer.parseInt(valueFromPrefs)) {
- case 0:
+ switch (valueFromPrefs) {
+ case "0":
return R.style.Theme_AntennaPod_Light;
- case 1:
+ case "1":
return R.style.Theme_AntennaPod_Dark;
- case 2:
+ case "2":
return R.style.Theme_AntennaPod_TrueBlack;
default:
+ int nightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+ if (nightMode == Configuration.UI_MODE_NIGHT_YES) {
+ return R.style.Theme_AntennaPod_Dark;
+ }
return R.style.Theme_AntennaPod_Light;
}
}
@@ -901,26 +906,6 @@ public class UserPreferences {
return getUpdateTimeOfDay().length == 2;
}
- public static void restartUpdateAlarm() {
- if (isAutoUpdateDisabled()) {
- AutoUpdateManager.disableAutoUpdate();
- } else if (isAutoUpdateTimeOfDay()) {
- int[] timeOfDay = getUpdateTimeOfDay();
- Log.d(TAG, "timeOfDay: " + Arrays.toString(timeOfDay));
- AutoUpdateManager.restartUpdateTimeOfDayAlarm(timeOfDay[0], timeOfDay[1]);
- } else {
- long milliseconds = getUpdateInterval();
- AutoUpdateManager.restartUpdateIntervalAlarm(milliseconds);
- }
- }
-
- /**
- * Reads episode cache size as it is saved in the episode_cache_size_values array.
- */
- public static int readEpisodeCacheSize(String valueFromPrefs) {
- return readEpisodeCacheSizeInternal(valueFromPrefs);
- }
-
/**
* Evaluates whether Cast support (Chromecast, Audio Cast, etc) is enabled on the preferences.
*/
diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java
index 126f12247..af0a0d426 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java
@@ -6,8 +6,7 @@ import android.content.Intent;
import android.util.Log;
import de.danoeh.antennapod.core.ClientConfig;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.util.FeedUpdateUtils;
+import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
/**
* Refreshes all feeds when it receives an intent
@@ -20,7 +19,8 @@ public class FeedUpdateReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Received intent");
ClientConfig.initialize(context);
- FeedUpdateUtils.startAutoUpdate(context, null);
+
+ AutoUpdateManager.runOnce();
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java
index b191dbf8b..b683f849c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java
@@ -3,7 +3,7 @@ package de.danoeh.antennapod.core.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.support.v4.content.ContextCompat;
+import androidx.core.content.ContextCompat;
import android.util.Log;
import android.view.KeyEvent;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java
index efdb96dc1..4443319e9 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java
@@ -1,18 +1,24 @@
package de.danoeh.antennapod.core.service;
import android.content.Context;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
+import android.util.Log;
+
import androidx.work.Worker;
import androidx.work.WorkerParameters;
+
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.util.FeedUpdateUtils;
-import org.awaitility.Awaitility;
-
-import java.util.concurrent.atomic.AtomicBoolean;
+import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.util.NetworkUtils;
+import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
public class FeedUpdateWorker extends Worker {
+ private static final String TAG = "FeedUpdateWorker";
+
+ public static final String PARAM_RUN_ONCE = "runOnce";
+
public FeedUpdateWorker(@NonNull Context context, @NonNull WorkerParameters params) {
super(context, params);
}
@@ -20,16 +26,20 @@ public class FeedUpdateWorker extends Worker {
@Override
@NonNull
public Result doWork() {
+ final boolean isRunOnce = getInputData().getBoolean(PARAM_RUN_ONCE, false);
+ Log.d(TAG, "doWork() : isRunOnce = " + isRunOnce);
ClientConfig.initialize(getApplicationContext());
- AtomicBoolean finished = new AtomicBoolean(false);
- FeedUpdateUtils.startAutoUpdate(getApplicationContext(), () -> finished.set(true));
- Awaitility.await().until(finished::get);
+ if (NetworkUtils.networkAvailable() && NetworkUtils.isFeedRefreshAllowed()) {
+ DBTasks.refreshAllFeeds(getApplicationContext());
+ } else {
+ Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed");
+ }
- if (UserPreferences.isAutoUpdateTimeOfDay()) {
+ if (!isRunOnce && UserPreferences.isAutoUpdateTimeOfDay()) {
// WorkManager does not allow to set specific time for repeated tasks.
// We repeatedly schedule a OneTimeWorkRequest instead.
- UserPreferences.restartUpdateAlarm();
+ AutoUpdateManager.restartUpdateAlarm();
}
return Result.success();
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java b/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java
index 5584991ca..b254cfc59 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java
@@ -5,10 +5,10 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.support.annotation.NonNull;
-import android.support.v4.app.NotificationCompat;
-import android.support.v4.app.SafeJobIntentService;
-import android.support.v4.util.ArrayMap;
+import androidx.annotation.NonNull;
+import androidx.core.app.NotificationCompat;
+import androidx.core.app.SafeJobIntentService;
+import androidx.collection.ArrayMap;
import android.util.Log;
import android.util.Pair;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java b/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java
index 7938e262d..a3eb92c0c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java
@@ -10,8 +10,8 @@ import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
-import android.support.annotation.NonNull;
-import android.support.v4.app.SafeJobIntentService;
+import androidx.annotation.NonNull;
+import androidx.core.app.SafeJobIntentService;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
@@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
+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.service.playback.PlaybackService;
@@ -69,9 +70,7 @@ public class PlayerWidgetJobService extends SafeJobIntentService {
}
synchronized (waitUsingService) {
- if (playbackService != null) {
- updateViews();
- }
+ updateViews();
}
if (playbackService != null) {
@@ -145,9 +144,10 @@ public class PlayerWidgetJobService extends SafeJobIntentService {
String progressString;
if (playbackService != null) {
- progressString = getProgressString(playbackService.getCurrentPosition(), playbackService.getDuration());
+ progressString = getProgressString(playbackService.getCurrentPosition(),
+ playbackService.getDuration(), playbackService.getCurrentPlaybackSpeed());
} else {
- progressString = getProgressString(media.getPosition(), media.getDuration());
+ progressString = getProgressString(media.getPosition(), media.getDuration(), UserPreferences.getPlaybackSpeed(media));
}
if (progressString != null) {
@@ -211,9 +211,9 @@ public class PlayerWidgetJobService extends SafeJobIntentService {
return PendingIntent.getBroadcast(this, 0, startingIntent, 0);
}
- private String getProgressString(int position, int duration) {
+ private String getProgressString(int position, int duration, float speed) {
if (position > 0 && duration > 0) {
- TimeSpeedConverter converter = new TimeSpeedConverter(playbackService.getCurrentPlaybackSpeed());
+ TimeSpeedConverter converter = new TimeSpeedConverter(speed);
position = converter.convert(position);
duration = converter.convert(duration);
return Converter.getDurationStringLong(position) + " / "
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
index 97007a214..2082b95d1 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.service.download;
import android.os.Build;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
@@ -16,7 +16,9 @@ import java.net.Socket;
import java.net.SocketAddress;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
@@ -28,6 +30,8 @@ import javax.net.ssl.X509TrustManager;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBWriter;
+import okhttp3.CipherSuite;
+import okhttp3.ConnectionSpec;
import okhttp3.Credentials;
import okhttp3.HttpUrl;
import okhttp3.JavaNetCookieJar;
@@ -138,9 +142,24 @@ public class AntennapodHttpClient {
});
}
}
- if(16 <= Build.VERSION.SDK_INT && Build.VERSION.SDK_INT < 21) {
+ if (16 <= Build.VERSION.SDK_INT && Build.VERSION.SDK_INT < 21) {
builder.sslSocketFactory(new CustomSslSocketFactory(), trustManager());
}
+
+ if (Build.VERSION.SDK_INT < 21) {
+ // workaround for Android 4.x for certain web sites.
+ // see: https://github.com/square/okhttp/issues/4053#issuecomment-402579554
+ List<CipherSuite> cipherSuites = new ArrayList<>();
+ cipherSuites.addAll(ConnectionSpec.MODERN_TLS.cipherSuites());
+ cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA);
+ cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA);
+
+ ConnectionSpec legacyTls = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
+ .cipherSuites(cipherSuites.toArray(new CipherSuite[0]))
+ .build();
+ builder.connectionSpecs(Arrays.asList(legacyTls, ConnectionSpec.CLEARTEXT));
+ }
+
return builder;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
index 48234c387..60591899d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
@@ -3,8 +3,8 @@ package de.danoeh.antennapod.core.service.download;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import de.danoeh.antennapod.core.feed.FeedFile;
import de.danoeh.antennapod.core.util.URLChecker;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java
index 787d465d8..296046031 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java
@@ -12,8 +12,10 @@ import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
-import android.support.annotation.NonNull;
-import android.support.v4.app.NotificationCompat;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.core.app.NotificationCompat;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -190,10 +192,8 @@ public class DownloadService extends Service {
handleFailedDownload(status, downloader.getDownloadRequest());
if (type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
- long id = status.getFeedfileId();
- FeedMedia media = DBReader.getFeedMedia(id);
- FeedItem item;
- if (media == null || (item = media.getItem()) == null) {
+ FeedItem item = getFeedItemFromId(status.getFeedfileId());
+ if (item == null) {
return;
}
boolean httpNotFound = status.getReason() == DownloadError.ERROR_HTTP_DATA_ERROR
@@ -213,9 +213,8 @@ public class DownloadService extends Service {
// if FeedMedia download has been canceled, fake FeedItem update
// so that lists reload that it
if (status.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
- FeedMedia media = DBReader.getFeedMedia(status.getFeedfileId());
- FeedItem item;
- if (media == null || (item = media.getItem()) == null) {
+ FeedItem item = getFeedItemFromId(status.getFeedfileId());
+ if (item == null) {
return;
}
EventBus.getDefault().post(FeedItemEvent.updated(item));
@@ -386,6 +385,12 @@ public class DownloadService extends Service {
Downloader d = getDownloader(url);
if (d != null) {
d.cancel();
+ DownloadRequester.getInstance().removeDownload(d.getDownloadRequest());
+
+ FeedItem item = getFeedItemFromId(d.getDownloadRequest().getFeedfileId());
+ if (item != null) {
+ EventBus.getDefault().post(FeedItemEvent.updated(item));
+ }
} else {
Log.e(TAG, "Could not cancel download with url " + url);
}
@@ -430,12 +435,40 @@ public class DownloadService extends Service {
queryDownloads();
}
- private Downloader getDownloader(DownloadRequest request) {
- if (!URLUtil.isHttpUrl(request.getSource()) && !URLUtil.isHttpsUrl(request.getSource())) {
- Log.e(TAG, "Could not find appropriate downloader for " + request.getSource());
- return null;
+ @VisibleForTesting
+ public interface DownloaderFactory {
+ @Nullable
+ Downloader create(@NonNull DownloadRequest request);
+ }
+
+ private static class DefaultDownloaderFactory implements DownloaderFactory {
+ @Nullable
+ @Override
+ public Downloader create(@NonNull DownloadRequest request) {
+ if (!URLUtil.isHttpUrl(request.getSource()) && !URLUtil.isHttpsUrl(request.getSource())) {
+ Log.e(TAG, "Could not find appropriate downloader for " + request.getSource());
+ return null;
+ }
+ return new HttpDownloader(request);
}
- return new HttpDownloader(request);
+ }
+
+ private static DownloaderFactory downloaderFactory = new DefaultDownloaderFactory();
+
+ @VisibleForTesting
+ public static DownloaderFactory getDownloaderFactory() {
+ return downloaderFactory;
+ }
+
+ // public scope rather than package private,
+ // because androidTest put classes in the non-standard de.test.antennapod hierarchy
+ @VisibleForTesting
+ public static void setDownloaderFactory(DownloaderFactory downloaderFactory) {
+ DownloadService.downloaderFactory = downloaderFactory;
+ }
+
+ private Downloader getDownloader(@NonNull DownloadRequest request) {
+ return downloaderFactory.create(request);
}
/**
@@ -546,7 +579,7 @@ public class DownloadService extends Service {
.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)
+ .setSmallIcon(R.drawable.ic_notification_key)
.setAutoCancel(true)
.setContentIntent(ClientConfig.downloadServiceCallbacks.getAuthentificationNotificationContentIntent(DownloadService.this, downloadRequest));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
@@ -578,6 +611,16 @@ public class DownloadService extends Service {
syncExecutor.execute(new FailedDownloadHandler(status, request));
}
+ @Nullable
+ private FeedItem getFeedItemFromId(long id) {
+ FeedMedia media = DBReader.getFeedMedia(id);
+ if (media != null) {
+ return media.getItem();
+ } else {
+ return null;
+ }
+ }
+
/**
* Takes a single Feed, parses the corresponding file and refreshes
* information in the manager
@@ -654,6 +697,7 @@ public class DownloadService extends Service {
Log.e(TAG, "FeedSyncThread was interrupted");
} catch (ExecutionException e) {
Log.e(TAG, "ExecutionException in FeedSyncThread: " + e.getMessage());
+ e.printStackTrace();
}
}
@@ -688,6 +732,7 @@ public class DownloadService extends Service {
Log.e(TAG, "FeedSyncThread was interrupted");
} catch (ExecutionException e) {
Log.e(TAG, "ExecutionException in FeedSyncThread: " + e.getMessage());
+ e.printStackTrace();
}
}
@@ -983,14 +1028,17 @@ public class DownloadService extends Service {
final FeedItem item = media.getItem();
try {
+ DBWriter.setFeedMedia(media).get();
+
// we've received the media, we don't want to autodownload it again
if (item != null) {
item.setAutoDownload(false);
+ // setFeedItem() signals (via EventBus) that the item has been updated,
+ // so we do it after the enclosing media has been updated above,
+ // to ensure subscribers will get the updated FeedMedia as well
DBWriter.setFeedItem(item).get();
}
- DBWriter.setFeedMedia(media).get();
-
if (item != null && UserPreferences.enqueueDownloadedEpisodes() &&
!DBTasks.isInQueue(DownloadService.this, item.getId())) {
DBWriter.addQueueItem(DownloadService.this, item).get();
@@ -1058,7 +1106,13 @@ public class DownloadService extends Service {
private final Runnable postDownloaderTask = new Runnable() {
@Override
public void run() {
- List<Downloader> list = Collections.unmodifiableList(downloads);
+ List<Downloader> runningDownloads = new ArrayList<>();
+ for (Downloader downloader : downloads) {
+ if (!downloader.cancelled) {
+ runningDownloads.add(downloader);
+ }
+ }
+ List<Downloader> list = Collections.unmodifiableList(runningDownloads);
EventBus.getDefault().postSticky(DownloadEvent.refresh(list));
postHandler.postDelayed(postDownloaderTask, 1500);
}
@@ -1076,7 +1130,10 @@ public class DownloadService extends Service {
private static String compileNotificationString(List<Downloader> downloads) {
List<String> lines = new ArrayList<>(downloads.size());
for (Downloader downloader : downloads) {
- StringBuilder line = new StringBuilder("\u2022 ");
+ if (downloader.cancelled) {
+ continue;
+ }
+ StringBuilder line = new StringBuilder("• ");
DownloadRequest request = downloader.getDownloadRequest();
switch (request.getFeedfileType()) {
case Feed.FEEDFILETYPE_FEED:
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java
index 5debc6d05..675115bc7 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.service.download;
import android.database.Cursor;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import java.util.Date;
@@ -193,10 +193,6 @@ public class DownloadStatus {
this.cancelled = true;
}
- public void setCompletionDate(Date completionDate) {
- this.completionDate = (Date) completionDate.clone();
- }
-
public void setId(long id) {
this.id = id;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/Downloader.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/Downloader.java
index 38b93eab8..02dc17301 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/Downloader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/Downloader.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.service.download;
import android.content.Context;
import android.net.wifi.WifiManager;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import java.util.concurrent.Callable;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
index c27cefc10..8abfa3da3 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.service.download;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java
index c4096c3da..0d59a1b7e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.service.download;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import java.net.Proxy;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java
index f20525f73..c988ef70e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java
@@ -2,6 +2,7 @@ package de.danoeh.antennapod.core.service.playback;
import android.content.Context;
import android.net.Uri;
+import android.util.Log;
import android.view.SurfaceHolder;
import com.google.android.exoplayer2.C;
@@ -22,28 +23,52 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
+import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
+import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.exoplayer2.util.Util;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
import org.antennapod.audio.MediaPlayer;
import de.danoeh.antennapod.core.util.playback.IPlayer;
+import java.util.concurrent.TimeUnit;
public class ExoPlayerWrapper implements IPlayer {
+ private static final String TAG = "ExoPlayerWrapper";
private final Context mContext;
+ private final Disposable bufferingUpdateDisposable;
private SimpleExoPlayer mExoPlayer;
private MediaSource mediaSource;
private MediaPlayer.OnSeekCompleteListener audioSeekCompleteListener;
private MediaPlayer.OnCompletionListener audioCompletionListener;
private MediaPlayer.OnErrorListener audioErrorListener;
+ private MediaPlayer.OnBufferingUpdateListener bufferingUpdateListener;
+
ExoPlayerWrapper(Context context) {
mContext = context;
mExoPlayer = createPlayer();
+
+ bufferingUpdateDisposable = Observable.interval(2, TimeUnit.SECONDS)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(aLong -> {
+ if (bufferingUpdateListener != null) {
+ bufferingUpdateListener.onBufferingUpdate(null, mExoPlayer.getBufferedPercentage());
+ }
+ });
}
private SimpleExoPlayer createPlayer() {
+ DefaultLoadControl.Builder loadControl = new DefaultLoadControl.Builder();
+ loadControl.setBufferDurationsMs(30000, 120000,
+ DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
+ DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS);
+ loadControl.setBackBuffer(UserPreferences.getRewindSecs() * 1000 + 500, true);
SimpleExoPlayer p = ExoPlayerFactory.newSimpleInstance(mContext, new DefaultRenderersFactory(mContext),
- new DefaultTrackSelector(), new DefaultLoadControl());
+ new DefaultTrackSelector(), loadControl.createDefaultLoadControl());
p.setSeekParameters(SeekParameters.PREVIOUS_SYNC);
p.addListener(new Player.EventListener() {
@Override
@@ -148,12 +173,14 @@ public class ExoPlayerWrapper implements IPlayer {
@Override
public void release() {
+ bufferingUpdateDisposable.dispose();
if (mExoPlayer != null) {
mExoPlayer.release();
}
audioSeekCompleteListener = null;
audioCompletionListener = null;
audioErrorListener = null;
+ bufferingUpdateListener = null;
}
@Override
@@ -180,8 +207,13 @@ public class ExoPlayerWrapper implements IPlayer {
@Override
public void setDataSource(String s) throws IllegalArgumentException, IllegalStateException {
- DataSource.Factory dataSourceFactory =
- new DefaultDataSourceFactory(mContext, Util.getUserAgent(mContext, mContext.getPackageName()), null);
+ Log.d(TAG, "setDataSource: " + s);
+ DefaultHttpDataSourceFactory httpDataSourceFactory = new DefaultHttpDataSourceFactory(
+ Util.getUserAgent(mContext, mContext.getPackageName()), null,
+ DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
+ DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS,
+ true);
+ DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(mContext, null, httpDataSourceFactory);
ExtractorMediaSource.Factory f = new ExtractorMediaSource.Factory(dataSourceFactory);
mediaSource = f.createMediaSource(Uri.parse(s));
}
@@ -247,4 +279,8 @@ public class ExoPlayerWrapper implements IPlayer {
}
return mExoPlayer.getVideoFormat().height;
}
+
+ void setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener bufferingUpdateListener) {
+ this.bufferingUpdateListener = bufferingUpdateListener;
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
index 72f5f183a..c982cb1e9 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
@@ -6,7 +6,7 @@ import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.os.Build;
import android.os.PowerManager;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.Pair;
@@ -585,7 +585,6 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
}
playerLock.unlock();
- Log.d(TAG, "getPosition() -> " + retVal);
return retVal;
}
@@ -1026,6 +1025,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
ExoPlayerWrapper ap = (ExoPlayerWrapper) mp;
ap.setOnCompletionListener(audioCompletionListener);
ap.setOnSeekCompleteListener(audioSeekCompleteListener);
+ ap.setOnBufferingUpdateListener(audioBufferingUpdateListener);
ap.setOnErrorListener(audioErrorListener);
} else {
Log.w(TAG, "Unknown media player: " + mp);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index e479a7711..2eb9c92e4 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -12,7 +12,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
@@ -22,12 +21,12 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.Vibrator;
import android.preference.PreferenceManager;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringRes;
-import android.support.v4.app.NotificationCompat;
-import android.support.v4.app.NotificationManagerCompat;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+import androidx.core.app.NotificationCompat;
+import androidx.core.app.NotificationManagerCompat;
import android.support.v4.media.MediaBrowserCompat;
-import android.support.v4.media.MediaBrowserServiceCompat;
+import androidx.media.MediaBrowserServiceCompat;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
@@ -45,10 +44,12 @@ import com.bumptech.glide.request.target.Target;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.event.MessageEvent;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import de.danoeh.antennapod.core.event.ServiceEvent;
import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.Feed;
@@ -66,7 +67,6 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.FeedSearcher;
-import de.danoeh.antennapod.core.util.IntList;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.core.util.QueueAccess;
@@ -74,6 +74,9 @@ import de.danoeh.antennapod.core.util.gui.NotificationUtils;
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
import org.greenrobot.eventbus.EventBus;
/**
@@ -212,6 +215,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
private PlaybackServiceTaskManager taskManager;
private PlaybackServiceFlavorHelper flavorHelper;
private PlaybackServiceStateManager stateManager;
+ private Disposable positionEventTimer;
/**
* Used for Lollipop notifications, Android Wear, and Android Auto.
@@ -331,8 +335,8 @@ public class PlaybackService extends MediaBrowserServiceCompat {
isRunning = false;
currentMediaType = MediaType.UNKNOWN;
- PreferenceManager.getDefaultSharedPreferences(this)
- .unregisterOnSharedPreferenceChangeListener(prefListener);
+ cancelPositionObserver();
+ PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(prefListener);
if (mediaSession != null) {
mediaSession.release();
}
@@ -451,7 +455,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
notificationBuilder.loadIcon(getPlayable());
}
}
- startForeground(NOTIFICATION_ID, notificationBuilder.build());
+ stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build());
}
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
@@ -566,7 +570,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
if (status == PlayerStatus.PLAYING) {
- mediaPlayer.pause(!UserPreferences.isPersistNotify(), true);
+ mediaPlayer.pause(!UserPreferences.isPersistNotify(), false);
} else if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) {
mediaPlayer.resume();
} else if (status == PlayerStatus.PREPARING) {
@@ -590,7 +594,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
return true;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
if (status == PlayerStatus.PLAYING) {
- mediaPlayer.pause(!UserPreferences.isPersistNotify(), true);
+ mediaPlayer.pause(!UserPreferences.isPersistNotify(), false);
}
return true;
@@ -717,7 +721,8 @@ public class PlaybackService extends MediaBrowserServiceCompat {
updateMediaSession(newInfo.playerStatus);
switch (newInfo.playerStatus) {
case INITIALIZED:
- writePlaybackPreferences();
+ PlaybackPreferences.writeMediaPlaying(mediaPlayer.getPSMPInfo().playable,
+ mediaPlayer.getPSMPInfo().playerStatus, mediaPlayer.isStreaming());
break;
case PREPARED:
@@ -734,7 +739,8 @@ public class PlaybackService extends MediaBrowserServiceCompat {
// remove notification on pause
stateManager.stopForeground(true);
}
- writePlayerStatusPlaybackPreferences();
+ cancelPositionObserver();
+ PlaybackPreferences.writePlayerStatus(mediaPlayer.getPlayerStatus());
break;
case STOPPED:
@@ -743,8 +749,9 @@ public class PlaybackService extends MediaBrowserServiceCompat {
break;
case PLAYING:
- writePlayerStatusPlaybackPreferences();
+ PlaybackPreferences.writePlayerStatus(mediaPlayer.getPlayerStatus());
setupNotification(newInfo);
+ setupPositionUpdater();
stateManager.validStartCommandWasReceived();
// set sleep timer if auto-enabled
if (newInfo.oldPlayerStatus != null && newInfo.oldPlayerStatus != PlayerStatus.SEEKING &&
@@ -1023,85 +1030,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
EventBus.getDefault().post(new MessageEvent(getString(R.string.sleep_timer_disabled_label)));
}
- private int getCurrentPlayerStatusAsInt(PlayerStatus playerStatus) {
- int playerStatusAsInt;
- switch (playerStatus) {
- case PLAYING:
- playerStatusAsInt = PlaybackPreferences.PLAYER_STATUS_PLAYING;
- break;
- case PAUSED:
- playerStatusAsInt = PlaybackPreferences.PLAYER_STATUS_PAUSED;
- break;
- default:
- playerStatusAsInt = PlaybackPreferences.PLAYER_STATUS_OTHER;
- }
- return playerStatusAsInt;
- }
-
- private void writePlaybackPreferences() {
- 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();
- int playerStatus = getCurrentPlayerStatusAsInt(info.playerStatus);
-
- 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.putInt(
- PlaybackPreferences.PREF_CURRENT_PLAYER_STATUS, playerStatus);
-
- editor.commit();
- }
-
- private void writePlayerStatusPlaybackPreferences() {
- Log.d(TAG, "Writing player status playback preferences");
-
- SharedPreferences.Editor editor = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext()).edit();
- int playerStatus = getCurrentPlayerStatusAsInt(mediaPlayer.getPlayerStatus());
-
- editor.putInt(
- PlaybackPreferences.PREF_CURRENT_PLAYER_STATUS, playerStatus);
-
- editor.commit();
- }
-
private void sendNotificationBroadcast(int type, int code) {
Intent intent = new Intent(ACTION_PLAYER_NOTIFICATION);
intent.putExtra(EXTRA_NOTIFICATION_TYPE, type);
@@ -1656,6 +1584,24 @@ public class PlaybackService extends MediaBrowserServiceCompat {
return mediaPlayer.getVideoSize();
}
+ private void setupPositionUpdater() {
+ if (positionEventTimer != null) {
+ positionEventTimer.dispose();
+ }
+
+ Log.d(TAG, "Setting up position observer");
+ positionEventTimer = Observable.interval(1, TimeUnit.SECONDS)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(aLong ->
+ EventBus.getDefault().post(new PlaybackPositionEvent(getCurrentPosition(), getDuration())));
+ }
+
+ private void cancelPositionObserver() {
+ if (positionEventTimer != null) {
+ positionEventTimer.dispose();
+ }
+ }
+
private final MediaSessionCompat.Callback sessionCallback = new MediaSessionCompat.Callback() {
private static final String TAG = "MediaSessionCompat";
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
index b8198fa63..bc009e2bc 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
@@ -2,8 +2,8 @@ package de.danoeh.antennapod.core.service.playback;
import android.content.Context;
import android.net.wifi.WifiManager;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
import android.util.Log;
import android.util.Pair;
import android.view.SurfaceHolder;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java
index 0e7339ac4..b809ad659 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java
@@ -1,13 +1,18 @@
package de.danoeh.antennapod.core.service.playback;
+import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.VectorDrawable;
import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.v4.app.NotificationCompat;
+import androidx.annotation.NonNull;
+import androidx.core.app.NotificationCompat;
+import androidx.core.content.ContextCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.util.Log;
import android.view.KeyEvent;
@@ -99,12 +104,32 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build
public void loadDefaultIcon() {
if (defaultIcon == null) {
- defaultIcon = BitmapFactory.decodeResource(context.getResources(),
- ClientConfig.playbackServiceCallbacks.getNotificationIconResource(context));
+ defaultIcon = getBitmap(context, R.drawable.notification_default_large_icon);
}
setLargeIcon(defaultIcon);
}
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private static Bitmap getBitmap(VectorDrawable vectorDrawable) {
+ Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
+ vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ vectorDrawable.draw(canvas);
+ return bitmap;
+ }
+
+ private static Bitmap getBitmap(Context context, int drawableId) {
+ Drawable drawable = ContextCompat.getDrawable(context, drawableId);
+ if (drawable instanceof BitmapDrawable) {
+ return ((BitmapDrawable) drawable).getBitmap();
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable instanceof VectorDrawable) {
+ return getBitmap((VectorDrawable) drawable);
+ } else {
+ return null;
+ }
+ }
+
private void addActions(MediaSessionCompat.Token mediaSessionToken, PlayerStatus playerStatus, boolean isCasting) {
IntList compactActionList = new IntList();
@@ -115,7 +140,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build
stopCastingIntent.putExtra(PlaybackService.EXTRA_CAST_DISCONNECT, true);
PendingIntent stopCastingPendingIntent = PendingIntent.getService(context,
numActions, stopCastingIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- addAction(R.drawable.ic_media_cast_disconnect,
+ addAction(R.drawable.ic_notification_cast_off,
context.getString(R.string.cast_disconnect_label),
stopCastingPendingIntent);
numActions++;
@@ -124,7 +149,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build
// always let them rewind
PendingIntent rewindButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_REWIND, numActions);
- addAction(android.R.drawable.ic_media_rew, context.getString(R.string.rewind_label), rewindButtonPendingIntent);
+ addAction(R.drawable.ic_notification_fast_rewind, context.getString(R.string.rewind_label), rewindButtonPendingIntent);
if (UserPreferences.showRewindOnCompactNotification()) {
compactActionList.add(numActions);
}
@@ -133,14 +158,14 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build
if (playerStatus == PlayerStatus.PLAYING) {
PendingIntent pauseButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_PAUSE, numActions);
- addAction(android.R.drawable.ic_media_pause, //pause action
+ addAction(R.drawable.ic_notification_pause, //pause action
context.getString(R.string.pause_label),
pauseButtonPendingIntent);
compactActionList.add(numActions++);
} else {
PendingIntent playButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_PLAY, numActions);
- addAction(android.R.drawable.ic_media_play, //play action
+ addAction(R.drawable.ic_notification_play, //play action
context.getString(R.string.play_label),
playButtonPendingIntent);
compactActionList.add(numActions++);
@@ -149,7 +174,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build
// ff follows play, then we have skip (if it's present)
PendingIntent ffButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, numActions);
- addAction(android.R.drawable.ic_media_ff, context.getString(R.string.fast_forward_label), ffButtonPendingIntent);
+ addAction(R.drawable.ic_notification_fast_forward, context.getString(R.string.fast_forward_label), ffButtonPendingIntent);
if (UserPreferences.showFastForwardOnCompactNotification()) {
compactActionList.add(numActions);
}
@@ -158,7 +183,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build
if (UserPreferences.isFollowQueue()) {
PendingIntent skipButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_NEXT, numActions);
- addAction(android.R.drawable.ic_media_next,
+ addAction(R.drawable.ic_notification_skip,
context.getString(R.string.skip_episode_label),
skipButtonPendingIntent);
if (UserPreferences.showSkipOnCompactNotification()) {
@@ -169,7 +194,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build
PendingIntent stopButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_STOP, numActions);
- setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
+ setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
.setMediaSession(mediaSessionToken)
.setShowActionsInCompactView(compactActionList.toArray())
.setShowCancelButton(true)
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
index 68839023e..1cf271a29 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
@@ -4,9 +4,12 @@ import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Vibrator;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@@ -14,13 +17,12 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.playback.Playable;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
import io.reactivex.Completable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@@ -102,6 +104,34 @@ public class PlaybackServiceTaskManager {
}
}
+ @Subscribe
+ public void onEvent(FeedItemEvent event) {
+ // Use case: when an item in the queue has been downloaded,
+ // listening to the event to ensure the downloaded item will be used.
+ Log.d(TAG, "onEvent(FeedItemEvent " + event + ")");
+
+ for (FeedItem item : event.items) {
+ if (isItemInQueue(item.getId())) {
+ Log.d(TAG, "onEvent(FeedItemEvent) - some item (" + item.getId() + ") in the queue has been updated (usually downloaded). Refresh the queue.");
+ cancelQueueLoader();
+ loadQueue();
+ return;
+ }
+ }
+ }
+
+ private boolean isItemInQueue(long itemId) {
+ List<FeedItem> queue = getQueueIfLoaded();
+ if (queue != null) {
+ for (FeedItem item : queue) {
+ if (item.getId() == itemId) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
/**
* 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()
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java
index c63ac4416..b88793e87 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.core.storage;
import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.annotation.VisibleForTesting;
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import android.util.Log;
import java.util.ArrayList;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java
index 04b200699..dfe0b5201 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.storage;
import android.content.Context;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import java.util.ArrayList;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
index 70d3ba9dd..948a21efc 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
@@ -1,9 +1,9 @@
package de.danoeh.antennapod.core.storage;
import android.database.Cursor;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.util.ArrayMap;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.collection.ArrayMap;
import android.text.TextUtils;
import android.util.Log;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
index e68bff16e..46fa4b99c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
@@ -3,7 +3,8 @@ package de.danoeh.antennapod.core.storage;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
-import android.support.annotation.Nullable;
+import android.os.Looper;
+import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
@@ -144,58 +145,36 @@ public final class DBTasks {
private static final 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
+ * Refreshes all feeds.
+ * It must not be from the main 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) {
- refreshAllFeeds(context, feeds, null);
- }
-
- /**
- * 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.
- * @param callback Called after everything was added enqueued for download. Might be null.
- */
- public static void refreshAllFeeds(final Context context, final List<Feed> feeds, @Nullable Runnable callback) {
+ public static void refreshAllFeeds(final Context context) {
if (!isRefreshing.compareAndSet(false, true)) {
Log.d(TAG, "Ignoring request to refresh all feeds: Refresh lock is locked");
return;
}
- new Thread(() -> {
- if (feeds != null) {
- refreshFeeds(context, feeds);
- } else {
- refreshFeeds(context, DBReader.getFeedList());
- }
- isRefreshing.set(false);
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ throw new IllegalStateException("DBTasks.refreshAllFeeds() must not be called from the main thread.");
+ }
- SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE);
- prefs.edit().putLong(PREF_LAST_REFRESH, System.currentTimeMillis()).apply();
+ refreshFeeds(context, DBReader.getFeedList());
+ isRefreshing.set(false);
- if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) {
- GpodnetSyncService.sendSyncIntent(context);
- }
- // Note: automatic download of episodes will be done but not here.
- // Instead it is done after all feeds have been refreshed (asynchronously),
- // in DownloadService.onDestroy()
- // See Issue #2577 for the details of the rationale
+ SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE);
+ prefs.edit().putLong(PREF_LAST_REFRESH, System.currentTimeMillis()).apply();
- if (callback != null) {
- callback.run();
- }
- }).start();
- }
-
- public static long getLastRefreshAllFeedsTimeMillis(final Context context) {
- SharedPreferences prefs = context.getSharedPreferences(DBTasks.PREF_NAME, MODE_PRIVATE);
- return prefs.getLong(DBTasks.PREF_LAST_REFRESH, 0);
+ if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) {
+ GpodnetSyncService.sendSyncIntent(context);
+ }
+ // Note: automatic download of episodes will be done but not here.
+ // Instead it is done after all feeds have been refreshed (asynchronously),
+ // in DownloadService.onDestroy()
+ // See Issue #2577 for the details of the rationale
}
/**
@@ -462,10 +441,9 @@ public final class DBTasks {
/**
* Get a FeedItem by its identifying value.
*/
- private static FeedItem searchFeedItemByIdentifyingValue(Feed feed,
- String identifier) {
+ private static FeedItem searchFeedItemByIdentifyingValue(Feed feed, String identifier) {
for (FeedItem item : feed.getItems()) {
- if (item.getIdentifyingValue().equals(identifier)) {
+ if (TextUtils.equals(item.getIdentifyingValue(), identifier)) {
return item;
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
index 4f0ee70ef..11d90e57c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
@@ -2,10 +2,7 @@ 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.preference.PreferenceManager;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import org.greenrobot.eventbus.EventBus;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java
index 892a4675a..71f6845c5 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java
@@ -3,8 +3,8 @@ package de.danoeh.antennapod.core.storage;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.URLUtil;
@@ -34,7 +34,6 @@ import de.danoeh.antennapod.core.util.URLChecker;
public class DownloadRequester {
private static final String TAG = "DownloadRequester";
- public static final String IMAGE_DOWNLOADPATH = "images/";
private static final String FEED_DOWNLOADPATH = "cache/";
private static final String MEDIA_DOWNLOADPATH = "media/";
@@ -274,10 +273,6 @@ public class DownloadRequester {
return item.getDownload_url() != null && downloads.containsKey(item.getDownload_url());
}
- public synchronized DownloadRequest getDownload(String downloadUrl) {
- return downloads.get(downloadUrl);
- }
-
/**
* Checks if feedfile with the given download url is in the downloads list
*/
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java b/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java
index c6620a90e..0c8d20007 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.storage;
import android.content.Context;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
index 0c93590e2..4de83f548 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
@@ -13,6 +13,8 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Build;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
@@ -25,8 +27,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
-import de.danoeh.antennapod.core.R;
-import de.danoeh.antennapod.core.event.ProgressEvent;
import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -35,7 +35,6 @@ import de.danoeh.antennapod.core.feed.FeedPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
import de.danoeh.antennapod.core.util.LongIntMap;
-import org.greenrobot.eventbus.EventBus;
import static de.danoeh.antennapod.core.feed.FeedMedia.LAST_PLAYBACK_SPEED_UNSET;
import static de.danoeh.antennapod.core.feed.FeedPreferences.SPEED_USE_GLOBAL;
@@ -55,16 +54,10 @@ public class PodDBAdapter {
*/
private static final int IN_OPERATOR_MAXIMUM = 800;
- /**
- * Maximum number of entries per search request.
- */
- public static final int SEARCH_LIMIT = 30;
-
// Key-constants
public static final String KEY_ID = "id";
public static final String KEY_TITLE = "title";
public static final String KEY_CUSTOM_TITLE = "custom_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";
@@ -1410,13 +1403,6 @@ public class PodDBAdapter {
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.
@@ -1501,11 +1487,9 @@ public class PodDBAdapter {
@Override
public void onUpgrade(final SQLiteDatabase db, final int oldVersion,
final int newVersion) {
- EventBus.getDefault().post(ProgressEvent.start(context.getString(R.string.progress_upgrading_database)));
Log.w("DBAdapter", "Upgrading from version " + oldVersion + " to "
+ newVersion + ".");
DBUpgrader.upgrade(db, oldVersion, newVersion);
- EventBus.getDefault().post(ProgressEvent.end());
}
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java
index 1cd05aa26..608cade88 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.syndication.handler;
-import android.support.v4.util.ArrayMap;
+import androidx.collection.ArrayMap;
import java.util.ArrayList;
import java.util.Map;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java
index e6d4ed6b7..300e0038a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.util;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.util.Log;
import org.apache.commons.io.IOUtils;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/DuckType.java b/core/src/main/java/de/danoeh/antennapod/core/util/DuckType.java
deleted file mode 100644
index 69dc38895..000000000
--- a/core/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.core.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")
- private 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/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java b/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java
index 826c06822..a8206d3bd 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java
@@ -7,19 +7,6 @@ import de.danoeh.antennapod.core.feed.FeedItem;
public class FeedItemUtil {
private FeedItemUtil(){}
- public static int indexOfItemWithDownloadUrl(List<FeedItem> items, String downloadUrl) {
- if(items == null) {
- return -1;
- }
- for(int i=0; i < items.size(); i++) {
- FeedItem item = items.get(i);
- if(item.hasMedia() && item.getMedia().getDownload_url().equals(downloadUrl)) {
- return i;
- }
- }
- return -1;
- }
-
public static int indexOfItemWithId(List<FeedItem> items, long id) {
for(int i=0; i < items.size(); i++) {
FeedItem item = items.get(i);
@@ -40,17 +27,6 @@ public class FeedItemUtil {
return -1;
}
- public static long[] getIds(FeedItem... items) {
- if(items == null || items.length == 0) {
- return new long[0];
- }
- long[] result = new long[items.length];
- for(int i=0; i < items.length; i++) {
- result[i] = items[i].getId();
- }
- return result;
- }
-
public static long[] getIds(List<FeedItem> items) {
if(items == null || items.size() == 0) {
return new long[0];
@@ -62,20 +38,6 @@ public class FeedItemUtil {
return result;
}
- public static boolean containsAnyId(List<FeedItem> items, long[] ids) {
- if(items == null || items.size() == 0) {
- return false;
- }
- for(FeedItem item : items) {
- for(long id : ids) {
- if(item.getId() == id) {
- return true;
- }
- }
- }
- return false;
- }
-
/**
* Get the link for the feed item for the purpose of Share. It fallbacks to
* use the feed's link if the named feed item has no link.
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java
deleted file mode 100644
index b425687ae..000000000
--- a/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import android.content.Context;
-import android.util.Log;
-
-import org.awaitility.core.ConditionTimeoutException;
-
-import java.util.concurrent.TimeUnit;
-
-import de.danoeh.antennapod.core.storage.DBTasks;
-
-import static org.awaitility.Awaitility.with;
-
-public class FeedUpdateUtils {
- private static final String TAG = "FeedUpdateUtils";
-
- private FeedUpdateUtils() {}
-
- public static void startAutoUpdate(Context context, Runnable callback) {
- // the network check is blocking for possibly a long time: so run the logic
- // in a separate thread to prevent the code blocking the callers
- final Runnable runnable = () -> {
- try {
- with().pollInterval(1, TimeUnit.SECONDS)
- .await()
- .atMost(10, TimeUnit.SECONDS)
- .until(() -> NetworkUtils.networkAvailable() && NetworkUtils.isFeedRefreshAllowed());
- DBTasks.refreshAllFeeds(context, null, callback);
- } catch (ConditionTimeoutException ignore) {
- Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed");
- }
- };
- new Thread(runnable).start();
- }
-
-}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/FeedtitleComparator.java b/core/src/main/java/de/danoeh/antennapod/core/util/FeedtitleComparator.java
deleted file mode 100644
index 29d095cd2..000000000
--- a/core/src/main/java/de/danoeh/antennapod/core/util/FeedtitleComparator.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package de.danoeh.antennapod.core.util;
-
-import java.util.Comparator;
-
-import de.danoeh.antennapod.core.feed.Feed;
-
-/** Compares the title of two feeds for sorting. */
-class FeedtitleComparator implements Comparator<Feed> {
-
- @Override
- public int compare(Feed lhs, Feed rhs) {
- return lhs.getTitle().compareToIgnoreCase(rhs.getTitle());
- }
-
-}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/IntentUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/IntentUtils.java
index e81ab47ed..656b518bf 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/IntentUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/IntentUtils.java
@@ -1,13 +1,20 @@
package de.danoeh.antennapod.core.util;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.util.Log;
+import android.widget.Toast;
+import de.danoeh.antennapod.core.R;
import java.util.List;
public class IntentUtils {
+ private static final String TAG = "IntentUtils";
+
private IntentUtils(){}
/*
@@ -28,4 +35,13 @@ public class IntentUtils {
context.sendBroadcast(new Intent(action).setPackage(context.getPackageName()));
}
+ public static void openInBrowser(Context context, String url) {
+ try {
+ Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ context.startActivity(myIntent);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(context, R.string.pref_no_browser_found, Toast.LENGTH_LONG).show();
+ Log.e(TAG, Log.getStackTraceString(e));
+ }
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java
index 90e0b0981..20af6415e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.util;
-import android.support.v4.util.ArrayMap;
+import androidx.collection.ArrayMap;
import java.nio.charset.Charset;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java
index ca48c9bc9..a9e46e42c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java
@@ -5,7 +5,7 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
-import android.support.v4.net.ConnectivityManagerCompat;
+import androidx.core.net.ConnectivityManagerCompat;
import android.text.TextUtils;
import android.util.Log;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/Optional.java b/core/src/main/java/de/danoeh/antennapod/core/util/Optional.java
index 0fe11ec53..37f12c01c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/Optional.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/Optional.java
@@ -77,7 +77,7 @@ public final class Optional<T> {
* @param <T> Type of the non-existent value
* @return an empty {@code Optional}
*/
- public static<T> Optional<T> empty() {
+ public static <T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java b/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java
index 37172d042..0c21ca393 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java
@@ -164,7 +164,7 @@ public class QueueSorter {
Collections.sort(feedItems, itemComparator);
if (spread == 0) {
spread = feedItems.size();
- } else if (feedItems.size() % spread != 0){
+ } else if (spread % feedItems.size() != 0){
spread *= feedItems.size();
}
}
@@ -180,6 +180,9 @@ public class QueueSorter {
Map<Long, List<FeedItem>> spreadItems = new HashMap<>();
for (List<FeedItem> feedItems : feeds) {
long thisSpread = spread / feedItems.size();
+ if (thisSpread == 0) {
+ thisSpread = 1;
+ }
// Starting from 0 ensures we front-load, so the queue starts with one episode from
// each feed in the queue
long itemSpread = 0;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java
index 5ae00460e..3e9e8327e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java
@@ -6,7 +6,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
-import android.support.v4.content.FileProvider;
+import androidx.core.content.FileProvider;
import android.util.Log;
import java.io.File;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ThemeUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/ThemeUtils.java
index 1da7a5c50..eabaaa828 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/ThemeUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/ThemeUtils.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.core.util;
import android.content.Context;
-import android.support.annotation.AttrRes;
-import android.support.annotation.ColorInt;
+import androidx.annotation.AttrRes;
+import androidx.annotation.ColorInt;
import android.util.TypedValue;
public class ThemeUtils {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java b/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java
index ffc6a6e28..7e3870a20 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.util;
import android.net.Uri;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import de.danoeh.antennapod.core.BuildConfig;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/comparator/SearchResultValueComparator.java b/core/src/main/java/de/danoeh/antennapod/core/util/comparator/SearchResultValueComparator.java
deleted file mode 100644
index 56a684475..000000000
--- a/core/src/main/java/de/danoeh/antennapod/core/util/comparator/SearchResultValueComparator.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package de.danoeh.antennapod.core.util.comparator;
-
-import java.util.Comparator;
-
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.feed.SearchResult;
-
-public class SearchResultValueComparator implements Comparator<SearchResult> {
-
- /**
- * Compare items based, first, on where they were found (ie. title, chapters, or show notes).
- * If they were found in the same section, then compare based on the title, in lexicographic
- * order. This is still not ideal since, for example, "#12 Example A" would be considered
- * before "#8 Example B" due to the fact that "8" has a larger unicode value than "1"
- */
- @Override
- public int compare(SearchResult lhs, SearchResult rhs) {
- int value = rhs.getValue() - lhs.getValue();
- if (value == 0 && lhs.getComponent() instanceof FeedItem && rhs.getComponent() instanceof FeedItem) {
- String lhsTitle = ((FeedItem) lhs.getComponent()).getTitle();
- String rhsTitle = ((FeedItem) rhs.getComponent()).getTitle();
- return lhsTitle.compareTo(rhsTitle);
- }
- return value;
- }
-
-}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java
index 412b150fa..e093a7e00 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java
@@ -1,21 +1,29 @@
package de.danoeh.antennapod.core.util.download;
+import android.content.Context;
+import androidx.annotation.NonNull;
import android.util.Log;
+
import androidx.work.Constraints;
+import androidx.work.Data;
import androidx.work.ExistingPeriodicWorkPolicy;
import androidx.work.ExistingWorkPolicy;
import androidx.work.NetworkType;
import androidx.work.OneTimeWorkRequest;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkManager;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.service.FeedUpdateWorker;
+import java.util.Arrays;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.service.FeedUpdateWorker;
+import de.danoeh.antennapod.core.storage.DBTasks;
+
public class AutoUpdateManager {
- private static final String WORK_ID_FEED_UPDATE = FeedUpdateWorker.class.getName();
+ private static final String WORK_ID_FEED_UPDATE = "de.danoeh.antennapod.core.service.FeedUpdateWorker";
+ private static final String WORK_ID_FEED_UPDATE_ONCE = WORK_ID_FEED_UPDATE + "Once";
private static final String TAG = "AutoUpdateManager";
private AutoUpdateManager() {
@@ -23,9 +31,25 @@ public class AutoUpdateManager {
}
/**
+ * Start / restart periodic auto feed refresh
+ */
+ public static void restartUpdateAlarm() {
+ if (UserPreferences.isAutoUpdateDisabled()) {
+ disableAutoUpdate();
+ } else if (UserPreferences.isAutoUpdateTimeOfDay()) {
+ int[] timeOfDay = UserPreferences.getUpdateTimeOfDay();
+ Log.d(TAG, "timeOfDay: " + Arrays.toString(timeOfDay));
+ restartUpdateTimeOfDayAlarm(timeOfDay[0], timeOfDay[1]);
+ } else {
+ long milliseconds = UserPreferences.getUpdateInterval();
+ restartUpdateIntervalAlarm(milliseconds);
+ }
+ }
+
+ /**
* Sets the interval in which the feeds are refreshed automatically
*/
- public static void restartUpdateIntervalAlarm(long intervalMillis) {
+ private static void restartUpdateIntervalAlarm(long intervalMillis) {
Log.d(TAG, "Restarting update alarm.");
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(FeedUpdateWorker.class,
@@ -40,7 +64,7 @@ public class AutoUpdateManager {
/**
* Sets time of day the feeds are refreshed automatically
*/
- public static void restartUpdateTimeOfDayAlarm(int hoursOfDay, int minute) {
+ private static void restartUpdateTimeOfDayAlarm(int hoursOfDay, int minute) {
Log.d(TAG, "Restarting update alarm.");
Calendar now = Calendar.getInstance();
@@ -60,6 +84,41 @@ public class AutoUpdateManager {
WorkManager.getInstance().enqueueUniqueWork(WORK_ID_FEED_UPDATE, ExistingWorkPolicy.REPLACE, workRequest);
}
+ /**
+ * Run auto feed refresh once in background, as soon as what OS scheduling allows.
+ *
+ * Callers from UI should use {@link #runImmediate(Context)}, as it will guarantee
+ * the refresh be run immediately.
+ */
+ public static void runOnce() {
+ Log.d(TAG, "Run auto update once, as soon as OS allows.");
+
+ OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(FeedUpdateWorker.class)
+ .setConstraints(getConstraints())
+ .setInitialDelay(0L, TimeUnit.MILLISECONDS)
+ .setInputData(new Data.Builder()
+ .putBoolean(FeedUpdateWorker.PARAM_RUN_ONCE, true)
+ .build()
+ )
+ .build();
+
+ WorkManager.getInstance().enqueueUniqueWork(WORK_ID_FEED_UPDATE_ONCE, ExistingWorkPolicy.REPLACE, workRequest);
+
+ }
+
+ /**
+ /**
+ * Run auto feed refresh once in background immediately, using its own thread.
+ *
+ * Callers where the additional threads is not suitable should use {@link #runOnce()}
+ */
+ public static void runImmediate(@NonNull Context context) {
+ Log.d(TAG, "Run auto update immediately in background.");
+ new Thread(() -> {
+ DBTasks.refreshAllFeeds(context.getApplicationContext());
+ }, "ManualRefreshAllFeeds").start();
+ }
+
public static void disableAutoUpdate() {
WorkManager.getInstance().cancelUniqueWork(WORK_ID_FEED_UPDATE);
}
@@ -74,4 +133,5 @@ public class AutoUpdateManager {
}
return constraints.build();
}
+
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/exception/RxJavaErrorHandlerSetup.java b/core/src/main/java/de/danoeh/antennapod/core/util/exception/RxJavaErrorHandlerSetup.java
index 12f0c1c6e..223104d2e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/exception/RxJavaErrorHandlerSetup.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/exception/RxJavaErrorHandlerSetup.java
@@ -1,12 +1,9 @@
package de.danoeh.antennapod.core.util.exception;
import android.util.Log;
-import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException;
import io.reactivex.exceptions.UndeliverableException;
import io.reactivex.plugins.RxJavaPlugins;
-import java.io.InterruptedIOException;
-
public class RxJavaErrorHandlerSetup {
private RxJavaErrorHandlerSetup() {
@@ -14,21 +11,14 @@ public class RxJavaErrorHandlerSetup {
}
public static void setupRxJavaErrorHandler() {
- RxJavaPlugins.setErrorHandler(originalCause -> {
- Throwable e = originalCause;
+ RxJavaPlugins.setErrorHandler(e -> {
if (e instanceof UndeliverableException) {
- e = e.getCause();
- }
- if (e instanceof GpodnetServiceException) {
- e = e.getCause();
- }
- if (e instanceof InterruptedException || e instanceof InterruptedIOException) {
- // fine, some blocking code was interrupted by a dispose call
- Log.d("RxJavaErrorHandler", "Ignored exception: " + Log.getStackTraceString(originalCause));
+ // Probably just disposed because the fragment was left
+ Log.d("RxJavaErrorHandler", "Ignored exception: " + Log.getStackTraceString(e));
return;
}
Thread.currentThread().getUncaughtExceptionHandler()
- .uncaughtException(Thread.currentThread(), originalCause);
+ .uncaughtException(Thread.currentThread(), e);
});
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/gui/NotificationUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/gui/NotificationUtils.java
index 52a43aab2..02e98ba84 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/gui/NotificationUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/gui/NotificationUtils.java
@@ -5,7 +5,7 @@ import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
-import android.support.annotation.RequiresApi;
+import androidx.annotation.RequiresApi;
import de.danoeh.antennapod.core.R;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java
index d22d08e09..a3f747e09 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java
@@ -72,7 +72,7 @@ public class ChapterReader extends ID3Reader {
String decodedLink = URLDecoder.decode(link.toString(), "UTF-8");
currentChapter.setLink(decodedLink);
Log.d(TAG, "Found link: " + currentChapter.getLink());
- } catch (IllegalArgumentException _iae) {
+ } catch (IllegalArgumentException iae) {
Log.w(TAG, "Bad URL found in ID3 data");
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java
index 645bae5f3..9b644c3ba 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java
@@ -182,7 +182,7 @@ public class ExternalMedia implements Playable {
editor.putLong(PREF_LAST_PLAYED_TIME, timestamp);
position = newPosition;
lastPlayedTime = timestamp;
- editor.commit();
+ editor.apply();
}
@Override
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java
index da9b96430..378c47faf 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java
@@ -4,7 +4,7 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.os.Parcelable;
import android.preference.PreferenceManager;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import android.util.Log;
import java.util.List;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
index 9caa2156d..8328ea577 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
@@ -11,8 +11,8 @@ import android.content.res.TypedArray;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.IBinder;
-import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -21,9 +21,7 @@ import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
-import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.event.ServiceEvent;
@@ -69,9 +67,6 @@ public class PlaybackController {
private final ScheduledThreadPoolExecutor schedExecutor;
private static final int SCHED_EX_POOLSIZE = 1;
- private MediaPositionObserver positionObserver;
- private ScheduledFuture<?> positionObserverFuture;
-
private boolean mediaInfoLoaded = false;
private boolean released = false;
private boolean initialized = false;
@@ -177,7 +172,6 @@ public class PlaybackController {
} catch (IllegalArgumentException e) {
// ignore
}
- cancelPositionObserver();
schedExecutor.shutdownNow();
media = null;
released = true;
@@ -254,29 +248,6 @@ public class PlaybackController {
.getIntent());
}
-
-
- private void setupPositionObserver() {
- if (positionObserverFuture == null ||
- positionObserverFuture.isCancelled() ||
- positionObserverFuture.isDone()) {
-
- 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);
- Log.d(TAG, "PositionObserver cancelled. Result: " + result);
- }
- }
-
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if(service instanceof PlaybackService.LocalBinder) {
@@ -337,7 +308,6 @@ public class PlaybackController {
onBufferUpdate(progress);
break;
case PlaybackService.NOTIFICATION_TYPE_RELOAD:
- cancelPositionObserver();
mediaInfoLoaded = false;
queryService();
onReloadNotification(intent.getIntExtra(
@@ -447,7 +417,6 @@ public class PlaybackController {
case PAUSED:
clearStatusMsg();
checkMediaInfoLoaded();
- cancelPositionObserver();
onPositionObserverUpdate();
updatePlayButtonAppearance(playResource, playText);
if (!PlaybackService.isCasting() &&
@@ -463,7 +432,6 @@ public class PlaybackController {
onAwaitingVideoSurface();
setScreenOn(true);
}
- setupPositionObserver();
updatePlayButtonAppearance(pauseResource, pauseText);
break;
case PREPARING:
@@ -581,7 +549,6 @@ public class PlaybackController {
*/
public void onSeekBarStartTrackingTouch(SeekBar seekBar) {
// interrupt position Observer, restart later
- cancelPositionObserver();
}
/**
@@ -590,7 +557,6 @@ public class PlaybackController {
public void onSeekBarStopTrackingTouch(SeekBar seekBar, float prog) {
if (playbackService != null && media != null) {
playbackService.seekTo((int) (prog * media.getDuration()));
- setupPositionObserver();
}
}
@@ -728,6 +694,8 @@ public class PlaybackController {
public void setPlaybackSpeed(float speed) {
if (playbackService != null) {
playbackService.setSpeed(speed);
+ } else {
+ onPlaybackSpeedChange();
}
}
public void setSkipSilence(boolean skipSilence) {
@@ -834,19 +802,4 @@ public class PlaybackController {
}
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
-
- /**
- * Refreshes the current position of the media file that is playing.
- */
- public class MediaPositionObserver implements Runnable {
-
- static final int WAITING_INTERVALL = 1000;
-
- @Override
- public void run() {
- if (playbackService != null && playbackService.getStatus() == PlayerStatus.PLAYING) {
- activity.runOnUiThread(PlaybackController.this::onPositionObserverUpdate);
- }
- }
- }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java
index f7d2ee409..01ca97134 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java
@@ -2,9 +2,8 @@ package de.danoeh.antennapod.core.util.playback;
import android.content.Context;
import android.content.Intent;
-import android.media.MediaPlayer;
-import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
index 75229b9cf..0fe1f0036 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
@@ -3,11 +3,10 @@ package de.danoeh.antennapod.core.util.playback;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
-import android.support.annotation.ColorInt;
-import android.support.annotation.NonNull;
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
-import android.util.Pair;
import android.util.TypedValue;
import org.jsoup.Jsoup;
@@ -15,7 +14,6 @@ import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
-import java.util.ArrayList;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java b/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java
index c5ad9cfd6..a474756e9 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.util.syndication;
import android.net.Uri;
-import android.support.v4.util.ArrayMap;
+import androidx.collection.ArrayMap;
import android.text.TextUtils;
import org.jsoup.Jsoup;
diff --git a/core/src/main/res/drawable-hdpi/ic_baseline_question_answer_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_baseline_question_answer_white_24dp.png
deleted file mode 100755
index 67924a5a2..000000000
--- a/core/src/main/res/drawable-hdpi/ic_baseline_question_answer_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_cast_disabled_light.png b/core/src/main/res/drawable-hdpi/ic_cast_disabled_light.png
deleted file mode 100644
index c0a55d555..000000000
--- a/core/src/main/res/drawable-hdpi/ic_cast_disabled_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_cast_light.png b/core/src/main/res/drawable-hdpi/ic_cast_light.png
deleted file mode 100644
index b0c581a0e..000000000
--- a/core/src/main/res/drawable-hdpi/ic_cast_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_cast_off_light.png b/core/src/main/res/drawable-hdpi/ic_cast_off_light.png
deleted file mode 100644
index 5f3c0179c..000000000
--- a/core/src/main/res/drawable-hdpi/ic_cast_off_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_cast_on_0_light.png b/core/src/main/res/drawable-hdpi/ic_cast_on_0_light.png
deleted file mode 100644
index e872693a4..000000000
--- a/core/src/main/res/drawable-hdpi/ic_cast_on_0_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_cast_on_1_light.png b/core/src/main/res/drawable-hdpi/ic_cast_on_1_light.png
deleted file mode 100644
index d8be1ebc6..000000000
--- a/core/src/main/res/drawable-hdpi/ic_cast_on_1_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_cast_on_2_light.png b/core/src/main/res/drawable-hdpi/ic_cast_on_2_light.png
deleted file mode 100644
index 27cda9e9d..000000000
--- a/core/src/main/res/drawable-hdpi/ic_cast_on_2_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_cast_on_light.png b/core/src/main/res/drawable-hdpi/ic_cast_on_light.png
deleted file mode 100644
index 4ee525875..000000000
--- a/core/src/main/res/drawable-hdpi/ic_cast_on_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_close_light.png b/core/src/main/res/drawable-hdpi/ic_close_light.png
deleted file mode 100644
index 93187e450..000000000
--- a/core/src/main/res/drawable-hdpi/ic_close_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_format_list_bulleted_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_format_list_bulleted_grey600_24dp.png
deleted file mode 100644
index 3668c9a00..000000000
--- a/core/src/main/res/drawable-hdpi/ic_format_list_bulleted_grey600_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_format_list_bulleted_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_format_list_bulleted_white_24dp.png
deleted file mode 100644
index a1a2c5b68..000000000
--- a/core/src/main/res/drawable-hdpi/ic_format_list_bulleted_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_forum_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_forum_grey600_24dp.png
deleted file mode 100644
index da5398d15..000000000
--- a/core/src/main/res/drawable-hdpi/ic_forum_grey600_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_media_cast_disconnect.png b/core/src/main/res/drawable-hdpi/ic_media_cast_disconnect.png
deleted file mode 100644
index 700c116e5..000000000
--- a/core/src/main/res/drawable-hdpi/ic_media_cast_disconnect.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_pause_light.png b/core/src/main/res/drawable-hdpi/ic_pause_light.png
deleted file mode 100644
index 0c505d1c8..000000000
--- a/core/src/main/res/drawable-hdpi/ic_pause_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_play_light.png b/core/src/main/res/drawable-hdpi/ic_play_light.png
deleted file mode 100644
index 7957dff5b..000000000
--- a/core/src/main/res/drawable-hdpi/ic_play_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_stat_antenna_default.png b/core/src/main/res/drawable-hdpi/ic_stat_antenna_default.png
deleted file mode 100644
index af99f4b3b..000000000
--- a/core/src/main/res/drawable-hdpi/ic_stat_antenna_default.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_stat_authentication.png b/core/src/main/res/drawable-hdpi/ic_stat_authentication.png
deleted file mode 100644
index 398dffa4b..000000000
--- a/core/src/main/res/drawable-hdpi/ic_stat_authentication.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-ldpi/ic_stat_antenna_default.png b/core/src/main/res/drawable-ldpi/ic_stat_antenna_default.png
deleted file mode 100644
index ddf545c0b..000000000
--- a/core/src/main/res/drawable-ldpi/ic_stat_antenna_default.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_baseline_question_answer_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_baseline_question_answer_white_24dp.png
deleted file mode 100755
index e87df752e..000000000
--- a/core/src/main/res/drawable-mdpi/ic_baseline_question_answer_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_cast_disabled_light.png b/core/src/main/res/drawable-mdpi/ic_cast_disabled_light.png
deleted file mode 100644
index 7940a0332..000000000
--- a/core/src/main/res/drawable-mdpi/ic_cast_disabled_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_cast_light.png b/core/src/main/res/drawable-mdpi/ic_cast_light.png
deleted file mode 100644
index 1f5bec20b..000000000
--- a/core/src/main/res/drawable-mdpi/ic_cast_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_cast_off_light.png b/core/src/main/res/drawable-mdpi/ic_cast_off_light.png
deleted file mode 100644
index 963db27d4..000000000
--- a/core/src/main/res/drawable-mdpi/ic_cast_off_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_cast_on_0_light.png b/core/src/main/res/drawable-mdpi/ic_cast_on_0_light.png
deleted file mode 100644
index a90d9e305..000000000
--- a/core/src/main/res/drawable-mdpi/ic_cast_on_0_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_cast_on_1_light.png b/core/src/main/res/drawable-mdpi/ic_cast_on_1_light.png
deleted file mode 100644
index bb2cf30bf..000000000
--- a/core/src/main/res/drawable-mdpi/ic_cast_on_1_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_cast_on_2_light.png b/core/src/main/res/drawable-mdpi/ic_cast_on_2_light.png
deleted file mode 100644
index 3ed59e55b..000000000
--- a/core/src/main/res/drawable-mdpi/ic_cast_on_2_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_cast_on_light.png b/core/src/main/res/drawable-mdpi/ic_cast_on_light.png
deleted file mode 100644
index 713427b97..000000000
--- a/core/src/main/res/drawable-mdpi/ic_cast_on_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_close_light.png b/core/src/main/res/drawable-mdpi/ic_close_light.png
deleted file mode 100644
index 2c52c9b0f..000000000
--- a/core/src/main/res/drawable-mdpi/ic_close_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_format_list_bulleted_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_format_list_bulleted_grey600_24dp.png
deleted file mode 100644
index 726eae499..000000000
--- a/core/src/main/res/drawable-mdpi/ic_format_list_bulleted_grey600_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_format_list_bulleted_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_format_list_bulleted_white_24dp.png
deleted file mode 100644
index 0cc401dff..000000000
--- a/core/src/main/res/drawable-mdpi/ic_format_list_bulleted_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_forum_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_forum_grey600_24dp.png
deleted file mode 100644
index d3bcfe7b6..000000000
--- a/core/src/main/res/drawable-mdpi/ic_forum_grey600_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_media_cast_disconnect.png b/core/src/main/res/drawable-mdpi/ic_media_cast_disconnect.png
deleted file mode 100644
index 767f420df..000000000
--- a/core/src/main/res/drawable-mdpi/ic_media_cast_disconnect.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_pause_light.png b/core/src/main/res/drawable-mdpi/ic_pause_light.png
deleted file mode 100644
index 6218a774f..000000000
--- a/core/src/main/res/drawable-mdpi/ic_pause_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_play_light.png b/core/src/main/res/drawable-mdpi/ic_play_light.png
deleted file mode 100644
index 1e0ccaf80..000000000
--- a/core/src/main/res/drawable-mdpi/ic_play_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_stat_antenna_default.png b/core/src/main/res/drawable-mdpi/ic_stat_antenna_default.png
deleted file mode 100644
index 41fd20655..000000000
--- a/core/src/main/res/drawable-mdpi/ic_stat_antenna_default.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_stat_authentication.png b/core/src/main/res/drawable-mdpi/ic_stat_authentication.png
deleted file mode 100644
index 550b56b33..000000000
--- a/core/src/main/res/drawable-mdpi/ic_stat_authentication.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_baseline_question_answer_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_baseline_question_answer_white_24dp.png
deleted file mode 100755
index 731f89c83..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_baseline_question_answer_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_cast_disabled_light.png b/core/src/main/res/drawable-xhdpi/ic_cast_disabled_light.png
deleted file mode 100644
index fbb3e062c..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_cast_disabled_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_cast_light.png b/core/src/main/res/drawable-xhdpi/ic_cast_light.png
deleted file mode 100644
index f2713e20e..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_cast_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_cast_off_light.png b/core/src/main/res/drawable-xhdpi/ic_cast_off_light.png
deleted file mode 100644
index f4f8aaea8..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_cast_off_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_cast_on_0_light.png b/core/src/main/res/drawable-xhdpi/ic_cast_on_0_light.png
deleted file mode 100644
index 247fc95ba..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_cast_on_0_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_cast_on_1_light.png b/core/src/main/res/drawable-xhdpi/ic_cast_on_1_light.png
deleted file mode 100644
index ecf4b4723..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_cast_on_1_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_cast_on_2_light.png b/core/src/main/res/drawable-xhdpi/ic_cast_on_2_light.png
deleted file mode 100644
index 60e3afa5d..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_cast_on_2_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_cast_on_light.png b/core/src/main/res/drawable-xhdpi/ic_cast_on_light.png
deleted file mode 100644
index 40ce9d4f2..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_cast_on_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_close_light.png b/core/src/main/res/drawable-xhdpi/ic_close_light.png
deleted file mode 100644
index 49faa429a..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_close_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_format_list_bulleted_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_format_list_bulleted_grey600_24dp.png
deleted file mode 100644
index 322adb6e0..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_format_list_bulleted_grey600_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_format_list_bulleted_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_format_list_bulleted_white_24dp.png
deleted file mode 100644
index c25860017..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_format_list_bulleted_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_forum_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_forum_grey600_24dp.png
deleted file mode 100644
index ac6876140..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_forum_grey600_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_media_cast_disconnect.png b/core/src/main/res/drawable-xhdpi/ic_media_cast_disconnect.png
deleted file mode 100644
index 740867129..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_media_cast_disconnect.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_pause_light.png b/core/src/main/res/drawable-xhdpi/ic_pause_light.png
deleted file mode 100644
index 40cd79f14..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_pause_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_play_light.png b/core/src/main/res/drawable-xhdpi/ic_play_light.png
deleted file mode 100644
index 33f6a5919..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_play_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_stat_antenna_default.png b/core/src/main/res/drawable-xhdpi/ic_stat_antenna_default.png
deleted file mode 100644
index 30431ed6a..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_stat_antenna_default.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_stat_authentication.png b/core/src/main/res/drawable-xhdpi/ic_stat_authentication.png
deleted file mode 100644
index e83cbc333..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_stat_authentication.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_baseline_question_answer_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_baseline_question_answer_white_24dp.png
deleted file mode 100755
index 255b82707..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_baseline_question_answer_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_cast_disabled_light.png b/core/src/main/res/drawable-xxhdpi/ic_cast_disabled_light.png
deleted file mode 100644
index e94df3889..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_cast_disabled_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_cast_light.png b/core/src/main/res/drawable-xxhdpi/ic_cast_light.png
deleted file mode 100644
index c5722a6eb..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_cast_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_cast_off_light.png b/core/src/main/res/drawable-xxhdpi/ic_cast_off_light.png
deleted file mode 100644
index 92ac67b34..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_cast_off_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_cast_on_0_light.png b/core/src/main/res/drawable-xxhdpi/ic_cast_on_0_light.png
deleted file mode 100644
index 2742fcb4a..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_cast_on_0_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_cast_on_1_light.png b/core/src/main/res/drawable-xxhdpi/ic_cast_on_1_light.png
deleted file mode 100644
index 405178e64..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_cast_on_1_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_cast_on_2_light.png b/core/src/main/res/drawable-xxhdpi/ic_cast_on_2_light.png
deleted file mode 100644
index dfe52428d..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_cast_on_2_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_cast_on_light.png b/core/src/main/res/drawable-xxhdpi/ic_cast_on_light.png
deleted file mode 100644
index 7e69a0864..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_cast_on_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_close_light.png b/core/src/main/res/drawable-xxhdpi/ic_close_light.png
deleted file mode 100644
index be519bfcb..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_close_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_format_list_bulleted_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_format_list_bulleted_grey600_24dp.png
deleted file mode 100644
index 87f8073ea..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_format_list_bulleted_grey600_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_format_list_bulleted_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_format_list_bulleted_white_24dp.png
deleted file mode 100644
index da3433c61..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_format_list_bulleted_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_forum_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_forum_grey600_24dp.png
deleted file mode 100644
index 7a3204693..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_forum_grey600_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_media_cast_disconnect.png b/core/src/main/res/drawable-xxhdpi/ic_media_cast_disconnect.png
deleted file mode 100644
index 2d2ec9035..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_media_cast_disconnect.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_pause_light.png b/core/src/main/res/drawable-xxhdpi/ic_pause_light.png
deleted file mode 100644
index a36d4d11e..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_pause_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_play_light.png b/core/src/main/res/drawable-xxhdpi/ic_play_light.png
deleted file mode 100644
index b1424874a..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_play_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_stat_authentication.png b/core/src/main/res/drawable-xxhdpi/ic_stat_authentication.png
deleted file mode 100755
index 965fabc57..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_stat_authentication.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_baseline_question_answer_white_24db.png b/core/src/main/res/drawable-xxxhdpi/ic_baseline_question_answer_white_24db.png
deleted file mode 100755
index 0d697e0f9..000000000
--- a/core/src/main/res/drawable-xxxhdpi/ic_baseline_question_answer_white_24db.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_close_light.png b/core/src/main/res/drawable-xxxhdpi/ic_close_light.png
deleted file mode 100644
index 679c2a4d5..000000000
--- a/core/src/main/res/drawable-xxxhdpi/ic_close_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_format_list_bulleted_grey600_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_format_list_bulleted_grey600_24dp.png
deleted file mode 100644
index c56590fe0..000000000
--- a/core/src/main/res/drawable-xxxhdpi/ic_format_list_bulleted_grey600_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_format_list_bulleted_white_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_format_list_bulleted_white_24dp.png
deleted file mode 100644
index 5deea3286..000000000
--- a/core/src/main/res/drawable-xxxhdpi/ic_format_list_bulleted_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_forum_grey600_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_forum_grey600_24dp.png
deleted file mode 100644
index 0ae33696b..000000000
--- a/core/src/main/res/drawable-xxxhdpi/ic_forum_grey600_24dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_pause_light.png b/core/src/main/res/drawable-xxxhdpi/ic_pause_light.png
deleted file mode 100644
index 7de2ef4ed..000000000
--- a/core/src/main/res/drawable-xxxhdpi/ic_pause_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_play_light.png b/core/src/main/res/drawable-xxxhdpi/ic_play_light.png
deleted file mode 100644
index 4428c8477..000000000
--- a/core/src/main/res/drawable-xxxhdpi/ic_play_light.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable/ic_antenna.xml b/core/src/main/res/drawable/ic_antenna.xml
new file mode 100644
index 000000000..9fcfab000
--- /dev/null
+++ b/core/src/main/res/drawable/ic_antenna.xml
@@ -0,0 +1,6 @@
+<vector android:height="24dp" android:viewportHeight="12.7"
+ android:viewportWidth="12.7" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillAlpha="1" android:fillColor="#ffffff"
+ android:pathData="m6.0631,0.4728v0.3274c1.1582,0.0249 1.911,0.4225 2.5991,1.1189 0.6881,0.6964 1.0924,1.7043 1.1125,2.9246h0.3211c0.0078,-1.3792 -0.5291,-2.4905 -1.1981,-3.1576C8.2288,1.019 7.3415,0.4734 6.0631,0.4728ZM6.0631,1.4283v0.3453c0.859,0.0361 1.3465,0.2123 1.9398,0.8081 0.5933,0.5957 0.843,1.3669 0.8598,2.2621L9.2029,4.8438c-0.0088,-1.2333 -0.5414,-2.0907 -0.9568,-2.5047 -0.4154,-0.4139 -0.9948,-0.9065 -2.183,-0.9108zM6.0625,2.4323 L6.0631,2.7495c0.3968,0.007 0.8308,0.1395 1.2089,0.5642 0.3781,0.4247 0.495,1.0244 0.51,1.53h0.3255c-0.0016,-0.669 -0.2787,-1.3891 -0.6153,-1.747 -0.3366,-0.358 -0.7368,-0.6621 -1.4298,-0.6645zM6.0906,3.7766c-0.4059,0.0002 -0.7349,0.3294 -0.7347,0.7353 0.0001,0.2677 0.1459,0.5142 0.3804,0.6434l-3.0102,6.2227 0.5151,0.3351 0.607,-1.2485 5.3821,1.5453 0.083,0.1609 0.5732,-0.2508 -3.4927,-6.7397c0.2624,-0.1189 0.4311,-0.3802 0.4315,-0.6683 0.0002,-0.4059 -0.3287,-0.7352 -0.7347,-0.7353zM6.065,5.8631 L6.5929,6.8882 5.2882,7.4761zM6.6976,7.0918 L7.6065,8.8561 5.137,7.8016zM5.0259,8.0199 L7.611,9.1184 4.0314,10.0854zM7.8395,9.3086 L9.081,11.7201 4.1489,10.3069z"
+ android:strokeAlpha="1" android:strokeColor="#00000000" android:strokeWidth="0.32680494"/>
+</vector>
diff --git a/core/src/main/res/drawable/ic_chat_grey600.xml b/core/src/main/res/drawable/ic_chat_grey600.xml
new file mode 100644
index 000000000..ebae2dbed
--- /dev/null
+++ b/core/src/main/res/drawable/ic_chat_grey600.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FF757575" android:pathData="M21,6h-2v9L6,15v2c0,0.55 0.45,1 1,1h11l4,4L22,7c0,-0.55 -0.45,-1 -1,-1zM17,12L17,3c0,-0.55 -0.45,-1 -1,-1L3,2c-0.55,0 -1,0.45 -1,1v14l4,-4h10c0.55,0 1,-0.45 1,-1z"/>
+</vector>
diff --git a/core/src/main/res/drawable/ic_chat_white.xml b/core/src/main/res/drawable/ic_chat_white.xml
new file mode 100644
index 000000000..45691c525
--- /dev/null
+++ b/core/src/main/res/drawable/ic_chat_white.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FFFFFFFF" android:pathData="M21,6h-2v9L6,15v2c0,0.55 0.45,1 1,1h11l4,4L22,7c0,-0.55 -0.45,-1 -1,-1zM17,12L17,3c0,-0.55 -0.45,-1 -1,-1L3,2c-0.55,0 -1,0.45 -1,1v14l4,-4h10c0.55,0 1,-0.45 1,-1z"/>
+</vector>
diff --git a/core/src/main/res/drawable/ic_notification.png b/core/src/main/res/drawable/ic_notification.png
deleted file mode 100644
index 8bd22b54a..000000000
--- a/core/src/main/res/drawable/ic_notification.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable/ic_notification_cast_off.xml b/core/src/main/res/drawable/ic_notification_cast_off.xml
new file mode 100644
index 000000000..63a21fbe2
--- /dev/null
+++ b/core/src/main/res/drawable/ic_notification_cast_off.xml
@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp" android:viewportHeight="24.0"
+ android:viewportWidth="24.0" android:width="24dp">
+ <path android:fillColor="#FFFFFFFF" android:pathData="M1.6,1.27L0.25,2.75L1.41,3.8C1.16,4.13 1,4.55 1,5V8H3V5.23L18.2,19H14V21H20.41L22.31,22.72L23.65,21.24M6.5,3L8.7,5H21V16.14L23,17.95V5C23,3.89 22.1,3 21,3M1,10V12A9,9 0 0,1 10,21H12C12,14.92 7.08,10 1,10M1,14V16A5,5 0 0,1 6,21H8A7,7 0 0,0 1,14M1,18V21H4A3,3 0 0,0 1,18Z" />
+</vector> \ No newline at end of file
diff --git a/core/src/main/res/drawable/ic_notification_fast_forward.xml b/core/src/main/res/drawable/ic_notification_fast_forward.xml
new file mode 100644
index 000000000..bf564977c
--- /dev/null
+++ b/core/src/main/res/drawable/ic_notification_fast_forward.xml
@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp" android:viewportHeight="24.0"
+ android:viewportWidth="24.0" android:width="24dp">
+ <path android:fillColor="#FFFFFFFF" android:pathData="M4,18l8.5,-6L4,6v12zM13,6v12l8.5,-6L13,6z"/>
+</vector>
diff --git a/core/src/main/res/drawable/ic_notification_fast_rewind.xml b/core/src/main/res/drawable/ic_notification_fast_rewind.xml
new file mode 100644
index 000000000..847159cc5
--- /dev/null
+++ b/core/src/main/res/drawable/ic_notification_fast_rewind.xml
@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp" android:viewportHeight="24.0"
+ android:viewportWidth="24.0" android:width="24dp">
+ <path android:fillColor="#FFFFFFFF" android:pathData="M11,18L11,6l-8.5,6 8.5,6zM11.5,12l8.5,6L20,6l-8.5,6z"/>
+</vector>
diff --git a/core/src/main/res/drawable/ic_notification_key.xml b/core/src/main/res/drawable/ic_notification_key.xml
new file mode 100644
index 000000000..c8a817eeb
--- /dev/null
+++ b/core/src/main/res/drawable/ic_notification_key.xml
@@ -0,0 +1,6 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp" android:viewportHeight="24.0"
+ android:viewportWidth="24.0" android:width="24dp">
+ <path android:fillColor="#FFFFFFFF"
+ android:pathData="M12.65,10C11.83,7.67 9.61,6 7,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6c2.61,0 4.83,-1.67 5.65,-4H17v4h4v-4h2v-4H12.65zM7,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
+</vector>
diff --git a/core/src/main/res/drawable/ic_notification_pause.xml b/core/src/main/res/drawable/ic_notification_pause.xml
new file mode 100644
index 000000000..d46efb2f5
--- /dev/null
+++ b/core/src/main/res/drawable/ic_notification_pause.xml
@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp" android:viewportHeight="24.0"
+ android:viewportWidth="24.0" android:width="24dp">
+ <path android:fillColor="#FFFFFFFF" android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
+</vector>
diff --git a/core/src/main/res/drawable/ic_notification_play.xml b/core/src/main/res/drawable/ic_notification_play.xml
new file mode 100644
index 000000000..d571460c6
--- /dev/null
+++ b/core/src/main/res/drawable/ic_notification_play.xml
@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp" android:viewportHeight="24.0"
+ android:viewportWidth="24.0" android:width="24dp">
+ <path android:fillColor="#FFFFFFFF" android:pathData="M8,5v14l11,-7z"/>
+</vector>
diff --git a/core/src/main/res/drawable/ic_notification_skip.xml b/core/src/main/res/drawable/ic_notification_skip.xml
new file mode 100644
index 000000000..0c65448cc
--- /dev/null
+++ b/core/src/main/res/drawable/ic_notification_skip.xml
@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp" android:viewportHeight="24.0"
+ android:viewportWidth="24.0" android:width="24dp">
+ <path android:fillColor="#FFFFFFFF" android:pathData="M6,18l8.5,-6L6,6v12zM16,6v12h2V6h-2z"/>
+</vector>
diff --git a/core/src/main/res/drawable/ic_playback_speed_dark.xml b/core/src/main/res/drawable/ic_playback_speed_dark.xml
new file mode 100644
index 000000000..7c7d1cf8c
--- /dev/null
+++ b/core/src/main/res/drawable/ic_playback_speed_dark.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path android:fillColor="#FF757575" android:pathData="M 12,14.888154 A 2.2284437,2.2284437 0 0 1 9.7715563,12.659711 c 0,-0.831952 0.4531167,-1.559911 1.1142217,-1.938746 L 18.098507,6.5463469 13.990743,13.66251 C 13.619336,14.390469 12.869093,14.888154 12,14.888154 m 0,-9.6565888 c 1.344494,0 2.599851,0.3714073 3.691789,0.9805151 L 14.131878,7.110886 C 13.485629,6.858329 12.742815,6.7171943 12,6.7171943 A 5.9425165,5.9425165 0 0 0 6.0574835,12.659711 c 0,1.64162 0.661105,3.127249 1.7381861,4.196902 h 0.00743 c 0.2896977,0.289697 0.2896977,0.757671 0,1.047369 -0.2896977,0.289697 -0.7650991,0.289697 -1.0547967,0.0075 v 0 C 5.4038067,16.566915 4.5718544,14.709879 4.5718544,12.659711 A 7.4281456,7.4281456 0 0 1 12,5.2315652 m 7.428145,7.4281458 c 0,2.050168 -0.831952,3.907204 -2.176446,5.251699 v 0 c -0.289698,0.282269 -0.757671,0.282269 -1.047369,-0.0075 -0.289697,-0.289698 -0.289697,-0.757671 0,-1.047368 v 0 c 1.077082,-1.077082 1.738186,-2.555282 1.738186,-4.196902 0,-0.742815 -0.141134,-1.48563 -0.401119,-2.154163 l 0.898805,-1.5599106 c 0.616537,1.1142216 0.987943,2.3621496 0.987943,3.7140736 z" />
+</vector> \ No newline at end of file
diff --git a/core/src/main/res/drawable/ic_playback_speed_white.xml b/core/src/main/res/drawable/ic_playback_speed_white.xml
new file mode 100644
index 000000000..cc6af0d55
--- /dev/null
+++ b/core/src/main/res/drawable/ic_playback_speed_white.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="48dp"
+ android:width="48dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path android:fillColor="#ffffffff" android:pathData="M 12,14.888154 A 2.2284437,2.2284437 0 0 1 9.7715563,12.659711 c 0,-0.831952 0.4531167,-1.559911 1.1142217,-1.938746 L 18.098507,6.5463469 13.990743,13.66251 C 13.619336,14.390469 12.869093,14.888154 12,14.888154 m 0,-9.6565888 c 1.344494,0 2.599851,0.3714073 3.691789,0.9805151 L 14.131878,7.110886 C 13.485629,6.858329 12.742815,6.7171943 12,6.7171943 A 5.9425165,5.9425165 0 0 0 6.0574835,12.659711 c 0,1.64162 0.661105,3.127249 1.7381861,4.196902 h 0.00743 c 0.2896977,0.289697 0.2896977,0.757671 0,1.047369 -0.2896977,0.289697 -0.7650991,0.289697 -1.0547967,0.0075 v 0 C 5.4038067,16.566915 4.5718544,14.709879 4.5718544,12.659711 A 7.4281456,7.4281456 0 0 1 12,5.2315652 m 7.428145,7.4281458 c 0,2.050168 -0.831952,3.907204 -2.176446,5.251699 v 0 c -0.289698,0.282269 -0.757671,0.282269 -1.047369,-0.0075 -0.289697,-0.289698 -0.289697,-0.757671 0,-1.047368 v 0 c 1.077082,-1.077082 1.738186,-2.555282 1.738186,-4.196902 0,-0.742815 -0.141134,-1.48563 -0.401119,-2.154163 l 0.898805,-1.5599106 c 0.616537,1.1142216 0.987943,2.3621496 0.987943,3.7140736 z" />
+</vector> \ No newline at end of file
diff --git a/core/src/main/res/drawable/ic_questionmark_grey600.xml b/core/src/main/res/drawable/ic_questionmark_grey600.xml
new file mode 100644
index 000000000..0907fcdec
--- /dev/null
+++ b/core/src/main/res/drawable/ic_questionmark_grey600.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FF757575" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z"/>
+</vector>
diff --git a/core/src/main/res/drawable/ic_questionmark_white.xml b/core/src/main/res/drawable/ic_questionmark_white.xml
new file mode 100644
index 000000000..69b42fef8
--- /dev/null
+++ b/core/src/main/res/drawable/ic_questionmark_white.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FFFFFFFF" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z"/>
+</vector>
diff --git a/core/src/main/res/drawable/ic_warning_red.xml b/core/src/main/res/drawable/ic_warning_red.xml
new file mode 100644
index 000000000..475a41bbb
--- /dev/null
+++ b/core/src/main/res/drawable/ic_warning_red.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#FF0000"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FF000000" android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/>
+</vector>
diff --git a/core/src/main/res/drawable/notification_default_large_icon.xml b/core/src/main/res/drawable/notification_default_large_icon.xml
new file mode 100644
index 000000000..6da31b1bb
--- /dev/null
+++ b/core/src/main/res/drawable/notification_default_large_icon.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportHeight="12.7"
+ android:viewportWidth="12.7"
+ android:height="64dp"
+ android:width="64dp">
+
+ <path
+ android:fillColor="#ff007DBA"
+ android:pathData="M 0,0 L 12.7,0 12.7,12.7 0,12.7 z"/>
+
+ <path
+ android:fillColor="#ffffffff"
+ android:pathData="m5.7552,2.2412l0,0.2651c0.9377,0.0202 1.5471,0.342 2.1043,0.9059 0.5571,0.5639 0.8845,1.3798 0.9007,2.3678l0.2599,0C9.0264,4.6634 8.5918,3.7637 8.0502,3.2236 7.5085,2.6834 6.7902,2.2418 5.7552,2.2412ZM5.7552,3.0148l0,0.2796c0.6954,0.0292 1.0901,0.1719 1.5704,0.6542 0.4803,0.4823 0.6825,1.1066 0.6961,1.8314l0.2754,0c-0.0071,-0.9985 -0.4383,-1.6927 -0.7746,-2.0278 -0.3363,-0.3351 -0.8054,-0.734 -1.7673,-0.7374zM5.7547,3.8277 L5.7552,4.0845c0.3213,0.006 0.6726,0.1129 0.9788,0.4568 0.3061,0.3439 0.4008,0.8294 0.4129,1.2387l0.2635,0C7.4091,5.2384 7.1848,4.6554 6.9122,4.3656 6.6397,4.0758 6.3157,3.8296 5.7547,3.8277ZM5.7774,4.916c-0.3286,0.0001 -0.595,0.2667 -0.5948,0.5953 0.0001,0.2168 0.1181,0.4163 0.308,0.5209l-2.4371,5.0379 0.417,0.2713 0.4914,-1.0108 4.3574,1.2511 0.0672,0.1302 0.4641,-0.2031L6.0229,6.0523c0.2124,-0.0963 0.349,-0.3078 0.3493,-0.5411 0.0002,-0.3286 -0.2661,-0.5952 -0.5948,-0.5953zM5.7567,6.6053 L6.1841,7.4352 5.1278,7.9111zM6.2689,7.6001 L7.0047,9.0284 5.0054,8.1747zM4.9154,8.3514 L7.0083,9.2408 4.1103,10.0237zM7.1934,9.3948 L8.1985,11.3471 4.2054,10.203Z" />
+
+</vector>
diff --git a/core/src/main/res/drawable/white_circle.xml b/core/src/main/res/drawable/white_circle.xml
deleted file mode 100644
index 597b70a2d..000000000
--- a/core/src/main/res/drawable/white_circle.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval" >
-
- <solid android:color="@color/white" />
-
- <size
- android:height="4dp"
- android:width="4dp" />
-
-</shape> \ No newline at end of file
diff --git a/core/src/main/res/values-de/strings.xml b/core/src/main/res/values-de/strings.xml
index b2b70575c..d191f4059 100644
--- a/core/src/main/res/values-de/strings.xml
+++ b/core/src/main/res/values-de/strings.xml
@@ -422,7 +422,7 @@
<string name="pref_gpodnet_full_sync_title">Jetzt komplett synchronisieren</string>
<string name="pref_gpodnet_full_sync_sum">Kompletten Abonnement- und Episoden-Status mit gpodder.net synchronisieren.</string>
<string name="pref_gpodnet_sync_sum_last_sync_line">Letzter Synchronisierungsversuch: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Synchronisation starten</string>
+ <string name="pref_gpodnet_sync_started">Synchronisation gestartet</string>
<string name="pref_gpodnet_full_sync_started">Komplette Synchronisierung gestartet</string>
<string name="pref_gpodnet_login_status"><![CDATA[Eingeloggt als <i>%1$s</i> mit dem Gerät <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Zeige Benachrichtungen bei Synchronisierungsfehlern</string>
@@ -617,7 +617,7 @@
<string name="media_type_audio_label">Audio</string>
<string name="media_type_video_label">Video</string>
<string name="navigate_upwards_label">Nach oben navigieren</string>
- <string name="status_downloading_label">Episode wird gerade heruntergeladen</string>
+ <string name="status_downloading_label">Episode wird heruntergeladen</string>
<string name="in_queue_label">Episode befindet sich in der Abspielliste</string>
<string name="drag_handle_content_description">Ziehe, um die Position dieses Objekts zu verändern</string>
<string name="load_next_page_label">Nächste Seite laden</string>
@@ -726,7 +726,7 @@
<!--Notification channels-->
<string name="notification_channel_user_action">Handlung notwendig</string>
<string name="notification_channel_user_action_description">Wird gezeigt, wenn deine Handlung notwendig ist, zum Beispiel wenn du ein Passwort eingeben musst.</string>
- <string name="notification_channel_downloading">Lädt herunter</string>
+ <string name="notification_channel_downloading">Herunterladen</string>
<string name="notification_channel_downloading_description">Wird gezeigt beim Herunterladen.</string>
<string name="notification_channel_playing">Jetzt spielt</string>
<string name="notification_channel_playing_description">Erlaubt es, die Wiedergabe zu steuern. Dies ist die Hauptbenachrichtigung, die du siehst, während ein Podcast abgespielt wird.</string>
diff --git a/core/src/main/res/values-hu/strings.xml b/core/src/main/res/values-hu/strings.xml
index 4a42da4c3..706b13b79 100644
--- a/core/src/main/res/values-hu/strings.xml
+++ b/core/src/main/res/values-hu/strings.xml
@@ -107,6 +107,7 @@
<string name="podcastdirectories_label">Podcast keresése mappában</string>
<string name="podcastdirectories_descr">Új podcastokat kereshetsz iTunes-on vagy fyyd-en, vagy a gpodder.net-en név, kategória vagy cím alapján.</string>
<string name="browse_gpoddernet_label">gpodder.net böngészése</string>
+ <string name="discover">Felfedezés</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Az összes megjelölése lejátszottként</string>
<string name="mark_all_read_msg">Az összes epizód lejátszottként megjelölve</string>
diff --git a/core/src/main/res/values-id/strings.xml b/core/src/main/res/values-in/strings.xml
index 2f1ffecea..2f1ffecea 100644
--- a/core/src/main/res/values-id/strings.xml
+++ b/core/src/main/res/values-in/strings.xml
diff --git a/core/src/main/res/values-land/styles.xml b/core/src/main/res/values-land/styles.xml
deleted file mode 100644
index d964ef3d4..000000000
--- a/core/src/main/res/values-land/styles.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <style name="Theme.MediaPlayer" parent="@style/Theme.AppCompat.Light">
- <item name="android:windowActionBarOverlay">true</item>
- </style>
-</resources> \ No newline at end of file
diff --git a/core/src/main/res/values-large/dimens.xml b/core/src/main/res/values-large/dimens.xml
index 2da283c5b..2d107eef0 100644
--- a/core/src/main/res/values-large/dimens.xml
+++ b/core/src/main/res/values-large/dimens.xml
@@ -4,5 +4,4 @@
<dimen name="thumbnail_length">170dp</dimen>
<dimen name="thumbnail_length_queue_item">64dp</dimen>
<dimen name="thumbnail_length_downloaded_item">64dp</dimen>
- <dimen name="queue_title_text_size">@dimen/text_size_medium</dimen>
</resources> \ No newline at end of file
diff --git a/core/src/main/res/values-pl-rPL/strings.xml b/core/src/main/res/values-pl-rPL/strings.xml
index 405bfeaa7..3ebdbe487 100644
--- a/core/src/main/res/values-pl-rPL/strings.xml
+++ b/core/src/main/res/values-pl-rPL/strings.xml
@@ -7,6 +7,7 @@
<string name="add_feed_label">Dodaj podcast</string>
<string name="episodes_label">Odcinki</string>
<string name="all_episodes_short_label">Wszystkie</string>
+ <string name="new_episodes_label">Nowe</string>
<string name="favorite_episodes_label">Ulubione</string>
<string name="new_label">Nowy</string>
<string name="settings_label">Ustawienia</string>
@@ -104,6 +105,7 @@
<string name="podcastdirectories_label">Znajdź podcast w folderze</string>
<string name="podcastdirectories_descr">Możesz wyszukiwać nowe podcasty ze względu na nazwę, kategorię lub popularność na gpodder.net, Itunes lub fyyd</string>
<string name="browse_gpoddernet_label">Przeglądaj gpodder.net</string>
+ <string name="discover_more">więcej »</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Oznacz wszystkie jako odtworzone</string>
<string name="mark_all_read_msg">Wszystkie odcinki zaznaczono jako odtworzone</string>
@@ -134,7 +136,7 @@
<string name="hide_has_media_label">Ma media</string>
<string name="filtered_label">Przefiltrowany</string>
<string name="refresh_failed_msg">{fa-exclamation-circle} Ostatnie odświerzanie nie powiodło się</string>
- <string name="open_podcast">Otwarty Podcast</string>
+ <string name="open_podcast">Otwórz Podcast</string>
<!--actions on feeditems-->
<string name="download_label">Pobierz</string>
<string name="play_label">Odtwórz</string>
@@ -249,6 +251,8 @@
<!--Empty list labels-->
<string name="no_feeds_label">Nie subskrybowałeś jeszcze żadnego podcastu.</string>
<string name="no_shownotes_label">Ten epizod nie ma notatek.</string>
+ <string name="no_comp_downloads_head_label">Brak pobranych odcinków</string>
+ <string name="no_fav_episodes_head_label">Brak ulubionych odcinków</string>
<string name="no_chapters_label">Ten odcinek nie ma rozdziałów.</string>
<!--Preferences-->
<string name="storage_pref">Pamięć</string>
@@ -258,6 +262,8 @@
<string name="queue_label">Kolejka</string>
<string name="download_pref_details">Szczegóły</string>
<string name="appearance">Wygląd</string>
+ <string name="preference_search_no_results">Brak wyników</string>
+ <string name="preference_search_clear_history">Wyczyść historię</string>
<string name="pref_episode_cleanup_title">Usuwanie odcinków</string>
<string name="pref_episode_cleanup_summary">Odcinki niebędące w kolejce i niebędące na liście ulubiobych powinny nadawać się do usunięcia, jeśli Automatyczne Pobieranie potrzebuje miejsca na nowe odcinki.</string>
<string name="pref_pauseOnDisconnect_sum">Wstrzymaj odtwarzanie po rozłączeniu słuchawek lub Bluetooth</string>
@@ -292,6 +298,7 @@
<string name="pref_unpauseOnHeadsetReconnect_title">Słuchawki podłączone ponownie</string>
<string name="pref_unpauseOnBluetoothReconnect_title">Bluetooth podłączony ponownie</string>
<string name="pref_mobileUpdate_title">Aktualizacje mobilne</string>
+ <string name="pref_mobileUpdate_auto_download">Automatyczne pobieranie</string>
<string name="refreshing_label">Odświeżanie</string>
<string name="user_interface_label">Interfejs użytkownika</string>
<string name="pref_set_theme_title">Wybierz motyw</string>
@@ -374,6 +381,9 @@
<string name="pref_cast_message_free_flavor">Chromecast wymagadodatkowych bibliotek, które są zablokowane w tej wersji AntennaPod</string>
<string name="pref_enqueue_downloaded_title">Rzeczy z kolejki pobrane</string>
<string name="pref_enqueue_downloaded_summary">Dodaj pobrane odcinki do kolejki</string>
+ <string name="behavior">Zachowanie</string>
+ <string name="back_button_default">Domyślne</string>
+ <string name="back_button_open_drawer">Otwórz panel nawigacyjny</string>
<!--Search-->
<string name="search_hint">Szukaj odcinków</string>
<string name="found_in_shownotes_label">Znalezione w notatkach dotyczących show</string>
diff --git a/core/src/main/res/values-v16/styles.xml b/core/src/main/res/values-v16/styles.xml
index a92790152..947e43f38 100644
--- a/core/src/main/res/values-v16/styles.xml
+++ b/core/src/main/res/values-v16/styles.xml
@@ -6,12 +6,4 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:fontFamily">sans-serif-light</item>
</style>
-
- <style name="AntennaPod.Dialog.Title" parent="@android:style/TextAppearance.Medium">
- <item name="android:textSize">@dimen/text_size_medium</item>
- <item name="android:textColor">@color/holo_blue_light</item>
- <item name="android:maxLines">2</item>
- <item name="android:ellipsize">end</item>
- <item name="android:fontFamily">sans-serif-light</item>
- </style>
</resources> \ No newline at end of file
diff --git a/core/src/main/res/values-v19/colors.xml b/core/src/main/res/values-v19/colors.xml
index 16c065d75..4154280e8 100644
--- a/core/src/main/res/values-v19/colors.xml
+++ b/core/src/main/res/values-v19/colors.xml
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="selection_background_color_dark">#484B4D</color>
- <color name="selection_background_color_light">#E3E3E3</color>
</resources> \ No newline at end of file
diff --git a/core/src/main/res/values/arrays.xml b/core/src/main/res/values/arrays.xml
index 0eaf0e5e7..5e7eab1ea 100644
--- a/core/src/main/res/values/arrays.xml
+++ b/core/src/main/res/values/arrays.xml
@@ -156,19 +156,15 @@
<item>4.00</item>
</string-array>
- <string-array name="autodl_select_networks_default_entries">
- <item>N/A</item>
- </string-array>
- <string-array name="autodl_select_networks_default_values">
- <item>0</item>
- </string-array>
-
<string-array name="theme_options">
+ <item>@string/pref_theme_title_use_system</item>
<item>@string/pref_theme_title_light</item>
<item>@string/pref_theme_title_dark</item>
<item>@string/pref_theme_title_trueblack</item>
</string-array>
+
<string-array name="theme_values">
+ <item>system</item>
<item>0</item>
<item>1</item>
<item>2</item>
diff --git a/core/src/main/res/values/attrs.xml b/core/src/main/res/values/attrs.xml
index 5b0bf5717..530b40d46 100644
--- a/core/src/main/res/values/attrs.xml
+++ b/core/src/main/res/values/attrs.xml
@@ -9,6 +9,7 @@
<attr name="av_fast_forward" format="reference"/>
<attr name="av_pause" format="reference"/>
<attr name="av_play" format="reference"/>
+ <attr name="av_speed" format="reference"/>
<attr name="av_rewind" format="reference"/>
<attr name="content_discard" format="reference"/>
<attr name="content_new" format="reference"/>
@@ -56,9 +57,9 @@
<attr name="ic_cast_disconnect" format="reference"/>
<attr name="ic_swap" format="reference"/>
<attr name="ic_cellphone_text" format="reference"/>
- <attr name="ic_question_answer" format="reference" />
+ <attr name="ic_questionmark" format="reference" />
+ <attr name="ic_chat" format="reference"/>
<attr name="ic_bug" format="reference" />
- <attr name="ic_known_issues" format="reference" />
<attr name="master_switch_background" format="color"/>
<attr name="currently_playing_background" format="color"/>
<attr name="ic_bookmark" format="reference"/>
diff --git a/core/src/main/res/values/colors.xml b/core/src/main/res/values/colors.xml
index 0e4533977..fea7da4a4 100644
--- a/core/src/main/res/values/colors.xml
+++ b/core/src/main/res/values/colors.xml
@@ -2,22 +2,16 @@
<resources>
<color name="white">#FFFFFF</color>
- <color name="gray">#808080</color>
<color name="grey600">#757575</color>
<color name="light_gray">#bfbfbf</color>
<color name="black">#000000</color>
<color name="holo_blue_light">#33B5E5</color>
<color name="holo_blue_dark">#0099CC</color>
- <color name="ics_gray">#858585</color>
- <color name="actionbar_gray">#DDDDDD</color>
<color name="download_success_green">#669900</color>
<color name="download_failed_red">#CC0000</color>
<color name="status_progress">#E033B5E5</color>
- <color name="status_playing">#E0EE5F52</color>
<color name="overlay_dark">#2C2C2C</color>
<color name="overlay_light">#FFFFFF</color>
- <color name="swipe_refresh_secondary_color_light">#EDEDED</color>
- <color name="swipe_refresh_secondary_color_dark">#060708</color>
<color name="new_indicator_green">#669900</color>
<color name="image_readability_tint">#80000000</color>
<color name="feed_image_bg">#50000000</color>
diff --git a/core/src/main/res/values/dimens.xml b/core/src/main/res/values/dimens.xml
index cdde0027d..02c398b62 100644
--- a/core/src/main/res/values/dimens.xml
+++ b/core/src/main/res/values/dimens.xml
@@ -10,7 +10,6 @@
<dimen name="text_size_navdrawer">16sp</dimen>
<dimen name="text_size_medium">18sp</dimen>
<dimen name="text_size_large">22sp</dimen>
- <dimen name="status_indicator_width">32dp</dimen>
<dimen name="thumbnail_length_itemlist">64dp</dimen>
<dimen name="thumbnail_length_queue_item">64dp</dimen>
<dimen name="thumbnail_length_downloaded_item">64dp</dimen>
@@ -21,7 +20,6 @@
<dimen name="drawer_width">280dp</dimen>
<dimen name="listitem_iconwithtext_height">48dp</dimen>
<dimen name="listitem_iconwithtext_textleftpadding">16dp</dimen>
- <dimen name="listitem_iconwithtext_textverticalpadding">16dp</dimen>
<dimen name="listitem_threeline_textleftpadding">16dp</dimen>
<dimen name="listitem_threeline_textrightpadding">8dp</dimen>
@@ -29,7 +27,6 @@
<dimen name="listitem_threeline_horizontalpadding">16dp</dimen>
<dimen name="list_vertical_padding">8dp</dimen>
- <dimen name="minimum_text_margin">8dp</dimen>
<dimen name="listitem_icon_leftpadding">16dp</dimen>
<dimen name="listitem_icon_rightpadding">16dp</dimen>
diff --git a/core/src/main/res/values/integers.xml b/core/src/main/res/values/integers.xml
index 33501d9fb..73d90cf98 100644
--- a/core/src/main/res/values/integers.xml
+++ b/core/src/main/res/values/integers.xml
@@ -1,4 +1,3 @@
<resources>
- <integer name="undobar_hide_delay">5000</integer>
<integer name="episode_cache_size_unlimited">-1</integer>
</resources>
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 1cd4a7836..0d61e30cd 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -27,10 +27,8 @@
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_summary">Synchronize with other devices</string>
<string name="gpodnet_auth_label">gpodder.net Login</string>
- <string name="free_space_label">%1$s free</string>
<string name="episode_cache_full_title">Episode cache full</string>
<string name="episode_cache_full_message">The episode cache limit has been reached. You can increase the cache size in the Settings.</string>
- <string name="synchronizing">Synchronizing…</string>
<!-- Statistics fragment -->
<string name="total_time_listened_to_podcasts">Total time of podcasts played:</string>
@@ -73,7 +71,6 @@
<string name="author_label">Author(s)</string>
<string name="language_label">Language</string>
<string name="url_label">URL</string>
- <string name="podcast_settings_label">Settings</string>
<string name="cover_label">Picture</string>
<string name="error_label">Error</string>
<string name="error_msg_prefix">An error occurred:</string>
@@ -82,14 +79,9 @@
<string name="external_storage_error_msg">No external storage is available. Please make sure that external storage is mounted so that the app can work properly.</string>
<string name="chapters_label">Chapters</string>
<string name="chapter_duration">Duration: %1$s</string>
- <string name="shownotes_label">Shownotes</string>
<string name="description_label">Description</string>
- <string name="most_recent_prefix">Most recent episode:\u0020</string>
<string name="episodes_suffix">\u0020episodes</string>
- <string name="length_prefix">Length:\u0020</string>
- <string name="size_prefix">Size:\u0020</string>
<string name="processing_label">Processing</string>
- <string name="loading_label">Loading&#8230;</string>
<string name="save_username_password_label">Save username and password</string>
<string name="close_label">Close</string>
<string name="retry_label">Retry</string>
@@ -119,8 +111,6 @@
<string name="feedurl_label">Feed URL</string>
<string name="etxtFeedurlHint">www.example.com/feed</string>
<string name="txtvfeedurl_label">Add Podcast by URL</string>
- <string name="podcastdirectories_label">Find Podcast in Directory</string>
- <string name="podcastdirectories_descr">For new podcasts, you can search iTunes or fyyd, or browse gpodder.net by name, category or popularity.</string>
<string name="browse_gpoddernet_label">Browse gpodder.net</string>
<string name="discover">Discover</string>
<string name="discover_more">more »</string>
@@ -143,13 +133,13 @@
<string name="share_link_label">Share Episode URL</string>
<string name="share_link_with_position_label">Share Episode URL with Position</string>
<string name="share_file_label">Share File</string>
+ <string name="share_website_url_label">Share Website URL</string>
<string name="share_feed_url_label">Share Feed URL</string>
<string name="share_item_url_label">Share Media File URL</string>
<string name="share_item_url_with_position_label">Share Media File URL with Position</string>
<string name="feed_delete_confirmation_msg">Please confirm that you want to delete the podcast \"%1$s\" and ALL its episodes (including downloaded episodes).</string>
<string name="feed_remover_msg">Removing podcast</string>
<string name="load_complete_feed">Refresh complete podcast</string>
- <string name="hide_episodes_title">Hide Episodes</string>
<string name="batch_edit">Batch edit</string>
<string name="select_all_above">Select all above</string>
<string name="select_all_below">Select all below</string>
@@ -174,9 +164,7 @@
</plurals>
<string name="play_label">Play</string>
<string name="pause_label">Pause</string>
- <string name="stop_label">Stop</string>
<string name="stream_label">Stream</string>
- <string name="remove_label">Remove</string>
<string name="delete_label">Delete</string>
<string name="delete_failed">Unable to delete file. Rebooting the device could help.</string>
<string name="delete_episode_label">Delete Episode</string>
@@ -221,14 +209,12 @@
<!-- Download messages and labels -->
<string name="download_successful">successful</string>
- <string name="download_failed">failed</string>
<string name="download_pending">Download pending</string>
<string name="download_running">Download running</string>
<string name="download_error_details">Details</string>
<string name="download_error_details_message">%1$s \n\nFile URL:\n%2$s</string>
<string name="download_error_device_not_found">Storage Device not found</string>
<string name="download_error_insufficient_space">Insufficient Space</string>
- <string name="download_error_file_error">File Error</string>
<string name="download_error_http_data_error">HTTP Data Error</string>
<string name="download_error_error_unknown">Unknown Error</string>
<string name="download_error_parser_exception">Parser Exception</string>
@@ -238,7 +224,6 @@
<string name="download_error_unauthorized">Authentication Error</string>
<string name="download_error_file_type_type">File Type Error</string>
<string name="download_error_forbidden">Forbidden</string>
- <string name="cancel_all_downloads_label">Cancel all downloads</string>
<string name="download_canceled_msg">Download canceled</string>
<string name="download_canceled_autodownload_enabled_msg">Download canceled\nDisabled <i>Auto Download</i> for this item</string>
<string name="download_report_title">Downloads completed with error(s)</string>
@@ -257,7 +242,6 @@
<string name="download_log_title_unknown">Unknown Title</string>
<string name="download_type_feed">Feed</string>
<string name="download_type_media">Media file</string>
- <string name="download_type_image">Image</string>
<string name="download_request_error_dialog_message_prefix">An error occurred when trying to download the file:\u0020</string>
<string name="null_value_podcast_error">No podcast was provided that could be shown.</string>
<string name="authentication_notification_title">Authentication required</string>
@@ -285,7 +269,6 @@
<string name="position_default_label" translate="false">00:00:00</string>
<string name="player_buffering_msg">Buffering</string>
<string name="player_go_to_picture_in_picture">Picture-in-picture mode</string>
- <string name="playbackservice_notification_title">Playing podcast</string>
<string name="unknown_media_key">AntennaPod - Unknown media key: %1$d</string>
<!-- Queue operations -->
@@ -293,9 +276,10 @@
<string name="unlock_queue">Unlock Queue</string>
<string name="queue_locked">Queue locked</string>
<string name="queue_unlocked">Queue unlocked</string>
+ <string name="queue_lock_warning">If you lock the queue, you can no longer swipe or reorder episodes.</string>
+ <string name="checkbox_do_not_show_again">Do not show again</string>
<string name="clear_queue_label">Clear Queue</string>
<string name="undo">Undo</string>
- <string name="removed_from_queue">Item removed</string>
<string name="move_to_top_label">Move to top</string>
<string name="move_to_bottom_label">Move to bottom</string>
<string name="sort">Sort</string>
@@ -322,7 +306,6 @@
<!-- Empty list labels -->
<string name="no_items_header_label">No queued episodes</string>
<string name="no_items_label">Add an episode by downloading it, or long press an episode and select \"Add to queue\".</string>
- <string name="no_feeds_label">You haven\'t subscribed to any podcasts yet.</string>
<string name="no_shownotes_label">This episode has no shownotes.</string>
<string name="no_run_downloads_head_label">No downloads running</string>
<string name="no_run_downloads_label">You can download episodes on the podcast details screen.</string>
@@ -344,7 +327,6 @@
<!-- Preferences -->
<string name="storage_pref">Storage</string>
<string name="project_pref">Project</string>
- <string name="other_pref">Other</string>
<string name="about_pref">About</string>
<string name="queue_label">Queue</string>
<string name="integrations_label">Integrations</string>
@@ -388,9 +370,7 @@
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Set Time of Day</string>
<string name="pref_autoUpdateIntervallOrTime_every">every %1$s</string>
<string name="pref_autoUpdateIntervallOrTime_at">at %1$s</string>
- <string name="pref_downloadMediaOnWifiOnly_sum">Download media files only over WiFi</string>
<string name="pref_followQueue_title">Continuous Playback</string>
- <string name="pref_downloadMediaOnWifiOnly_title">WiFi media download</string>
<string name="pref_pauseOnHeadsetDisconnect_title">Headphones Disconnect</string>
<string name="pref_unpauseOnHeadsetReconnect_title">Headphones Reconnect</string>
<string name="pref_unpauseOnBluetoothReconnect_title">Bluetooth Reconnect</string>
@@ -401,11 +381,8 @@
<string name="pref_mobileUpdate_auto_download">Auto download</string>
<string name="pref_mobileUpdate_episode_download">Episode download</string>
<string name="pref_mobileUpdate_streaming">Streaming</string>
- <string name="refreshing_label">Refreshing</string>
<string name="user_interface_label">User Interface</string>
<string name="pref_set_theme_title">Select Theme</string>
- <string name="pref_nav_drawer_title">Customize Navigation Drawer</string>
- <string name="pref_nav_drawer_sum">Customize the appearance of the navigation drawer.</string>
<string name="pref_nav_drawer_items_title">Set Navigation Drawer items</string>
<string name="pref_nav_drawer_items_sum">Change which items appear in the navigation drawer.</string>
<string name="pref_nav_drawer_feed_order_title">Set Subscription Order</string>
@@ -417,13 +394,14 @@
<string name="pref_automatic_download_sum">Configure the automatic download of episodes.</string>
<string name="pref_autodl_wifi_filter_title">Enable Wi-Fi filter</string>
<string name="pref_autodl_wifi_filter_sum">Allow automatic download only for selected Wi-Fi networks.</string>
- <string name="pref_autodl_allow_on_mobile_title">Download on mobile connection</string>
- <string name="pref_autodl_allow_on_mobile_sum">Allow automatic download over the mobile data connection.</string>
+ <string name="autodl_wifi_filter_permission_title">Permission required</string>
+ <string name="autodl_wifi_filter_permission_message">Location permission is required for Wi-Fi filter. Tap to grant the permission.</string>
<string name="pref_automatic_download_on_battery_title">Download when not charging</string>
<string name="pref_automatic_download_on_battery_sum">Allow automatic download when the battery is not charging</string>
<string name="pref_parallel_downloads_title">Parallel Downloads</string>
<string name="pref_episode_cache_title">Episode Cache</string>
<string name="pref_episode_cache_summary">Total number of downloaded episodes cached on the device. Automatic download will be suspended if this number is reached.</string>
+ <string name="pref_theme_title_use_system">Use system theme</string>
<string name="pref_theme_title_light">Light</string>
<string name="pref_theme_title_dark">Dark</string>
<string name="pref_theme_title_trueblack">Black (AMOLED ready)</string>
@@ -443,7 +421,6 @@
<string name="pref_gpodnet_full_sync_sum">Sync all subscriptions and episode states with gpodder.net.</string>
<string name="pref_gpodnet_sync_sum_last_sync_line">Last sync attempt: %1$s (%2$s)</string>
<string name="pref_gpodnet_sync_started">Sync started</string>
- <string name="pref_gpodnet_full_sync_started">Full sync started</string>
<string name="pref_gpodnet_login_status"><![CDATA[Logged in as <i>%1$s</i> with device <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Show sync error notifications</string>
<string name="pref_gpodnet_notifications_sum">This setting does not apply to authentication errors.</string>
@@ -476,16 +453,17 @@
<string name="pref_smart_mark_as_played_disabled">Disabled</string>
<string name="pref_image_cache_size_title">Image Cache Size</string>
<string name="pref_image_cache_size_sum">Size of the disk cache for images.</string>
- <string name="crash_report_title">Crash Report</string>
- <string name="crash_report_sum">Send the latest crash report via e-mail</string>
- <string name="send_email">Send e-mail</string>
+ <string name="view_mailing_list">View mailing list</string>
+ <string name="bug_report_title">Report bug</string>
+ <string name="open_bug_tracker">Open bug tracker</string>
+ <string name="copy_to_clipboard">Copy to clipboard</string>
+ <string name="copied_to_clipboard">Copied to clipboard</string>
<string name="experimental_pref">Experimental</string>
<string name="pref_media_player_message">Select which media player to use to play files</string>
<string name="pref_current_value">Current value: %1$s</string>
<string name="pref_proxy_title">Proxy</string>
<string name="pref_proxy_sum">Set a network proxy</string>
- <string name="pref_faq">FAQ</string>
- <string name="pref_known_issues">Known issues</string>
+ <string name="pref_faq">Frequently Asked Questions</string>
<string name="pref_no_browser_found">No web browser found.</string>
<string name="pref_cast_title">Chromecast support</string>
<string name="pref_cast_message_play_flavor">Enable support for remote media playback on Cast devices (such as Chromecast, Audio Speakers or Android TV)</string>
@@ -526,21 +504,16 @@
<string name="no_results_for_query">No results were found for \"%1$s\"</string>
<!-- OPML import and export -->
- <string name="opml_import_txtv_button_lable">OPML files allow you to move your podcasts from one podcatcher to another.</string>
<string name="opml_import_option">Option %1$d</string>
<string name="opml_import_explanation_1">Choose a specific file path from the local filesystem.</string>
- <string name="opml_import_explanation_2">Use an external applications like Dropbox, Google Drive or your favourite file manager to open an OPML file.</string>
- <string name="opml_import_explanation_3">Many applications like Google Mail, Dropbox, Google Drive and most file managers can <i>open</i> OPML files <i>with</i> AntennaPod.</string> <string name="start_import_label">Start import</string>
+ <string name="opml_import_explanation_3">Many applications like Google Mail, Dropbox, Google Drive and most file managers can <i>open</i> OPML files <i>with</i> AntennaPod.</string>
<string name="opml_import_label">OPML Import</string>
- <string name="opml_directory_error">ERROR!</string>
<string name="reading_opml_label">Reading OPML file</string>
<string name="opml_reader_error">An error has occurred while reading the OPML document:</string>
<string name="opml_import_error_no_file">No file selected!</string>
<string name="select_all_label">Select all</string>
<string name="deselect_all_label">Deselect all</string>
- <string name="select_options_label">Select&#8230;</string>
<string name="choose_file_from_filesystem">From local filesystem</string>
- <string name="choose_file_from_external_application">Use external application</string>
<string name="opml_export_label">OPML export</string>
<string name="html_export_label">HTML export</string>
<string name="exporting_label">Exporting&#8230;</string>
@@ -639,7 +612,6 @@
<!-- Online feed view -->
<string name="subscribe_label">Subscribe</string>
- <string name="subscribed_label">Subscribed</string>
<string name="downloading_label">Downloading&#8230;</string>
<!-- Content descriptions for image buttons -->
@@ -762,7 +734,6 @@
<string name="cast_failed_setting_volume">Failed to set the volume</string>
<string name="cast_failed_no_connection">No connection to the cast device is present</string>
<string name="cast_failed_no_connection_trans">Connection to the cast device has been lost. Application is trying to re-establish the connection, if possible. Please wait for a few seconds and try again.</string>
- <string name="cast_failed_perform_action">Failed to perform the action</string>
<string name="cast_failed_status_request">Failed to sync up with the cast device</string>
<string name="cast_failed_seek">Failed to seek to the new position on the cast device</string>
<string name="cast_failed_receiver_player_error">Receiver player has encountered a severe error</string>
diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml
index fb69e54e7..d2ba4bb50 100644
--- a/core/src/main/res/values/styles.xml
+++ b/core/src/main/res/values/styles.xml
@@ -23,6 +23,7 @@
<item name="av_fast_forward">@drawable/ic_fast_forward_grey600_24dp</item>
<item name="av_pause">@drawable/ic_pause_grey600_24dp</item>
<item name="av_play">@drawable/ic_play_arrow_grey600_24dp</item>
+ <item name="av_speed">@drawable/ic_playback_speed_dark</item>
<item name="av_rewind">@drawable/ic_fast_rewind_grey600_24dp</item>
<item name="content_discard">@drawable/ic_delete_grey600_24dp</item>
<item name="content_new">@drawable/ic_add_grey600_24dp</item>
@@ -68,9 +69,9 @@
<item name="ic_create_new_folder">@drawable/ic_create_new_folder_grey600_24dp</item>
<item name="ic_cast_disconnect">@drawable/ic_cast_disconnect_grey600_36dp</item>
<item name="ic_cellphone_text">@drawable/ic_cellphone_text_grey600_24dp</item>
- <item name="ic_question_answer">@drawable/ic_forum_grey600_24dp</item>
+ <item name="ic_questionmark">@drawable/ic_questionmark_grey600</item>
+ <item name="ic_chat">@drawable/ic_chat_grey600</item>
<item name="ic_bug">@drawable/ic_bug_grey600_24dp</item>
- <item name="ic_known_issues">@drawable/ic_format_list_bulleted_grey600_24dp</item>
<item name="ic_bookmark">@drawable/ic_bookmark_grey600_24dp</item>
<item name="batch_edit_fab_icon">@drawable/ic_fab_edit_white</item>
<item name="master_switch_background">@color/master_switch_background_light</item>
@@ -108,6 +109,7 @@
<item name="av_fast_forward">@drawable/ic_fast_forward_white_24dp</item>
<item name="av_pause">@drawable/ic_pause_white_24dp</item>
<item name="av_play">@drawable/ic_play_arrow_white_24dp</item>
+ <item name="av_speed">@drawable/ic_playback_speed_white</item>
<item name="av_rewind">@drawable/ic_fast_rewind_white_24dp</item>
<item name="content_discard">@drawable/ic_delete_white_24dp</item>
<item name="content_new">@drawable/ic_add_white_24dp</item>
@@ -153,9 +155,9 @@
<item name="ic_create_new_folder">@drawable/ic_create_new_folder_white_24dp</item>
<item name="ic_cast_disconnect">@drawable/ic_cast_disconnect_white_36dp</item>
<item name="ic_cellphone_text">@drawable/ic_cellphone_text_white_24dp</item>
- <item name="ic_question_answer">@drawable/ic_baseline_question_answer_white_24dp</item>
+ <item name="ic_questionmark">@drawable/ic_questionmark_white</item>
+ <item name="ic_chat">@drawable/ic_chat_white</item>
<item name="ic_bug">@drawable/ic_bug_white_24dp</item>
- <item name="ic_known_issues">@drawable/ic_format_list_bulleted_white_24dp</item>
<item name="ic_bookmark">@drawable/ic_bookmark_white_24dp</item>
<item name="batch_edit_fab_icon">@drawable/ic_fab_edit_white</item>
<item name="master_switch_background">@color/master_switch_background_dark</item>
@@ -258,13 +260,6 @@
<item name="android:ellipsize">end</item>
</style>
- <style name="AntennaPod.Dialog.Title" parent="@android:style/TextAppearance.Medium">
- <item name="android:textSize">@dimen/text_size_medium</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
- <item name="android:maxLines">2</item>
- <item name="android:ellipsize">end</item>
- </style>
-
<style name="AntennaPod.TextView.UnreadIndicator" parent="@android:style/TextAppearance.Small">
<item name="android:textSize">@dimen/text_size_micro</item>
<item name="android:textColor">@color/new_indicator_green</item>
@@ -276,16 +271,6 @@
<item name="textAllCaps">false</item>
</style>
- <style name="Divider">
- <item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">1dp</item>
- <item name="android:layout_marginTop">8dp</item>
- <item name="android:layout_marginLeft">16dp</item>
- <item name="android:layout_marginRight">16dp</item>
- <item name="android:layout_marginBottom">8dp</item>
- <item name="android:background">?android:attr/listDivider</item>
- </style>
-
<style name="AntennaPod.Dialog.Light" parent="Theme.AppCompat.Light.Dialog">
<item name="colorAccent">@color/holo_blue_light</item>
</style>
diff --git a/core/src/play/java/de/danoeh/antennapod/core/CastCallbacks.java b/core/src/play/java/de/danoeh/antennapod/core/CastCallbacks.java
index 770fee9b9..27f985a4c 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/CastCallbacks.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/CastCallbacks.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core;
-import android.support.annotation.Nullable;
-import android.support.v7.app.MediaRouteDialogFactory;
+import androidx.annotation.Nullable;
+import androidx.mediarouter.app.MediaRouteDialogFactory;
/**
* Callbacks for Chromecast support on the core module
diff --git a/core/src/play/java/de/danoeh/antennapod/core/ClientConfig.java b/core/src/play/java/de/danoeh/antennapod/core/ClientConfig.java
index 244fb0254..800222ada 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/ClientConfig.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/ClientConfig.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.core;
import android.content.Context;
+import android.util.Log;
import de.danoeh.antennapod.core.cast.CastManager;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
@@ -15,6 +16,8 @@ import de.danoeh.antennapod.core.util.exception.RxJavaErrorHandlerSetup;
* Apps using the core module of AntennaPod should register implementations of all interfaces here.
*/
public class ClientConfig {
+ private static final String TAG = "ClientConfig";
+
private ClientConfig(){}
/**
@@ -44,7 +47,15 @@ public class ClientConfig {
UserPreferences.init(context);
PlaybackPreferences.init(context);
NetworkUtils.init(context);
- CastManager.init(context);
+ // Don't initialize Cast-related logic unless it is enabled, to avoid the unnecessary
+ // Google Play Service usage.
+ // Down side: when the user decides to enable casting, AntennaPod needs to be restarted
+ // for it to take effect.
+ if (UserPreferences.isCastEnabled()) {
+ CastManager.init(context);
+ } else {
+ Log.v(TAG, "Cast is disabled. All Cast-related initialization will be skipped.");
+ }
SleepTimerPreferences.init(context);
RxJavaErrorHandlerSetup.setupRxJavaErrorHandler();
initialized = true;
diff --git a/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java b/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java
index 5198a76bd..bf9ef3f5b 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java
@@ -24,10 +24,10 @@ package de.danoeh.antennapod.core.cast;
import android.content.Context;
import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.v4.view.ActionProvider;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.media.MediaRouter;
+import androidx.annotation.NonNull;
+import androidx.core.view.ActionProvider;
+import androidx.core.view.MenuItemCompat;
+import androidx.mediarouter.media.MediaRouter;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MenuItem;
@@ -163,6 +163,10 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
return INSTANCE;
}
+ public static boolean isInitialized() {
+ return INSTANCE != null;
+ }
+
/**
* Returns the active {@link RemoteMediaPlayer} instance. Since there are a number of media
* control APIs that this library do not provide a wrapper for, client applications can call
@@ -1731,7 +1735,7 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
* {@link SwitchableMediaRouteActionProvider} associated with the button if the caller needs
* such reference. It is assumed that the enclosing
* {@link android.app.Activity} inherits (directly or indirectly) from
- * {@link android.support.v7.app.AppCompatActivity}.
+ * {@link androidx.appcompat.app.AppCompatActivity}.
*
* @param menuItem MenuItem of the Media Router cast button.
*/
diff --git a/core/src/play/java/de/danoeh/antennapod/core/cast/RemoteMedia.java b/core/src/play/java/de/danoeh/antennapod/core/cast/RemoteMedia.java
index 1c6dd30c4..0614e5952 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/cast/RemoteMedia.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/cast/RemoteMedia.java
@@ -5,7 +5,7 @@ import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import android.text.TextUtils;
import com.google.android.gms.cast.MediaInfo;
diff --git a/core/src/play/java/de/danoeh/antennapod/core/cast/SwitchableMediaRouteActionProvider.java b/core/src/play/java/de/danoeh/antennapod/core/cast/SwitchableMediaRouteActionProvider.java
index f063cf5e3..5a6a0aa2b 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/cast/SwitchableMediaRouteActionProvider.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/cast/SwitchableMediaRouteActionProvider.java
@@ -3,12 +3,12 @@ package de.danoeh.antennapod.core.cast;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentManager;
-import android.support.v7.app.MediaRouteActionProvider;
-import android.support.v7.app.MediaRouteChooserDialogFragment;
-import android.support.v7.app.MediaRouteControllerDialogFragment;
-import android.support.v7.media.MediaRouter;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+import androidx.mediarouter.app.MediaRouteActionProvider;
+import androidx.mediarouter.app.MediaRouteChooserDialogFragment;
+import androidx.mediarouter.app.MediaRouteControllerDialogFragment;
+import androidx.mediarouter.media.MediaRouter;
import android.util.Log;
/**
diff --git a/core/src/play/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java b/core/src/play/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java
index 7ab1be380..c32ba2385 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java
@@ -7,11 +7,11 @@ import android.content.IntentFilter;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
-import android.support.v7.media.MediaRouter;
+import androidx.mediarouter.media.MediaRouter;
import android.support.wearable.media.MediaControlConstants;
import android.util.Log;
import android.widget.Toast;
@@ -56,11 +56,18 @@ public class PlaybackServiceFlavorHelper {
PlaybackServiceFlavorHelper(Context context, PlaybackService.FlavorHelperCallback callback) {
this.callback = callback;
+ if (!CastManager.isInitialized()) {
+ return;
+ }
mediaRouter = MediaRouter.getInstance(context.getApplicationContext());
setCastConsumer(context);
}
void initializeMediaPlayer(Context context) {
+ if (!CastManager.isInitialized()) {
+ callback.setMediaPlayer(new LocalPSMP(context, callback.getMediaPlayerCallback()));
+ return;
+ }
castManager = CastManager.getInstance();
castManager.addCastConsumer(castConsumer);
boolean isCasting = castManager.isConnected();
@@ -77,10 +84,16 @@ public class PlaybackServiceFlavorHelper {
}
void removeCastConsumer() {
+ if (!CastManager.isInitialized()) {
+ return;
+ }
castManager.removeCastConsumer(castConsumer);
}
boolean castDisconnect(boolean castDisconnect) {
+ if (!CastManager.isInitialized()) {
+ return false;
+ }
if (castDisconnect) {
castManager.disconnect();
}
@@ -88,6 +101,9 @@ public class PlaybackServiceFlavorHelper {
}
boolean onMediaPlayerInfo(Context context, int code, @StringRes int resourceId) {
+ if (!CastManager.isInitialized()) {
+ return false;
+ }
switch (code) {
case RemotePSMP.CAST_ERROR:
callback.sendNotificationBroadcast(PlaybackService.NOTIFICATION_TYPE_SHOW_TOAST, resourceId);
@@ -218,6 +234,9 @@ public class PlaybackServiceFlavorHelper {
}
void registerWifiBroadcastReceiver() {
+ if (!CastManager.isInitialized()) {
+ return;
+ }
if (wifiBroadcastReceiver != null) {
return;
}
@@ -243,6 +262,9 @@ public class PlaybackServiceFlavorHelper {
}
void unregisterWifiBroadcastReceiver() {
+ if (!CastManager.isInitialized()) {
+ return;
+ }
if (wifiBroadcastReceiver != null) {
callback.unregisterReceiver(wifiBroadcastReceiver);
wifiBroadcastReceiver = null;
@@ -250,6 +272,9 @@ public class PlaybackServiceFlavorHelper {
}
boolean onSharedPreference(String key) {
+ if (!CastManager.isInitialized()) {
+ return false;
+ }
if (UserPreferences.PREF_CAST_ENABLED.equals(key)) {
if (!UserPreferences.isCastEnabled()) {
if (castManager.isConnecting() || castManager.isConnected()) {
@@ -263,6 +288,9 @@ public class PlaybackServiceFlavorHelper {
}
void sessionStateAddActionForWear(PlaybackStateCompat.Builder sessionState, String actionName, CharSequence name, int icon) {
+ if (!CastManager.isInitialized()) {
+ return;
+ }
PlaybackStateCompat.CustomAction.Builder actionBuilder =
new PlaybackStateCompat.CustomAction.Builder(actionName, name, icon);
Bundle actionExtras = new Bundle();
@@ -273,6 +301,9 @@ public class PlaybackServiceFlavorHelper {
}
void mediaSessionSetExtraForWear(MediaSessionCompat mediaSession) {
+ if (!CastManager.isInitialized()) {
+ return;
+ }
Bundle sessionExtras = new Bundle();
sessionExtras.putBoolean(MediaControlConstants.EXTRA_RESERVE_SLOT_SKIP_TO_PREVIOUS, true);
sessionExtras.putBoolean(MediaControlConstants.EXTRA_RESERVE_SLOT_SKIP_TO_NEXT, true);
diff --git a/core/src/play/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java b/core/src/play/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java
index f91264c59..63fc05cb8 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.service.playback;
import android.content.Context;
import android.media.MediaPlayer;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import android.util.Pair;
import android.view.SurfaceHolder;
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 000000000..431e485f2
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,3 @@
+android.useAndroidX=true
+android.enableJetifier=true
+org.gradle.jvmargs=-Xmx4096m