The Android internal media player blocks its `start()` call until the
seek listener completes. The seek listener is called on the main thread
even though `start()` is called on the executor. This makes the main
thread wait for the lock and the executor (which has the lock) wait for the
main thread to finish the call to the listener.
The cover fragment would hide both podcast and episode names in small
screen devices or multi-window mode.
This replaces the deprecated PercentRelativeLayout in favor of a regular
LinearLayout with weights to make sure that each section of the fragment
(podcast title, image, episode name) will have the necessary space in
the screen.
Since PercentRelativeLayout was only being used here, it also removes
the dependencies from the gradle files.
Closes: #3169
Callbacks are called on the thread that created the MediaPlayer.
For Sonic, this is the executor. For ExoPlayer, this is the main thread.
When calling executor.submit, every thread waiting for the runnable to
complete gets blocked.
Because the callback is called in the thread that created the player,
we can simply remove the call to executor.submit and still be sure
that a background thread is used.
Apple says this [1] about the `<itunes:duration>` tag:
If you specify a single number as a value (without colons), Apple
Podcasts displays the value as seconds.
This commit makes it also handle this single-number format.
Closes: #3024
[1]: https://help.apple.com/itc/podcasts_connect/#/itcb54353390
Also made sure that register/unregister are called in onStart/onStop
instead of onResume/onPause (prevents possible MultiWindow problems
where updates are not received because activity is not fucused).
should never happen in the code path, e.g.,
return the current FeedItem in ItemFragment UI.
Mark underlying method as @Nullable, and let observer's existing
onError() to handle null case
Rx observer : underlying sources marked as @Nullable
ItemFragment.load : .loadInBackground
MediaplayerActivity.checkFavorite : DBReader.getFeedItem
ItemDescriptionFragment.onViewCreated : DBReader.getFeedItem
ItemlistFragment.loadItems : .loadData
to be on the safe side, for cases that the consuming observers checks null
unnecessarily.
Rx observer : underlying sources marked as NonNull
OnlineFeedViewActivity.startFeedDownload : Downloader.getResult
AllEpisodesFragment.loadItems : AllEpisodesFragment.loadData
PlaybackHistoryFragment.loadItems : DBReader.getPlaybackHistory
QueueFragment.loadItems : DBReader.getQueue
SearchFragment.search : .performSearch
to be on the safe side, for cases that the consuming observers
already assumes the result is not null.
Rx observer : underlying sources marked as NonNull
OnlineFeedViewActivity.listener member : DBReader.getFeedList
StatisticsActivity.loadStatistics : DBReader.getStatistics
CustomMRControllerDialog.updateViews : CustomMRControllerDialog.fetchArt
CompletedDownloadsFragment.loadItems : DBReader.getDownloadedItems
DownloadLogFragment.loadItems : DBReader.getDownloadedItems
ItemDescriptionFragment.onViewCreated : .loadData, Timeline.processShownotes
SubscriptionFragment.loadSubscriptions : DBReader.getNavDrawerData
SubscriptionFragment.onContextItemSelected (x2) : DBWriter.markFeedSeen, DBWriter.markFeedRead
PreferenceController.export : ExportWorker.output member