diff options
Diffstat (limited to 'core')
75 files changed, 1103 insertions, 1236 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/ApplicationCallbacks.java b/core/src/main/java/de/danoeh/antennapod/core/ApplicationCallbacks.java index 1064e98ac..3acc84e3b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/ApplicationCallbacks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/ApplicationCallbacks.java @@ -12,12 +12,12 @@ public interface ApplicationCallbacks { /** * Returns a non-null instance of the application class */ - public Application getApplicationInstance(); + Application getApplicationInstance(); /** * Returns a non-null intent that starts the storage error * activity. */ - public Intent getStorageErrorActivity(Context context); + Intent getStorageErrorActivity(Context context); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/DBTasksCallbacks.java b/core/src/main/java/de/danoeh/antennapod/core/DBTasksCallbacks.java index edf3e3199..11a6b2c9f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/DBTasksCallbacks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/DBTasksCallbacks.java @@ -11,10 +11,10 @@ public interface DBTasksCallbacks { /** * Returns the client's implementation of the AutomaticDownloadAlgorithm interface. */ - public AutomaticDownloadAlgorithm getAutomaticDownloadAlgorithm(); + AutomaticDownloadAlgorithm getAutomaticDownloadAlgorithm(); /** * Returns the client's implementation of the EpisodeCacheCleanupAlgorithm interface. */ - public EpisodeCleanupAlgorithm getEpisodeCacheCleanupAlgorithm(); + EpisodeCleanupAlgorithm getEpisodeCacheCleanupAlgorithm(); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/DownloadServiceCallbacks.java b/core/src/main/java/de/danoeh/antennapod/core/DownloadServiceCallbacks.java index 286e830c5..e56445489 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/DownloadServiceCallbacks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/DownloadServiceCallbacks.java @@ -19,7 +19,7 @@ public interface DownloadServiceCallbacks { * * @return A non-null PendingIntent for the notification. */ - public PendingIntent getNotificationContentIntent(Context context); + PendingIntent getNotificationContentIntent(Context context); /** * Returns a PendingIntent for a notification that tells the user to enter a username @@ -30,7 +30,7 @@ public interface DownloadServiceCallbacks { * * @return A non-null PendingIntent for the notification. */ - public PendingIntent getAuthentificationNotificationContentIntent(Context context, DownloadRequest request); + PendingIntent getAuthentificationNotificationContentIntent(Context context, DownloadRequest request); /** * Returns a PendingIntent for notification that notifies the user about the completion of downloads @@ -40,19 +40,19 @@ public interface DownloadServiceCallbacks { * * @return A non-null PendingIntent for the notification or null if shouldCreateReport()==false */ - public PendingIntent getReportNotificationContentIntent(Context context); + PendingIntent getReportNotificationContentIntent(Context context); /** * Called by the FeedSyncThread after a feed has been downloaded and parsed. * * @param feed The non-null feed that has been parsed. */ - public void onFeedParsed(Context context, Feed feed); + void onFeedParsed(Context context, Feed feed); /** * Returns true if the DownloadService should create a report that shows the number of failed * downloads when the service shuts down. * */ - public boolean shouldCreateReport(); + boolean shouldCreateReport(); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/FlattrCallbacks.java b/core/src/main/java/de/danoeh/antennapod/core/FlattrCallbacks.java index cee1029d8..5fa6faa13 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/FlattrCallbacks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/FlattrCallbacks.java @@ -15,7 +15,7 @@ public interface FlattrCallbacks { * Returns if true if the flattr integration should be activated, * false otherwise. */ - public boolean flattrEnabled(); + boolean flattrEnabled(); /** * Returns an intent that starts the activity that is responsible for @@ -24,13 +24,13 @@ public interface FlattrCallbacks { * @return The intent that starts the authentication activity or null * if flattr integration is disabled (i.e. flattrEnabled() == false). */ - public Intent getFlattrAuthenticationActivityIntent(Context context); + Intent getFlattrAuthenticationActivityIntent(Context context); - public PendingIntent getFlattrFailedNotificationContentIntent(Context context); + PendingIntent getFlattrFailedNotificationContentIntent(Context context); - public String getFlattrAppKey(); + String getFlattrAppKey(); - public String getFlattrAppSecret(); + String getFlattrAppSecret(); - public void handleFlattrAuthenticationSuccess(AccessToken token); + void handleFlattrAuthenticationSuccess(AccessToken token); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/GpodnetCallbacks.java b/core/src/main/java/de/danoeh/antennapod/core/GpodnetCallbacks.java index 6174bce29..10797ecfb 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/GpodnetCallbacks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/GpodnetCallbacks.java @@ -13,7 +13,7 @@ public interface GpodnetCallbacks { * Returns if true if the gpodder.net integration should be activated, * false otherwise. */ - public boolean gpodnetEnabled(); + boolean gpodnetEnabled(); /** * Returns a PendingIntent for the error notification of the GpodnetSyncService. @@ -23,5 +23,5 @@ public interface GpodnetCallbacks { * @return A PendingIntent for the notification or null if gpodder.net integration * has been disabled (i.e. gpodnetEnabled() == false). */ - public PendingIntent getGpodnetSyncServiceErrorNotificationPendingIntent(Context context); + PendingIntent getGpodnetSyncServiceErrorNotificationPendingIntent(Context context); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/PlaybackServiceCallbacks.java b/core/src/main/java/de/danoeh/antennapod/core/PlaybackServiceCallbacks.java index fb01fa703..08ccb6d71 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/PlaybackServiceCallbacks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/PlaybackServiceCallbacks.java @@ -17,17 +17,17 @@ public interface PlaybackServiceCallbacks { * @param mediaType The type of media that is being played. * @return A non-null activity intent. */ - public Intent getPlayerActivityIntent(Context context, MediaType mediaType); + Intent getPlayerActivityIntent(Context context, MediaType mediaType); /** * Returns true if the PlaybackService should load new episodes from the queue when playback ends * and false if the PlaybackService should ignore the queue and load no more episodes when playback * finishes. */ - public boolean useQueue(); + boolean useQueue(); /** * Returns a drawable resource that is used for the notification of the playback service. */ - public int getNotificationIconResource(Context context); + int getNotificationIconResource(Context context); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FeedRemover.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FeedRemover.java index 7ff622f34..e475e696c 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FeedRemover.java +++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FeedRemover.java @@ -30,9 +30,7 @@ public class FeedRemover extends AsyncTask<Void, Void, Void> { protected Void doInBackground(Void... params) { try { DBWriter.deleteFeed(context, feed.getId()).get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { + } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } return null; diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java index c0ec8d08a..3ddaba52e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java +++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java @@ -45,7 +45,7 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke private final Context context; - public static enum ExitCode {EXIT_NORMAL, NO_TOKEN, NO_NETWORK, NO_THINGS} + public enum ExitCode {EXIT_NORMAL, NO_TOKEN, NO_NETWORK, NO_THINGS} private final AtomicInteger countFailed = new AtomicInteger(); private final AtomicInteger countSuccess = new AtomicInteger(); @@ -106,7 +106,7 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke return ExitCode.NO_THINGS; } - List<Future> dbFutures = new LinkedList<Future>(); + List<Future> dbFutures = new LinkedList<>(); for (FlattrThing thing : flattrQueue) { if (BuildConfig.DEBUG) Log.d(TAG, "Processing " + thing.getTitle()); @@ -134,9 +134,7 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke for (Future f : dbFutures) { try { f.get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { + } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrStatusFetcher.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrStatusFetcher.java index 888591e89..4c084eaaf 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrStatusFetcher.java +++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrStatusFetcher.java @@ -2,15 +2,17 @@ package de.danoeh.antennapod.core.asynctask; import android.content.Context; import android.util.Log; -import de.danoeh.antennapod.core.BuildConfig; -import de.danoeh.antennapod.core.storage.DBWriter; -import de.danoeh.antennapod.core.util.flattr.FlattrUtils; + import org.shredzone.flattr4j.exception.FlattrException; import org.shredzone.flattr4j.model.Flattr; import java.util.List; import java.util.concurrent.ExecutionException; +import de.danoeh.antennapod.core.BuildConfig; +import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.core.util.flattr.FlattrUtils; + /** * Fetch list of flattred things and flattr status in database in a background thread. */ @@ -36,9 +38,7 @@ public class FlattrStatusFetcher extends Thread { } catch (FlattrException e) { e.printStackTrace(); Log.d(TAG, "flattrQueue exception retrieving list with flattred items " + e.getMessage()); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { + } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/ImageResource.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/ImageResource.java index edd69f15b..992321441 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/ImageResource.java +++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/ImageResource.java @@ -16,13 +16,13 @@ public interface ImageResource { * <p/> * For example implementations, see FeedMedia or ExternalMedia. */ - public static final String SCHEME_MEDIA = "media"; + String SCHEME_MEDIA = "media"; /** * Parameter key for an encoded fallback Uri. This Uri MUST point to a local image file */ - public static final String PARAM_FALLBACK = "fallback"; + String PARAM_FALLBACK = "fallback"; /** * Returns a Uri to the image or null if no image is available. @@ -33,5 +33,5 @@ public interface ImageResource { * The Uri can also have an optional fallback-URL if loading the default URL * failed (see PARAM_FALLBACK). */ - public Uri getImageUri(); + Uri getImageUri(); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java b/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java index 690fbdfc6..982015314 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java +++ b/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java @@ -8,7 +8,6 @@ import android.content.Context; import android.os.ParcelFileDescriptor; import android.util.Log; -import de.danoeh.antennapod.core.BuildConfig; import org.xmlpull.v1.XmlPullParserException; import java.io.ByteArrayOutputStream; @@ -26,8 +25,8 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Date; +import de.danoeh.antennapod.core.BuildConfig; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.opml.OpmlElement; import de.danoeh.antennapod.core.opml.OpmlReader; @@ -45,13 +44,13 @@ public class OpmlBackupAgent extends BackupAgentHelper { addHelper(OPML_BACKUP_KEY, new OpmlBackupHelper(this)); } - private static final void LOGD(String tag, String msg) { + private static void LOGD(String tag, String msg) { if (BuildConfig.DEBUG && Log.isLoggable(tag, Log.DEBUG)) { Log.d(tag, msg); } } - private static final void LOGD(String tag, String msg, Throwable tr) { + private static void LOGD(String tag, String msg, Throwable tr) { if (BuildConfig.DEBUG && Log.isLoggable(tag, Log.DEBUG)) { Log.d(tag, msg, tr); } 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 abb75e5e7..266526d82 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 @@ -49,28 +49,10 @@ public abstract class ConfirmationDialog { builder.setTitle(titleId); builder.setMessage(messageId); builder.setPositiveButton(positiveText != 0 ? positiveText : R.string.confirm_label, - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - onConfirmButtonPressed(dialog); - } - }); + (dialog, which) -> onConfirmButtonPressed(dialog)); builder.setNegativeButton(negativeText != 0 ? negativeText : R.string.cancel_label, - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - onCancelButtonPressed(dialog); - } - }); - builder.setOnCancelListener(new DialogInterface.OnCancelListener() { - - @Override - public void onCancel(DialogInterface dialog) { - onCancelButtonPressed(dialog); - } - }); + (dialog, which) -> onCancelButtonPressed(dialog)); + builder.setOnCancelListener(ConfirmationDialog.this::onCancelButtonPressed); return builder.create(); } } 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 b7e79431d..b1beac315 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,6 @@ package de.danoeh.antennapod.core.dialog; import android.content.Context; -import android.content.DialogInterface; import android.support.v7.app.AlertDialog; import de.danoeh.antennapod.core.R; @@ -15,13 +14,7 @@ public class DownloadRequestErrorDialogCreator { String errorMessage) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setNeutralButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }) + (dialog, which) -> dialog.dismiss()) .setTitle(R.string.download_error_request_error) .setMessage( context.getString(R.string.download_request_error_dialog_message_prefix) diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java b/core/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java index 7ccb742fb..dbad084c7 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java @@ -34,7 +34,7 @@ public class EventDistributor extends Observable { private EventDistributor() { this.handler = new Handler(); - events = new ConcurrentLinkedQueue<Integer>(); + events = new ConcurrentLinkedQueue<>(); } public static synchronized EventDistributor getInstance() { @@ -54,13 +54,7 @@ public class EventDistributor extends Observable { public void addEvent(Integer i) { events.offer(i); - handler.post(new Runnable() { - - @Override - public void run() { - processEventQueue(); - } - }); + handler.post(EventDistributor.this::processEventQueue); } private void processEventQueue() { 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 d2d7cbc73..67ac2d280 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 @@ -112,7 +112,7 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource { this.flattrStatus = status; this.paged = paged; this.nextPageLink = nextPageLink; - this.items = new ArrayList<FeedItem>(); + this.items = new ArrayList<>(); if(filter != null) { this.itemfilter = new FeedItemFilter(filter); } else { @@ -235,7 +235,7 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource { */ public boolean hasUnplayedItems() { for (FeedItem item : items) { - if (false == item.isNew() && false == item.isPlayed()) { + if (!item.isNew() && !item.isPlayed()) { return true; } } @@ -324,12 +324,11 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource { if (super.compareWithOther(other)) { return true; } - if (!title.equals(other.title)) { + if (!TextUtils.equals(title, other.title)) { return true; } if (other.feedIdentifier != null) { - if (feedIdentifier == null - || !feedIdentifier.equals(other.feedIdentifier)) { + if (feedIdentifier == null || !feedIdentifier.equals(other.feedIdentifier)) { return true; } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java index 05115c1ea..90b5e50b7 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java @@ -54,9 +54,8 @@ public abstract class FeedComponent { FeedComponent that = (FeedComponent) o; - if (id != that.id) return false; + return id == that.id; - return true; } @Override diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedFile.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedFile.java index 3dc58654b..ca9af058b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedFile.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedFile.java @@ -1,5 +1,7 @@ package de.danoeh.antennapod.core.feed; +import android.text.TextUtils; + import java.io.File; /** @@ -54,7 +56,7 @@ public abstract class FeedFile extends FeedComponent { if (super.compareWithOther(other)) { return true; } - if (!download_url.equals(other.download_url)) { + if (!TextUtils.equals(download_url, other.download_url)) { return true; } return false; 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 d8c32f55e..b2192c66f 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 @@ -171,9 +171,8 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr String itemIdentifier = cursor.getString(indexItemIdentifier); long autoDownload = cursor.getLong(indexAutoDownload); - FeedItem item = new FeedItem(id, title, link, pubDate, paymentLink, feedId, flattrStatus, + return new FeedItem(id, title, link, pubDate, paymentLink, feedId, flattrStatus, hasChapters, null, state, itemIdentifier, autoDownload); - return item; } public void updateFromOther(FeedItem other) { @@ -359,24 +358,16 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr } private boolean isPlaying() { - if (media != null) { - return media.isPlaying(); - } - return false; + return media != null && media.isPlaying(); } @Override public Callable<String> loadShownotes() { - return new Callable<String>() { - @Override - public String call() throws Exception { - - if (contentEncoded == null || description == null) { - DBReader.loadExtraInformationOfFeedItem(FeedItem.this); - - } - return (contentEncoded != null) ? contentEncoded : description; + return () -> { + if (contentEncoded == null || description == null) { + DBReader.loadExtraInformationOfFeedItem(FeedItem.this); } + return (contentEncoded != null) ? contentEncoded : description; }; } 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 6b11e162e..8a04e65ec 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 @@ -499,20 +499,17 @@ public class FeedMedia extends FeedFile implements Playable { @Override public Callable<String> loadShownotes() { - return new Callable<String>() { - @Override - public String call() throws Exception { - if (item == null) { - item = DBReader.getFeedItem( - itemID); - } - if (item.getContentEncoded() == null || item.getDescription() == null) { - DBReader.loadExtraInformationOfFeedItem( - item); + return () -> { + if (item == null) { + item = DBReader.getFeedItem( + itemID); + } + if (item.getContentEncoded() == null || item.getDescription() == null) { + DBReader.loadExtraInformationOfFeedItem( + item); - } - return (item.getContentEncoded() != null) ? item.getContentEncoded() : item.getDescription(); } + return (item.getContentEncoded() != null) ? item.getContentEncoded() : item.getDescription(); }; } 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 faf23a37a..e2b5dd7c2 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 @@ -68,7 +68,7 @@ public class FeedPreferences { /** * @return the filter for this feed */ - public FeedFilter getFilter() { + public @NonNull FeedFilter getFilter() { return filter; } @@ -95,8 +95,9 @@ public class FeedPreferences { * @return True if the two objects are different. */ public boolean compareWithOther(FeedPreferences other) { - if (other == null) + if (other == null) { return true; + } if (!TextUtils.equals(username, other.username)) { return true; } 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 86baa459c..513264a05 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 @@ -18,7 +18,6 @@ import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; -import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; import de.danoeh.antennapod.core.service.download.HttpDownloader; import de.danoeh.antennapod.core.storage.DBReader; @@ -107,7 +106,6 @@ public class ApOkHttpUrlLoader implements ModelLoader<GlideUrl, InputStream> { public Response intercept(Chain chain) throws IOException { com.squareup.okhttp.Request request = chain.request(); String url = request.urlString(); - Context context = ClientConfig.applicationCallbacks.getApplicationInstance(); String authentication = DBReader.getImageAuthentication(url); if(TextUtils.isEmpty(authentication)) { 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 48f234917..9f716e546 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 @@ -80,7 +80,7 @@ public class GpodnetService { String response = executeRequest(request); try { JSONArray jsonTagList = new JSONArray(response); - List<GpodnetTag> tagList = new ArrayList<GpodnetTag>( + List<GpodnetTag> tagList = new ArrayList<>( jsonTagList.length()); for (int i = 0; i < jsonTagList.length(); i++) { JSONObject jObj = jsonTagList.getJSONObject(i); @@ -318,8 +318,7 @@ public class GpodnetService { URL url = new URI(BASE_SCHEME, BASE_HOST, String.format( "/subscriptions/%s.opml", username), null).toURL(); Request.Builder request = new Request.Builder().url(url); - String response = executeRequest(request); - return response; + return executeRequest(request); } catch (MalformedURLException | URISyntaxException e) { e.printStackTrace(); throw new GpodnetServiceException(e); @@ -660,7 +659,7 @@ public class GpodnetService { private List<GpodnetPodcast> readPodcastListFromJSONArray(@NonNull JSONArray array) throws JSONException { - List<GpodnetPodcast> result = new ArrayList<GpodnetPodcast>( + List<GpodnetPodcast> result = new ArrayList<>( array.length()); for (int i = 0; i < array.length(); i++) { result.add(readPodcastFromJSONObject(array.getJSONObject(i))); @@ -712,7 +711,7 @@ public class GpodnetService { private List<GpodnetDevice> readDeviceListFromJSONArray(@NonNull JSONArray array) throws JSONException { - List<GpodnetDevice> result = new ArrayList<GpodnetDevice>( + List<GpodnetDevice> result = new ArrayList<>( array.length()); for (int i = 0; i < array.length(); i++) { result.add(readDeviceFromJSONObject(array.getJSONObject(i))); @@ -732,7 +731,7 @@ public class GpodnetService { private GpodnetSubscriptionChange readSubscriptionChangesFromJSONObject( @NonNull JSONObject object) throws JSONException { - List<String> added = new LinkedList<String>(); + List<String> added = new LinkedList<>(); JSONArray jsonAdded = object.getJSONArray("add"); for (int i = 0; i < jsonAdded.length(); i++) { String addedUrl = jsonAdded.getString(i); @@ -741,7 +740,7 @@ public class GpodnetService { added.add(addedUrl); } - List<String> removed = new LinkedList<String>(); + List<String> removed = new LinkedList<>(); JSONArray jsonRemoved = object.getJSONArray("remove"); for (int i = 0; i < jsonRemoved.length(); i++) { String removedUrl = jsonRemoved.getString(i); @@ -757,7 +756,7 @@ public class GpodnetService { private GpodnetEpisodeActionGetResponse readEpisodeActionsFromJSONObject( @NonNull JSONObject object) throws JSONException { - List<GpodnetEpisodeAction> episodeActions = new ArrayList<GpodnetEpisodeAction>(); + List<GpodnetEpisodeAction> episodeActions = new ArrayList<>(); long timestamp = object.getLong("timestamp"); JSONArray jsonActions = object.getJSONArray("actions"); 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 2d49c170a..79eb33cb5 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 @@ -25,7 +25,7 @@ public class GpodnetDevice { + type + ", subscriptions=" + subscriptions + "]"; } - public static enum DeviceType { + public enum DeviceType { DESKTOP, LAPTOP, MOBILE, SERVER, OTHER; static DeviceType fromString(String s) { @@ -33,16 +33,17 @@ public class GpodnetDevice { return OTHER; } - if (s.equals("desktop")) { - return DESKTOP; - } else if (s.equals("laptop")) { - return LAPTOP; - } else if (s.equals("mobile")) { - return MOBILE; - } else if (s.equals("server")) { - return SERVER; - } else { - return OTHER; + switch (s) { + case "desktop": + return DESKTOP; + case "laptop": + return LAPTOP; + case "mobile": + return MOBILE; + case "server": + return SERVER; + default: + return OTHER; } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeAction.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeAction.java index 01c888d6b..9627ecae6 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeAction.java +++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeAction.java @@ -61,14 +61,13 @@ public class GpodnetEpisodeAction { String deviceId = fields[2]; try { Action action = Action.valueOf(fields[3]); - GpodnetEpisodeAction result = new Builder(podcast, episode, action) + return new Builder(podcast, episode, action) .deviceId(deviceId) .timestamp(new Date(Long.parseLong(fields[4]))) .started(Integer.parseInt(fields[5])) .position(Integer.parseInt(fields[6])) .total(Integer.parseInt(fields[7])) .build(); - return result; } catch(IllegalArgumentException e) { Log.e(TAG, "readFromString(" + s + "): " + e.getMessage()); return null; 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 5f096db14..03c33c9a1 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 @@ -38,7 +38,7 @@ public class GpodnetEpisodeActionPostResponse { final JSONObject object = new JSONObject(objectString); final long timestamp = object.getLong("timestamp"); JSONArray urls = object.getJSONArray("update_urls"); - Map<String, String> updatedUrls = new ArrayMap<String, String>(urls.length()); + Map<String, String> updatedUrls = new ArrayMap<>(urls.length()); for (int i = 0; i < urls.length(); i++) { JSONArray urlPair = urls.getJSONArray(i); updatedUrls.put(urlPair.getString(0), urlPair.getString(1)); diff --git a/core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java b/core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java index b8d17bcce..f63c9aeb0 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java @@ -32,7 +32,7 @@ public class MenuItemUtils { } } - public static interface UpdateRefreshMenuItemChecker { - public boolean isRefreshing(); + public interface UpdateRefreshMenuItemChecker { + boolean isRefreshing(); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/opml/OpmlReader.java b/core/src/main/java/de/danoeh/antennapod/core/opml/OpmlReader.java index 775129d09..17afc7904 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/opml/OpmlReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/opml/OpmlReader.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.core.opml; import android.util.Log; -import de.danoeh.antennapod.core.BuildConfig; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; @@ -10,6 +10,8 @@ import java.io.IOException; import java.io.Reader; import java.util.ArrayList; +import de.danoeh.antennapod.core.BuildConfig; + /** Reads OPML documents. */ public class OpmlReader { private static final String TAG = "OpmlReader"; @@ -27,7 +29,7 @@ public class OpmlReader { */ public ArrayList<OpmlElement> readDocument(Reader reader) throws XmlPullParserException, IOException { - elementList = new ArrayList<OpmlElement>(); + elementList = new ArrayList<>(); XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); factory.setNamespaceAware(true); XmlPullParser xpp = factory.newPullParser(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java index edd7b807a..6d4d3baa6 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java +++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java @@ -189,7 +189,7 @@ public class GpodnetPreferences { public static Set<String> getAddedFeedsCopy() { ensurePreferencesLoaded(); - Set<String> copy = new HashSet<String>(); + Set<String> copy = new HashSet<>(); feedListLock.lock(); copy.addAll(addedFeeds); feedListLock.unlock(); @@ -206,7 +206,7 @@ public class GpodnetPreferences { public static Set<String> getRemovedFeedsCopy() { ensurePreferencesLoaded(); - Set<String> copy = new HashSet<String>(); + Set<String> copy = new HashSet<>(); feedListLock.lock(); copy.addAll(removedFeeds); feedListLock.unlock(); @@ -232,7 +232,7 @@ public class GpodnetPreferences { public static List<GpodnetEpisodeAction> getQueuedEpisodeActions() { ensurePreferencesLoaded(); - List<GpodnetEpisodeAction> copy = new ArrayList(); + List<GpodnetEpisodeAction> copy = new ArrayList<>(); feedListLock.lock(); copy.addAll(queuedEpisodeActions); feedListLock.unlock(); @@ -272,7 +272,7 @@ public class GpodnetPreferences { } private static Set<String> readListFromString(String s) { - Set<String> result = new HashSet<String>(); + Set<String> result = new HashSet<>(); for (String item : s.split(" ")) { result.add(item); } @@ -290,7 +290,7 @@ public class GpodnetPreferences { private static List<GpodnetEpisodeAction> readEpisodeActionsFromString(String s) { String[] lines = s.split("\n"); - List<GpodnetEpisodeAction> result = new ArrayList<GpodnetEpisodeAction>(lines.length); + List<GpodnetEpisodeAction> result = new ArrayList<>(lines.length); for(String line : lines) { if(TextUtils.isEmpty(line)) { GpodnetEpisodeAction action = GpodnetEpisodeAction.readFromString(line); 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 aa20b69b6..2541a27aa 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 @@ -292,7 +292,7 @@ public class UserPreferences { public static long getUpdateInterval() { String updateInterval = prefs.getString(PREF_UPDATE_INTERVAL, "0"); - if(false == updateInterval.contains(":")) { + if(!updateInterval.contains(":")) { return readUpdateInterval(updateInterval); } else { return 0; @@ -411,8 +411,7 @@ public class UserPreferences { int port = prefs.getInt(PREF_PROXY_PORT, 0); String username = prefs.getString(PREF_PROXY_USER, null); String password = prefs.getString(PREF_PROXY_PASSWORD, null); - ProxyConfig config = new ProxyConfig(type, host, port, username, password); - return config; + return new ProxyConfig(type, host, port, username, password); } public static boolean shouldResumeAfterCall() { @@ -546,15 +545,7 @@ public class UserPreferences { String[] selectedSpeeds = null; // If this preference hasn't been set yet, return the default options if (valueFromPrefs == null) { - String[] allSpeeds = context.getResources().getStringArray(R.array.playback_speed_values); - List<String> speedList = new ArrayList<>(); - for (String speedStr : allSpeeds) { - float speed = Float.parseFloat(speedStr); - if (speed < 2.0001 && speed * 10 % 1 == 0) { - speedList.add(speedStr); - } - } - selectedSpeeds = speedList.toArray(new String[speedList.size()]); + selectedSpeeds = new String[] { "1.00", "1.25", "1.50", "1.75", "2.00" }; } else { try { JSONArray jsonArray = new JSONArray(valueFromPrefs); 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 be6cd88cb..3f0112b56 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 @@ -41,11 +41,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -252,54 +249,35 @@ public class DownloadService extends Service { Log.d(TAG, "Service started"); isRunning = true; handler = new Handler(); - reportQueue = Collections.synchronizedList(new ArrayList<DownloadStatus>()); - downloads = Collections.synchronizedList(new ArrayList<Downloader>()); + reportQueue = Collections.synchronizedList(new ArrayList<>()); + downloads = Collections.synchronizedList(new ArrayList<>()); numberOfDownloads = new AtomicInteger(0); IntentFilter cancelDownloadReceiverFilter = new IntentFilter(); cancelDownloadReceiverFilter.addAction(ACTION_CANCEL_ALL_DOWNLOADS); cancelDownloadReceiverFilter.addAction(ACTION_CANCEL_DOWNLOAD); registerReceiver(cancelDownloadReceiver, cancelDownloadReceiverFilter); - syncExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() { - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setPriority(Thread.MIN_PRIORITY); - return t; - } + syncExecutor = Executors.newSingleThreadExecutor(r -> { + Thread t = new Thread(r); + t.setPriority(Thread.MIN_PRIORITY); + return t; }); Log.d(TAG, "parallel downloads: " + UserPreferences.getParallelDownloads()); - downloadExecutor = new ExecutorCompletionService<Downloader>( + downloadExecutor = new ExecutorCompletionService<>( Executors.newFixedThreadPool(UserPreferences.getParallelDownloads(), - new ThreadFactory() { - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setPriority(Thread.MIN_PRIORITY); - return t; - } + r -> { + Thread t = new Thread(r); + t.setPriority(Thread.MIN_PRIORITY); + return t; } ) ); schedExecutor = new ScheduledThreadPoolExecutor(SCHED_EX_POOL_SIZE, - new ThreadFactory() { - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setPriority(Thread.MIN_PRIORITY); - return t; - } - }, new RejectedExecutionHandler() { - - @Override - public void rejectedExecution(Runnable r, - ThreadPoolExecutor executor) { - Log.w(TAG, "SchedEx rejected submission of new task"); - } - } + r -> { + Thread t = new Thread(r); + t.setPriority(Thread.MIN_PRIORITY); + return t; + }, (r, executor) -> Log.w(TAG, "SchedEx rejected submission of new task") ); downloadCompletionThread.start(); feedSyncThread = new FeedSyncThread(); @@ -383,16 +361,16 @@ public class DownloadService extends Service { if (i > 0) { bigText.append("\n"); } - bigText.append("\u2022 " + request.getTitle()); + bigText.append("\u2022 ").append(request.getTitle()); } } else if (request.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) { if (request.getTitle() != null) { if (i > 0) { bigText.append("\n"); } - bigText.append("\u2022 " + request.getTitle() - + " (" + request.getProgressPercent() - + "%)"); + bigText.append("\u2022 ").append(request.getTitle()) + .append(" (").append(request.getProgressPercent()) + .append("%)"); } } @@ -489,16 +467,13 @@ public class DownloadService extends Service { * DownloadService list. */ private void removeDownload(final Downloader d) { - handler.post(new Runnable() { - @Override - public void run() { - Log.d(TAG, "Removing downloader: " - + d.getDownloadRequest().getSource()); - boolean rc = downloads.remove(d); - Log.d(TAG, "Result of downloads.remove: " + rc); - DownloadRequester.getInstance().removeDownload(d.getDownloadRequest()); - postDownloaders(); - } + handler.post(() -> { + Log.d(TAG, "Removing downloader: " + + d.getDownloadRequest().getSource()); + boolean rc = downloads.remove(d); + Log.d(TAG, "Result of downloads.remove: " + rc); + DownloadRequester.getInstance().removeDownload(d.getDownloadRequest()); + postDownloaders(); }); } @@ -574,12 +549,7 @@ public class DownloadService extends Service { * used from a thread other than the main thread. */ void queryDownloadsAsync() { - handler.post(new Runnable() { - public void run() { - queryDownloads(); - ; - } - }); + handler.post(DownloadService.this::queryDownloads); } /** @@ -598,27 +568,24 @@ public class DownloadService extends Service { } private void postAuthenticationNotification(final DownloadRequest downloadRequest) { - handler.post(new Runnable() { - @Override - public void run() { - final String resourceTitle = (downloadRequest.getTitle() != null) - ? downloadRequest.getTitle() : downloadRequest.getSource(); - - NotificationCompat.Builder builder = new NotificationCompat.Builder(DownloadService.this); - builder.setTicker(getText(R.string.authentication_notification_title)) - .setContentTitle(getText(R.string.authentication_notification_title)) - .setContentText(getText(R.string.authentication_notification_msg)) - .setStyle(new NotificationCompat.BigTextStyle().bigText(getText(R.string.authentication_notification_msg) - + ": " + resourceTitle)) - .setSmallIcon(R.drawable.ic_stat_authentication) - .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_stat_authentication)) - .setAutoCancel(true) - .setContentIntent(ClientConfig.downloadServiceCallbacks.getAuthentificationNotificationContentIntent(DownloadService.this, downloadRequest)) - .setVisibility(Notification.VISIBILITY_PUBLIC); - Notification n = builder.build(); - NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - nm.notify(downloadRequest.getSource().hashCode(), n); - } + handler.post(() -> { + final String resourceTitle = (downloadRequest.getTitle() != null) + ? downloadRequest.getTitle() : downloadRequest.getSource(); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(DownloadService.this); + builder.setTicker(getText(R.string.authentication_notification_title)) + .setContentTitle(getText(R.string.authentication_notification_title)) + .setContentText(getText(R.string.authentication_notification_msg)) + .setStyle(new NotificationCompat.BigTextStyle().bigText(getText(R.string.authentication_notification_msg) + + ": " + resourceTitle)) + .setSmallIcon(R.drawable.ic_stat_authentication) + .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_stat_authentication)) + .setAutoCancel(true) + .setContentIntent(ClientConfig.downloadServiceCallbacks.getAuthentificationNotificationContentIntent(DownloadService.this, downloadRequest)) + .setVisibility(Notification.VISIBILITY_PUBLIC); + Notification n = builder.build(); + NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(downloadRequest.getSource().hashCode(), n); }); } @@ -651,8 +618,8 @@ public class DownloadService extends Service { class FeedSyncThread extends Thread { private static final String TAG = "FeedSyncThread"; - private BlockingQueue<DownloadRequest> completedRequests = new LinkedBlockingDeque<DownloadRequest>(); - private CompletionService<Pair<DownloadRequest, FeedHandlerResult>> parserService = new ExecutorCompletionService<Pair<DownloadRequest, FeedHandlerResult>>(Executors.newSingleThreadExecutor()); + private BlockingQueue<DownloadRequest> completedRequests = new LinkedBlockingDeque<>(); + private CompletionService<Pair<DownloadRequest, FeedHandlerResult>> parserService = new ExecutorCompletionService<>(Executors.newSingleThreadExecutor()); private ExecutorService dbService = Executors.newSingleThreadExecutor(); private Future<?> dbUpdateFuture; private volatile boolean isActive = true; @@ -668,7 +635,7 @@ public class DownloadService extends Service { * @return Collected feeds or null if the method has been interrupted during the first waiting period. */ private List<Pair<DownloadRequest, FeedHandlerResult>> collectCompletedRequests() { - List<Pair<DownloadRequest, FeedHandlerResult>> results = new LinkedList<Pair<DownloadRequest, FeedHandlerResult>>(); + List<Pair<DownloadRequest, FeedHandlerResult>> results = new LinkedList<>(); DownloadRequester requester = DownloadRequester.getInstance(); int tasks = 0; @@ -712,11 +679,9 @@ public class DownloadService extends Service { if (result != null) { results.add(result); } - } catch (InterruptedException e) { + } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); - } catch (ExecutionException e) { - e.printStackTrace(); } } @@ -751,41 +716,36 @@ public class DownloadService extends Service { if (dbUpdateFuture != null) { try { dbUpdateFuture.get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { + } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } - dbUpdateFuture = dbService.submit(new Runnable() { - @Override - public void run() { - Feed[] savedFeeds = DBTasks.updateFeed(DownloadService.this, getFeeds(results)); - - for (int i = 0; i < savedFeeds.length; i++) { - Feed savedFeed = savedFeeds[i]; - - // If loadAllPages=true, check if another page is available and queue it for download - final boolean loadAllPages = results.get(i).first.getArguments().getBoolean(DownloadRequester.REQUEST_ARG_LOAD_ALL_PAGES); - final Feed feed = results.get(i).second.feed; - if (loadAllPages && feed.getNextPageLink() != null) { - try { - feed.setId(savedFeed.getId()); - DBTasks.loadNextPageOfFeed(DownloadService.this, savedFeed, true); - } catch (DownloadRequestException e) { - Log.e(TAG, "Error trying to load next page", e); - } + dbUpdateFuture = dbService.submit(() -> { + Feed[] savedFeeds = DBTasks.updateFeed(DownloadService.this, getFeeds(results)); + + for (int i = 0; i < savedFeeds.length; i++) { + Feed savedFeed = savedFeeds[i]; + + // If loadAllPages=true, check if another page is available and queue it for download + final boolean loadAllPages = results.get(i).first.getArguments().getBoolean(DownloadRequester.REQUEST_ARG_LOAD_ALL_PAGES); + final Feed feed = results.get(i).second.feed; + if (loadAllPages && feed.getNextPageLink() != null) { + try { + feed.setId(savedFeed.getId()); + DBTasks.loadNextPageOfFeed(DownloadService.this, savedFeed, true); + } catch (DownloadRequestException e) { + Log.e(TAG, "Error trying to load next page", e); } - - ClientConfig.downloadServiceCallbacks.onFeedParsed(DownloadService.this, - savedFeed); - - numberOfDownloads.decrementAndGet(); } - queryDownloadsAsync(); + ClientConfig.downloadServiceCallbacks.onFeedParsed(DownloadService.this, + savedFeed); + + numberOfDownloads.decrementAndGet(); } + + queryDownloadsAsync(); }); } @@ -847,21 +807,11 @@ public class DownloadService extends Service { try { result = feedHandler.parseFeed(feed); Log.d(TAG, feed.getTitle() + " parsed"); - if (checkFeedData(feed) == false) { + if (!checkFeedData(feed)) { throw new InvalidFeedException(); } - } catch (SAXException e) { - successful = false; - e.printStackTrace(); - reason = DownloadError.ERROR_PARSER_EXCEPTION; - reasonDetailed = e.getMessage(); - } catch (IOException e) { - successful = false; - e.printStackTrace(); - reason = DownloadError.ERROR_PARSER_EXCEPTION; - reasonDetailed = e.getMessage(); - } catch (ParserConfigurationException e) { + } catch (SAXException | IOException | ParserConfigurationException e) { successful = false; e.printStackTrace(); reason = DownloadError.ERROR_PARSER_EXCEPTION; @@ -884,7 +834,7 @@ public class DownloadService extends Service { if (successful) { // we create a 'successful' download log if the feed's last refresh failed List<DownloadStatus> log = DBReader.getFeedDownloadLog(feed); - if(log.size() > 0 && log.get(0).isSuccessful() == false) { + if(log.size() > 0 && !log.get(0).isSuccessful()) { saveDownloadStatus(new DownloadStatus(feed, feed.getHumanReadableIdentifier(), DownloadError.SUCCESS, successful, reasonDetailed)); @@ -1017,9 +967,7 @@ public class DownloadService extends Service { media.setFile_url(request.getDestination()); try { DBWriter.setFeedMedia(media).get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { + } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } @@ -1087,10 +1035,7 @@ public class DownloadService extends Service { if (item != null && !DBTasks.isInQueue(DownloadService.this, item.getId())) { DBWriter.addQueueItem(DownloadService.this, item).get(); } - } catch (ExecutionException e) { - e.printStackTrace(); - status = new DownloadStatus(media, media.getEpisodeTitle(), DownloadError.ERROR_DB_ACCESS_ERROR, false, e.getMessage()); - } catch (InterruptedException e) { + } catch (ExecutionException | InterruptedException e) { e.printStackTrace(); status = new DownloadStatus(media, media.getEpisodeTitle(), DownloadError.ERROR_DB_ACCESS_ERROR, false, e.getMessage()); } @@ -1134,14 +1079,11 @@ public class DownloadService extends Service { private class NotificationUpdater implements Runnable { public void run() { - handler.post(new Runnable() { - @Override - public void run() { - Notification n = updateNotifications(); - if (n != null) { - NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - nm.notify(NOTIFICATION_ID, n); - } + handler.post(() -> { + Notification n = updateNotifications(); + if (n != null) { + NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(NOTIFICATION_ID, n); } }); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloaderCallback.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloaderCallback.java index 2d9347b0a..b0829f084 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloaderCallback.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloaderCallback.java @@ -6,5 +6,5 @@ package de.danoeh.antennapod.core.service.download; */ public interface DownloaderCallback { - public void onDownloadCompleted(Downloader downloader); + void onDownloadCompleted(Downloader downloader); } 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 2b26f58c0..f79cf9685 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 @@ -21,7 +21,7 @@ import java.net.HttpURLConnection; import java.net.SocketTimeoutException; import java.net.URI; import java.net.UnknownHostException; -import java.util.Arrays; +import java.util.Collections; import java.util.Date; import de.danoeh.antennapod.core.ClientConfig; @@ -84,9 +84,8 @@ public class HttpDownloader extends Downloader { httpReq.addHeader("If-Modified-Since", lastModified); } } else { - String eTag = lastModified; - Log.d(TAG, "addHeader(\"If-None-Match\", \"" + eTag + "\")"); - httpReq.addHeader("If-None-Match", eTag); + Log.d(TAG, "addHeader(\"If-None-Match\", \"" + lastModified + "\")"); + httpReq.addHeader("If-None-Match", lastModified); } } @@ -111,13 +110,13 @@ public class HttpDownloader extends Downloader { Log.d(TAG, "Adding range header: " + request.getSoFar()); } - Response response = null; + Response response; try { response = httpClient.newCall(httpReq.build()).execute(); } catch(IOException e) { Log.e(TAG, e.toString()); if(e.getMessage().contains("PROTOCOL_ERROR")) { - httpClient.setProtocols(Arrays.asList(Protocol.HTTP_1_1)); + httpClient.setProtocols(Collections.singletonList(Protocol.HTTP_1_1)); response = httpClient.newCall(httpReq.build()).execute(); } else { 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 e886932f2..6eb1f4118 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 @@ -8,7 +8,7 @@ public class ProxyConfig { public final Proxy.Type type; @Nullable public final String host; - @Nullable public final int port; + public final int port; @Nullable public final String username; @Nullable public final String password; 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 2be075a92..9ca05d1f7 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 @@ -835,7 +835,7 @@ public class PlaybackService extends Service { if (!Thread.currentThread().isInterrupted() && started && info.playable != null) { String contentText = info.playable.getEpisodeTitle(); String contentTitle = info.playable.getFeedTitle(); - Notification notification = null; + Notification notification; // Builder is v7, even if some not overwritten methods return its parent's v4 interface NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder( 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 d3a5f576a..3ab26eb22 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 @@ -99,7 +99,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre this.audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); this.playerLock = new ReentrantLock(); this.startWhenPrepared = new AtomicBoolean(false); - executor = new ThreadPoolExecutor(1, 1, 5, TimeUnit.MINUTES, new LinkedBlockingDeque<Runnable>(), + executor = new ThreadPoolExecutor(1, 1, 5, TimeUnit.MINUTES, new LinkedBlockingDeque<>(), new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { @@ -175,18 +175,15 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre */ public void playMediaObject(@NonNull final Playable playable, final boolean stream, final boolean startWhenPrepared, final boolean prepareImmediately) { Log.d(TAG, "playMediaObject(...)"); - executor.submit(new Runnable() { - @Override - public void run() { - playerLock.lock(); - try { - playMediaObject(playable, false, stream, startWhenPrepared, prepareImmediately); - } catch (RuntimeException e) { - e.printStackTrace(); - throw e; - } finally { - playerLock.unlock(); - } + executor.submit(() -> { + playerLock.lock(); + try { + playMediaObject(playable, false, stream, startWhenPrepared, prepareImmediately); + } catch (RuntimeException e) { + e.printStackTrace(); + throw e; + } finally { + playerLock.unlock(); } }); } @@ -258,24 +255,13 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre } setPlayerStatus(PlayerStatus.INITIALIZED, media); - if (mediaType == MediaType.VIDEO) { - VideoPlayer vp = (VideoPlayer) mediaPlayer; - // vp.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT); - } - if (prepareImmediately) { setPlayerStatus(PlayerStatus.PREPARING, media); mediaPlayer.prepare(); onPrepared(startWhenPrepared); } - } catch (Playable.PlayableException e) { - e.printStackTrace(); - setPlayerStatus(PlayerStatus.ERROR, null); - } catch (IOException e) { - e.printStackTrace(); - setPlayerStatus(PlayerStatus.ERROR, null); - } catch (IllegalStateException e) { + } catch (Playable.PlayableException | IOException | IllegalStateException e) { e.printStackTrace(); setPlayerStatus(PlayerStatus.ERROR, null); } @@ -379,58 +365,52 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre * file is being streamed */ public void pause(final boolean abandonFocus, final boolean reinit) { - executor.submit(new Runnable() { - @Override - public void run() { - playerLock.lock(); - releaseWifiLockIfNecessary(); - if (playerStatus == PlayerStatus.PLAYING) { - Log.d(TAG, "Pausing playback."); - mediaPlayer.pause(); - setPlayerStatus(PlayerStatus.PAUSED, media); - - if (abandonFocus) { - audioManager.abandonAudioFocus(audioFocusChangeListener); - pausedBecauseOfTransientAudiofocusLoss = false; - } - if (stream && reinit) { - reinit(); - } - } else { - Log.d(TAG, "Ignoring call to pause: Player is in " + playerStatus + " state"); + executor.submit(() -> { + playerLock.lock(); + releaseWifiLockIfNecessary(); + if (playerStatus == PlayerStatus.PLAYING) { + Log.d(TAG, "Pausing playback."); + mediaPlayer.pause(); + setPlayerStatus(PlayerStatus.PAUSED, media); + + if (abandonFocus) { + audioManager.abandonAudioFocus(audioFocusChangeListener); + pausedBecauseOfTransientAudiofocusLoss = false; } - - playerLock.unlock(); + if (stream && reinit) { + reinit(); + } + } else { + Log.d(TAG, "Ignoring call to pause: Player is in " + playerStatus + " state"); } + + playerLock.unlock(); }); } /** - * Prepared media player for playback if the service is in the INITALIZED + * Prepares media player for playback if the service is in the INITALIZED * state. * <p/> * This method is executed on an internal executor service. */ public void prepare() { - executor.submit(new Runnable() { - @Override - public void run() { - playerLock.lock(); - - if (playerStatus == PlayerStatus.INITIALIZED) { - Log.d(TAG, "Preparing media player"); - setPlayerStatus(PlayerStatus.PREPARING, media); - try { - mediaPlayer.prepare(); - onPrepared(startWhenPrepared.get()); - } catch (IOException e) { - e.printStackTrace(); - setPlayerStatus(PlayerStatus.ERROR, null); - } - } - playerLock.unlock(); + executor.submit(() -> { + playerLock.lock(); + if (playerStatus == PlayerStatus.INITIALIZED) { + Log.d(TAG, "Preparing media player"); + setPlayerStatus(PlayerStatus.PREPARING, media); + try { + mediaPlayer.prepare(); + onPrepared(startWhenPrepared.get()); + } catch (IOException e) { + e.printStackTrace(); + setPlayerStatus(PlayerStatus.ERROR, null); + } } + playerLock.unlock(); + }); } @@ -449,7 +429,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre if (mediaType == MediaType.VIDEO) { VideoPlayer vp = (VideoPlayer) mediaPlayer; - videoSize = new Pair<Integer, Integer>(vp.getVideoWidth(), vp.getVideoHeight()); + videoSize = new Pair<>(vp.getVideoWidth(), vp.getVideoHeight()); } if (media.getPosition() > 0) { @@ -475,20 +455,17 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre * This method is executed on an internal executor service. */ public void reinit() { - executor.submit(new Runnable() { - @Override - public void run() { - playerLock.lock(); - releaseWifiLockIfNecessary(); - if (media != null) { - playMediaObject(media, true, stream, startWhenPrepared.get(), false); - } else if (mediaPlayer != null) { - mediaPlayer.reset(); - } else { - Log.d(TAG, "Call to reinit was ignored: media and mediaPlayer were null"); - } - playerLock.unlock(); + executor.submit(() -> { + playerLock.lock(); + releaseWifiLockIfNecessary(); + if (media != null) { + playMediaObject(media, true, stream, startWhenPrepared.get(), false); + } else if (mediaPlayer != null) { + mediaPlayer.reset(); + } else { + Log.d(TAG, "Call to reinit was ignored: media and mediaPlayer were null"); } + playerLock.unlock(); }); } @@ -542,12 +519,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre * This method is executed on an internal executor service. */ public void seekTo(final int t) { - executor.submit(new Runnable() { - @Override - public void run() { - seekToSync(t); - } - }); + executor.submit(() -> seekToSync(t)); } /** @@ -556,19 +528,16 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre * @param d offset from current position (positive or negative) */ public void seekDelta(final int d) { - executor.submit(new Runnable() { - @Override - public void run() { - playerLock.lock(); - int currentPosition = getPosition(); - if (currentPosition != INVALID_TIME) { - seekToSync(currentPosition + d); - } else { - Log.e(TAG, "getPosition() returned INVALID_TIME in seekDelta"); - } - - playerLock.unlock(); + executor.submit(() -> { + playerLock.lock(); + int currentPosition = getPosition(); + if (currentPosition != INVALID_TIME) { + seekToSync(currentPosition + d); + } else { + Log.e(TAG, "getPosition() returned INVALID_TIME in seekDelta"); } + + playerLock.unlock(); }); } @@ -618,10 +587,8 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre || playerStatus == PlayerStatus.PREPARED || playerStatus == PlayerStatus.SEEKING) { retVal = mediaPlayer.getCurrentPosition(); - if(retVal <= 0 && media != null && media.getPosition() > 0) { - retVal = media.getPosition(); - } - } else if (media != null && media.getPosition() > 0) { + } + if (retVal <= 0 && media != null && media.getPosition() >= 0) { retVal = media.getPosition(); } @@ -657,7 +624,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre playerLock.lock(); if (media != null && media.getMediaType() == MediaType.AUDIO) { if (mediaPlayer.canSetSpeed()) { - mediaPlayer.setPlaybackSpeed((float) speed); + mediaPlayer.setPlaybackSpeed(speed); Log.d(TAG, "Playback speed was set to " + speed); callback.playbackSpeedChanged(speed); } @@ -670,12 +637,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre * This method is executed on an internal executor service. */ public void setSpeed(final float speed) { - executor.submit(new Runnable() { - @Override - public void run() { - setSpeedSync(speed); - } - }); + executor.submit(() -> setSpeedSync(speed)); } /** @@ -761,28 +723,22 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre } public void setVideoSurface(final SurfaceHolder surface) { - executor.submit(new Runnable() { - @Override - public void run() { - playerLock.lock(); - if (mediaPlayer != null) { - mediaPlayer.setDisplay(surface); - } - playerLock.unlock(); + executor.submit(() -> { + playerLock.lock(); + if (mediaPlayer != null) { + mediaPlayer.setDisplay(surface); } + playerLock.unlock(); }); } public void resetVideoSurface() { - executor.submit(new Runnable() { - @Override - public void run() { - playerLock.lock(); - Log.d(TAG, "Resetting video surface"); - mediaPlayer.setDisplay(null); - reinit(); - playerLock.unlock(); - } + executor.submit(() -> { + playerLock.lock(); + Log.d(TAG, "Resetting video surface"); + mediaPlayer.setDisplay(null); + reinit(); + playerLock.unlock(); }); } @@ -803,7 +759,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre res = null; } else { VideoPlayer vp = (VideoPlayer) mediaPlayer; - videoSize = new Pair<Integer, Integer>(vp.getVideoWidth(), vp.getVideoHeight()); + videoSize = new Pair<>(vp.getVideoWidth(), vp.getVideoHeight()); res = videoSize; } playerLock.unlock(); @@ -1009,20 +965,17 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre * abandoning audio focus have to be done with other methods. */ public void stop() { - executor.submit(new Runnable() { - @Override - public void run() { - playerLock.lock(); - releaseWifiLockIfNecessary(); - - if (playerStatus == PlayerStatus.INDETERMINATE) { - setPlayerStatus(PlayerStatus.STOPPED, null); - } else { - Log.d(TAG, "Ignored call to stop: Current player state is: " + playerStatus); - } - playerLock.unlock(); + executor.submit(() -> { + playerLock.lock(); + releaseWifiLockIfNecessary(); + if (playerStatus == PlayerStatus.INDETERMINATE) { + setPlayerStatus(PlayerStatus.STOPPED, null); + } else { + Log.d(TAG, "Ignored call to stop: Current player state is: " + playerStatus); } + playerLock.unlock(); + }); } @@ -1097,100 +1050,59 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre return mp; } - private final org.antennapod.audio.MediaPlayer.OnCompletionListener audioCompletionListener = new org.antennapod.audio.MediaPlayer.OnCompletionListener() { - @Override - public void onCompletion(org.antennapod.audio.MediaPlayer mp) { - genericOnCompletion(); - } - }; + private final org.antennapod.audio.MediaPlayer.OnCompletionListener audioCompletionListener = + mp -> genericOnCompletion(); - private final android.media.MediaPlayer.OnCompletionListener videoCompletionListener = new android.media.MediaPlayer.OnCompletionListener() { - @Override - public void onCompletion(android.media.MediaPlayer mp) { - genericOnCompletion(); - } - }; + private final android.media.MediaPlayer.OnCompletionListener videoCompletionListener = + mp -> genericOnCompletion(); private void genericOnCompletion() { endPlayback(false); } - private final org.antennapod.audio.MediaPlayer.OnBufferingUpdateListener audioBufferingUpdateListener = new org.antennapod.audio.MediaPlayer.OnBufferingUpdateListener() { - @Override - public void onBufferingUpdate(org.antennapod.audio.MediaPlayer mp, - int percent) { - genericOnBufferingUpdate(percent); - } - }; + private final org.antennapod.audio.MediaPlayer.OnBufferingUpdateListener audioBufferingUpdateListener = + (mp, percent) -> genericOnBufferingUpdate(percent); - private final android.media.MediaPlayer.OnBufferingUpdateListener videoBufferingUpdateListener = new android.media.MediaPlayer.OnBufferingUpdateListener() { - @Override - public void onBufferingUpdate(android.media.MediaPlayer mp, int percent) { - genericOnBufferingUpdate(percent); - } - }; + private final android.media.MediaPlayer.OnBufferingUpdateListener videoBufferingUpdateListener = + (mp, percent) -> genericOnBufferingUpdate(percent); private void genericOnBufferingUpdate(int percent) { callback.onBufferingUpdate(percent); } - private final org.antennapod.audio.MediaPlayer.OnInfoListener audioInfoListener = new org.antennapod.audio.MediaPlayer.OnInfoListener() { - @Override - public boolean onInfo(org.antennapod.audio.MediaPlayer mp, int what, - int extra) { - return genericInfoListener(what); - } - }; + private final org.antennapod.audio.MediaPlayer.OnInfoListener audioInfoListener = + (mp, what, extra) -> genericInfoListener(what); - private final android.media.MediaPlayer.OnInfoListener videoInfoListener = new android.media.MediaPlayer.OnInfoListener() { - @Override - public boolean onInfo(android.media.MediaPlayer mp, int what, int extra) { - return genericInfoListener(what); - } - }; + private final android.media.MediaPlayer.OnInfoListener videoInfoListener = + (mp, what, extra) -> genericInfoListener(what); private boolean genericInfoListener(int what) { return callback.onMediaPlayerInfo(what); } - private final org.antennapod.audio.MediaPlayer.OnErrorListener audioErrorListener = new org.antennapod.audio.MediaPlayer.OnErrorListener() { - @Override - public boolean onError(org.antennapod.audio.MediaPlayer mp, int what, int extra) { - if(mp.canFallback()) { - mp.fallback(); - return true; - } else { - return genericOnError(mp, what, extra); - } - } - }; + private final org.antennapod.audio.MediaPlayer.OnErrorListener audioErrorListener = + (mp, what, extra) -> { + if(mp.canFallback()) { + mp.fallback(); + return true; + } else { + return genericOnError(mp, what, extra); + } + }; - private final android.media.MediaPlayer.OnErrorListener videoErrorListener = new android.media.MediaPlayer.OnErrorListener() { - @Override - public boolean onError(android.media.MediaPlayer mp, int what, int extra) { - return genericOnError(mp, what, extra); - } - }; + private final android.media.MediaPlayer.OnErrorListener videoErrorListener = this::genericOnError; private boolean genericOnError(Object inObj, int what, int extra) { return callback.onMediaPlayerError(inObj, what, extra); } - private final org.antennapod.audio.MediaPlayer.OnSeekCompleteListener audioSeekCompleteListener = new org.antennapod.audio.MediaPlayer.OnSeekCompleteListener() { - @Override - public void onSeekComplete(org.antennapod.audio.MediaPlayer mp) { - genericSeekCompleteListener(); - } - }; + private final org.antennapod.audio.MediaPlayer.OnSeekCompleteListener audioSeekCompleteListener = + mp -> genericSeekCompleteListener(); - private final android.media.MediaPlayer.OnSeekCompleteListener videoSeekCompleteListener = new android.media.MediaPlayer.OnSeekCompleteListener() { - @Override - public void onSeekComplete(android.media.MediaPlayer mp) { - genericSeekCompleteListener(); - } - }; + private final android.media.MediaPlayer.OnSeekCompleteListener videoSeekCompleteListener = + mp -> genericSeekCompleteListener(); - private final void genericSeekCompleteListener() { + private void genericSeekCompleteListener() { Thread t = new Thread(() -> { Log.d(TAG, "genericSeekCompleteListener"); if(seekLatch != null) { @@ -1210,6 +1122,71 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre private static final String TAG = "MediaSessionCompat"; @Override + public void onPlay() { + Log.d(TAG, "onPlay()"); + if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) { + resume(); + } else if (playerStatus == PlayerStatus.INITIALIZED) { + setStartWhenPrepared(true); + prepare(); + } + } + + @Override + public void onPause() { + Log.d(TAG, "onPause()"); + if (playerStatus == PlayerStatus.PLAYING) { + pause(false, true); + } + if (UserPreferences.isPersistNotify()) { + pause(false, true); + } else { + pause(true, true); + } + } + + @Override + public void onStop() { + Log.d(TAG, "onStop()"); + stop(); + } + + @Override + public void onSkipToPrevious() { + Log.d(TAG, "onSkipToPrevious()"); + seekDelta(-UserPreferences.getRewindSecs() * 1000); + } + + @Override + public void onRewind() { + Log.d(TAG, "onRewind()"); + seekDelta(-UserPreferences.getRewindSecs() * 1000); + } + + @Override + public void onFastForward() { + Log.d(TAG, "onFastForward()"); + seekDelta(UserPreferences.getFastFowardSecs() * 1000); + } + + @Override + public void onSkipToNext() { + Log.d(TAG, "onSkipToNext()"); + if(UserPreferences.shouldHardwareButtonSkip()) { + endPlayback(true); + } else { + seekDelta(UserPreferences.getFastFowardSecs() * 1000); + } + } + + + @Override + public void onSeekTo(long pos) { + Log.d(TAG, "onSeekTo()"); + seekTo((int) pos); + } + + @Override public boolean onMediaButtonEvent(final Intent mediaButton) { Log.d(TAG, "onMediaButtonEvent(" + mediaButton + ")"); if (mediaButton != null) { @@ -1245,42 +1222,27 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre return true; } case KeyEvent.KEYCODE_MEDIA_PLAY: { - Log.d(TAG, "Received Play event from RemoteControlClient"); - if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) { - resume(); - } else if (playerStatus == PlayerStatus.INITIALIZED) { - setStartWhenPrepared(true); - prepare(); - } + sessionCallback.onPlay(); return true; } case KeyEvent.KEYCODE_MEDIA_PAUSE: { - Log.d(TAG, "Received Pause event from RemoteControlClient"); - if (playerStatus == PlayerStatus.PLAYING) { - pause(false, true); - } - if (UserPreferences.isPersistNotify()) { - pause(false, true); - } else { - pause(true, true); - } + sessionCallback.onPause(); return true; } case KeyEvent.KEYCODE_MEDIA_STOP: { - Log.d(TAG, "Received Stop event from RemoteControlClient"); - stop(); + sessionCallback.onStop(); return true; } case KeyEvent.KEYCODE_MEDIA_PREVIOUS: { - seekDelta(-UserPreferences.getRewindSecs() * 1000); + sessionCallback.onSkipToPrevious(); return true; } case KeyEvent.KEYCODE_MEDIA_REWIND: { - seekDelta(-UserPreferences.getRewindSecs() * 1000); + sessionCallback.onRewind(); return true; } case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { - seekDelta(UserPreferences.getFastFowardSecs() * 1000); + sessionCallback.onFastForward(); return true; } case KeyEvent.KEYCODE_MEDIA_NEXT: { 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 680fb8777..8a0964d36 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 @@ -6,12 +6,10 @@ import android.support.annotation.NonNull; import android.util.Log; import java.util.List; -import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.event.QueueEvent; @@ -65,13 +63,10 @@ public class PlaybackServiceTaskManager { @NonNull PSTMCallback callback) { this.context = context; this.callback = callback; - schedExecutor = new ScheduledThreadPoolExecutor(SCHED_EX_POOL_SIZE, new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setPriority(Thread.MIN_PRIORITY); - return t; - } + schedExecutor = new ScheduledThreadPoolExecutor(SCHED_EX_POOL_SIZE, r -> { + Thread t = new Thread(r); + t.setPriority(Thread.MIN_PRIORITY); + return t; }); loadQueue(); EventBus.getDefault().register(this); @@ -95,12 +90,7 @@ public class PlaybackServiceTaskManager { private synchronized void loadQueue() { if (!isQueueLoaderActive()) { - queueFuture = schedExecutor.submit(new Callable<List<FeedItem>>() { - @Override - public List<FeedItem> call() throws Exception { - return DBReader.getQueue(); - } - }); + queueFuture = schedExecutor.submit(DBReader::getQueue); } } @@ -112,9 +102,7 @@ public class PlaybackServiceTaskManager { if (queueFuture.isDone()) { try { return queueFuture.get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { + } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } @@ -137,12 +125,7 @@ public class PlaybackServiceTaskManager { */ public synchronized void startPositionSaver() { if (!isPositionSaverActive()) { - Runnable positionSaver = new Runnable() { - @Override - public void run() { - callback.positionSaverTick(); - } - }; + Runnable positionSaver = callback::positionSaverTick; positionSaverFuture = schedExecutor.scheduleWithFixedDelay(positionSaver, POSITION_SAVER_WAITING_INTERVAL, POSITION_SAVER_WAITING_INTERVAL, TimeUnit.MILLISECONDS); @@ -174,12 +157,7 @@ public class PlaybackServiceTaskManager { */ public synchronized void startWidgetUpdater() { if (!isWidgetUpdaterActive()) { - Runnable widgetUpdater = new Runnable() { - @Override - public void run() { - callback.onWidgetUpdaterTick(); - } - }; + Runnable widgetUpdater = callback::onWidgetUpdaterTick; widgetUpdaterFuture = schedExecutor.scheduleWithFixedDelay(widgetUpdater, WIDGET_UPDATER_NOTIFICATION_INTERVAL, WIDGET_UPDATER_NOTIFICATION_INTERVAL, TimeUnit.MILLISECONDS); @@ -279,18 +257,15 @@ public class PlaybackServiceTaskManager { cancelChapterLoader(); } - Runnable chapterLoader = new Runnable() { - @Override - public void run() { - Log.d(TAG, "Chapter loader started"); - if (media.getChapters() == null) { - media.loadChapterMarks(); - if (!Thread.currentThread().isInterrupted() && media.getChapters() != null) { - callback.onChapterLoaded(media); - } + Runnable chapterLoader = () -> { + Log.d(TAG, "Chapter loader started"); + if (media.getChapters() == null) { + media.loadChapterMarks(); + if (!Thread.currentThread().isInterrupted() && media.getChapters() != null) { + callback.onChapterLoaded(media); } - Log.d(TAG, "Chapter loader stopped"); } + Log.d(TAG, "Chapter loader stopped"); }; chapterLoaderFuture = schedExecutor.submit(chapterLoader); } 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 80703e22d..e94874453 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 @@ -13,8 +13,6 @@ import java.util.concurrent.ExecutionException; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.util.LongList; /** * Implementation of the EpisodeCleanupAlgorithm interface used by AntennaPod. diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java index 26dc027bf..aa97b321a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java @@ -33,73 +33,70 @@ public class APDownloadAlgorithm implements AutomaticDownloadAlgorithm { */ @Override public Runnable autoDownloadUndownloadedItems(final Context context) { - return new Runnable() { - @Override - public void run() { - - // true if we should auto download based on network status - boolean networkShouldAutoDl = NetworkUtils.autodownloadNetworkAvailable() - && UserPreferences.isEnableAutodownload(); - - // true if we should auto download based on power status - boolean powerShouldAutoDl = PowerUtils.deviceCharging(context) - || UserPreferences.isEnableAutodownloadOnBattery(); - - // we should only auto download if both network AND power are happy - if (networkShouldAutoDl && powerShouldAutoDl) { - - Log.d(TAG, "Performing auto-dl of undownloaded episodes"); - - List<FeedItem> candidates; - final List<FeedItem> queue = DBReader.getQueue(); - final List<FeedItem> newItems = DBReader.getNewItemsList(); - candidates = new ArrayList<FeedItem>(queue.size() + newItems.size()); - candidates.addAll(queue); - for(FeedItem newItem : newItems) { - FeedPreferences feedPrefs = newItem.getFeed().getPreferences(); - FeedFilter feedFilter = feedPrefs.getFilter(); - if(candidates.contains(newItem) == false && feedFilter.shouldAutoDownload(newItem)) { - candidates.add(newItem); - } - } - - // filter items that are not auto downloadable - Iterator<FeedItem> it = candidates.iterator(); - while(it.hasNext()) { - FeedItem item = it.next(); - if(item.isAutoDownloadable() == false) { - it.remove(); - } + return () -> { + + // true if we should auto download based on network status + boolean networkShouldAutoDl = NetworkUtils.autodownloadNetworkAvailable() + && UserPreferences.isEnableAutodownload(); + + // true if we should auto download based on power status + boolean powerShouldAutoDl = PowerUtils.deviceCharging(context) + || UserPreferences.isEnableAutodownloadOnBattery(); + + // we should only auto download if both network AND power are happy + if (networkShouldAutoDl && powerShouldAutoDl) { + + Log.d(TAG, "Performing auto-dl of undownloaded episodes"); + + List<FeedItem> candidates; + final List<FeedItem> queue = DBReader.getQueue(); + final List<FeedItem> newItems = DBReader.getNewItemsList(); + candidates = new ArrayList<>(queue.size() + newItems.size()); + candidates.addAll(queue); + for(FeedItem newItem : newItems) { + FeedPreferences feedPrefs = newItem.getFeed().getPreferences(); + FeedFilter feedFilter = feedPrefs.getFilter(); + if(!candidates.contains(newItem) && feedFilter.shouldAutoDownload(newItem)) { + candidates.add(newItem); } + } - int autoDownloadableEpisodes = candidates.size(); - int downloadedEpisodes = DBReader.getNumberOfDownloadedEpisodes(); - int deletedEpisodes = UserPreferences.getEpisodeCleanupAlgorithm() - .makeRoomForEpisodes(context, autoDownloadableEpisodes); - boolean cacheIsUnlimited = UserPreferences.getEpisodeCacheSize() == UserPreferences - .getEpisodeCacheSizeUnlimited(); - int episodeCacheSize = UserPreferences.getEpisodeCacheSize(); - - int episodeSpaceLeft; - if (cacheIsUnlimited || - episodeCacheSize >= downloadedEpisodes + autoDownloadableEpisodes) { - episodeSpaceLeft = autoDownloadableEpisodes; - } else { - episodeSpaceLeft = episodeCacheSize - (downloadedEpisodes - deletedEpisodes); + // filter items that are not auto downloadable + Iterator<FeedItem> it = candidates.iterator(); + while(it.hasNext()) { + FeedItem item = it.next(); + if(!item.isAutoDownloadable()) { + it.remove(); } + } - FeedItem[] itemsToDownload = candidates.subList(0, episodeSpaceLeft) - .toArray(new FeedItem[episodeSpaceLeft]); + int autoDownloadableEpisodes = candidates.size(); + int downloadedEpisodes = DBReader.getNumberOfDownloadedEpisodes(); + int deletedEpisodes = UserPreferences.getEpisodeCleanupAlgorithm() + .makeRoomForEpisodes(context, autoDownloadableEpisodes); + boolean cacheIsUnlimited = UserPreferences.getEpisodeCacheSize() == UserPreferences + .getEpisodeCacheSizeUnlimited(); + int episodeCacheSize = UserPreferences.getEpisodeCacheSize(); + + int episodeSpaceLeft; + if (cacheIsUnlimited || + episodeCacheSize >= downloadedEpisodes + autoDownloadableEpisodes) { + episodeSpaceLeft = autoDownloadableEpisodes; + } else { + episodeSpaceLeft = episodeCacheSize - (downloadedEpisodes - deletedEpisodes); + } - Log.d(TAG, "Enqueueing " + itemsToDownload.length + " items for download"); + FeedItem[] itemsToDownload = candidates.subList(0, episodeSpaceLeft) + .toArray(new FeedItem[episodeSpaceLeft]); - try { - DBTasks.downloadFeedItems(false, context, itemsToDownload); - } catch (DownloadRequestException e) { - e.printStackTrace(); - } + Log.d(TAG, "Enqueueing " + itemsToDownload.length + " items for download"); + try { + DBTasks.downloadFeedItems(false, context, itemsToDownload); + } catch (DownloadRequestException e) { + e.printStackTrace(); } + } }; } 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 baa9a986e..04b200699 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 @@ -5,15 +5,12 @@ import android.support.annotation.NonNull; import android.util.Log; import java.util.ArrayList; -import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.concurrent.ExecutionException; import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.util.LongList; /** * A cleanup algorithm that removes any item that isn't in the queue and isn't a favorite diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java index 72c68ddb6..dbb77e19c 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java @@ -14,5 +14,5 @@ public interface AutomaticDownloadAlgorithm { * @param context Used for accessing the DB. * @return A Runnable that will be submitted to an ExecutorService. */ - public Runnable autoDownloadUndownloadedItems(Context context); + Runnable autoDownloadUndownloadedItems(Context context); } 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 fd832a8cb..278a8c42b 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 @@ -591,17 +591,18 @@ public final class DBReader { FeedItem item = null; Cursor itemCursor = adapter.getFeedItemCursor(Long.toString(itemId)); - if (itemCursor.moveToFirst()) { - List<FeedItem> list = extractItemlistFromCursor(adapter, itemCursor); - if (list.size() > 0) { - item = list.get(0); - loadAdditionalFeedItemListData(list); - if (item.hasChapters()) { - loadChaptersOfFeedItem(adapter, item); - } - } + if (!itemCursor.moveToFirst()) { + return null; } + List<FeedItem> list = extractItemlistFromCursor(adapter, itemCursor); itemCursor.close(); + if (list.size() > 0) { + item = list.get(0); + loadAdditionalFeedItemListData(list); + if (item.hasChapters()) { + loadChaptersOfFeedItem(adapter, item); + } + } return item; } @@ -899,19 +900,24 @@ public final class DBReader { adapter.open(); Cursor mediaCursor = adapter.getSingleFeedMediaCursor(mediaId); - FeedMedia media = null; - if (mediaCursor.moveToFirst()) { - int indexFeedItem = mediaCursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM); - final long itemId = mediaCursor.getLong(indexFeedItem); - media = FeedMedia.fromCursor(mediaCursor); + if (!mediaCursor.moveToFirst()) { + mediaCursor.close(); + return null; + } + + int indexFeedItem = mediaCursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM); + long itemId = mediaCursor.getLong(indexFeedItem); + FeedMedia media = FeedMedia.fromCursor(mediaCursor); + mediaCursor.close(); + + if(media != null) { FeedItem item = getFeedItem(itemId); - if (media != null && item != null) { + if (item != null) { media.setItem(item); item.setMedia(media); } } - mediaCursor.close(); adapter.close(); return media; 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 ed593bb82..47e2d8a26 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 @@ -48,13 +48,10 @@ public final class DBTasks { private static ExecutorService autodownloadExec; static { - autodownloadExec = Executors.newSingleThreadExecutor(new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setPriority(Thread.MIN_PRIORITY); - return t; - } + autodownloadExec = Executors.newSingleThreadExecutor(r -> { + Thread t = new Thread(r); + t.setPriority(Thread.MIN_PRIORITY); + return t; }); } @@ -85,9 +82,7 @@ public final class DBTasks { if (feedID != 0) { try { DBWriter.deleteFeed(context, feedID).get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { + } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } else { @@ -114,7 +109,7 @@ public final class DBTasks { boolean showPlayer, boolean startWhenPrepared, boolean shouldStream) { try { if (!shouldStream) { - if (media.fileExists() == false) { + if (!media.fileExists()) { throw new MediaFileNotFoundException( "No episode was found at " + media.getFile_url(), media); @@ -518,8 +513,8 @@ public final class DBTasks { */ public static synchronized Feed[] updateFeed(final Context context, final Feed... newFeeds) { - List<Feed> newFeedsList = new ArrayList<Feed>(); - List<Feed> updatedFeedsList = new ArrayList<Feed>(); + List<Feed> newFeedsList = new ArrayList<>(); + List<Feed> updatedFeedsList = new ArrayList<>(); Feed[] resultFeeds = new Feed[newFeeds.length]; PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); @@ -611,9 +606,7 @@ public final class DBTasks { try { DBWriter.addNewFeed(context, newFeedsList.toArray(new Feed[newFeedsList.size()])).get(); DBWriter.setCompleteFeed(updatedFeedsList.toArray(new Feed[updatedFeedsList.size()])).get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { + } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } @@ -633,7 +626,7 @@ public final class DBTasks { */ public static FutureTask<List<FeedItem>> searchFeedItemTitle(final Context context, final long feedID, final String query) { - return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) { + return new FutureTask<>(new QueryTask<List<FeedItem>>(context) { @Override public void execute(PodDBAdapter adapter) { Cursor searchResult = adapter.searchItemTitles(feedID, @@ -657,7 +650,7 @@ public final class DBTasks { */ public static FutureTask<List<FeedItem>> searchFeedItemDescription(final Context context, final long feedID, final String query) { - return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) { + return new FutureTask<>(new QueryTask<List<FeedItem>>(context) { @Override public void execute(PodDBAdapter adapter) { Cursor searchResult = adapter.searchItemDescriptions(feedID, @@ -681,7 +674,7 @@ public final class DBTasks { */ public static FutureTask<List<FeedItem>> searchFeedItemContentEncoded(final Context context, final long feedID, final String query) { - return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) { + return new FutureTask<>(new QueryTask<List<FeedItem>>(context) { @Override public void execute(PodDBAdapter adapter) { Cursor searchResult = adapter.searchItemContentEncoded(feedID, @@ -704,7 +697,7 @@ public final class DBTasks { */ public static FutureTask<List<FeedItem>> searchFeedItemChapters(final Context context, final long feedID, final String query) { - return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) { + return new FutureTask<>(new QueryTask<List<FeedItem>>(context) { @Override public void execute(PodDBAdapter adapter) { Cursor searchResult = adapter.searchItemChapters(feedID, 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 e728abc3b..7dad9cb08 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 @@ -14,7 +14,6 @@ import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; @@ -132,7 +131,7 @@ public class DBWriter { } } Log.d(TAG, "Deleting File. Result: " + result); - EventBus.getDefault().post(FeedItemEvent.deletedMedia(Arrays.asList(media.getItem()))); + EventBus.getDefault().post(FeedItemEvent.deletedMedia(Collections.singletonList(media.getItem()))); EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); } }); @@ -372,7 +371,7 @@ public class DBWriter { if (queue != null) { boolean queueModified = false; LongList markAsUnplayedIds = new LongList(); - List<QueueEvent> events = new ArrayList<QueueEvent>(); + List<QueueEvent> events = new ArrayList<>(); for (int i = 0; i < itemIds.length; i++) { if (!itemListContains(queue, itemIds[i])) { final FeedItem item = DBReader.getFeedItem(itemIds[i]); @@ -545,9 +544,7 @@ public class DBWriter { */ public static Future<?> moveQueueItem(final int from, final int to, final boolean broadcastUpdate) { - return dbExec.submit(() -> { - moveQueueItemHelper(from, to, broadcastUpdate); - }); + return dbExec.submit(() -> moveQueueItemHelper(from, to, broadcastUpdate)); } /** 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 22c9538ca..04afc504b 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 @@ -51,7 +51,7 @@ public class DownloadRequester { private Map<String, DownloadRequest> downloads; private DownloadRequester() { - downloads = new ConcurrentHashMap<String, DownloadRequest>(); + downloads = new ConcurrentHashMap<>(); } public static synchronized DownloadRequester getInstance() { @@ -268,10 +268,7 @@ public class DownloadRequester { * Checks if feedfile is in the downloads list */ public synchronized boolean isDownloadingFile(FeedFile item) { - if (item.getDownload_url() != null) { - return downloads.containsKey(item.getDownload_url()); - } - return false; + return item.getDownload_url() != null && downloads.containsKey(item.getDownload_url()); } public synchronized DownloadRequest getDownload(String downloadUrl) { 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 3a63685ba..d7c9e9108 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,10 +1,6 @@ package de.danoeh.antennapod.core.storage; import android.content.Context; -import de.danoeh.antennapod.core.R; -import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.feed.SearchResult; -import de.danoeh.antennapod.core.util.comparator.SearchResultValueComparator; import java.util.ArrayList; import java.util.Collections; @@ -12,6 +8,11 @@ import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; +import de.danoeh.antennapod.core.R; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.SearchResult; +import de.danoeh.antennapod.core.util.comparator.SearchResultValueComparator; + /** * Performs search on Feeds and FeedItems */ @@ -30,7 +31,7 @@ public class FeedSearcher { context.getString(R.string.found_in_chapters_label), context.getString(R.string.found_in_title_label)}; - List<SearchResult> result = new ArrayList<SearchResult>(); + List<SearchResult> result = new ArrayList<>(); FutureTask<List<FeedItem>>[] tasks = new FutureTask[4]; (tasks[0] = DBTasks.searchFeedItemContentEncoded(context, selectedFeed, query)).run(); @@ -46,9 +47,7 @@ public class FeedSearcher { } } - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { + } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } Collections.sort(result, new SearchResultValueComparator()); 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 5b7f5f720..c8df0f572 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 @@ -10,12 +10,14 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; import android.media.MediaMetadataRetriever; +import android.os.Build; import android.text.TextUtils; import android.util.Log; import java.util.Arrays; import java.util.List; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import de.danoeh.antennapod.core.R; import de.danoeh.antennapod.core.event.ProgressEvent; @@ -303,7 +305,7 @@ public class PodDBAdapter { private static SQLiteDatabase db; private static Context context; private static PodDBHelper dbHelper; - private static int counter = 0; + private static AtomicInteger counter = new AtomicInteger(0); public static void init(Context context) { PodDBAdapter.context = context.getApplicationContext(); @@ -318,11 +320,15 @@ public class PodDBAdapter { private PodDBAdapter() {} - public PodDBAdapter open() { + public synchronized PodDBAdapter open() { + int adapters = counter.incrementAndGet(); + Log.v(TAG, "Opening DB #" + adapters); if (db == null || !db.isOpen() || db.isReadOnly()) { - Log.v(TAG, "Opening DB"); try { db = dbHelper.getWritableDatabase(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + db.enableWriteAheadLogging(); + } } catch (SQLException ex) { Log.e(TAG, Log.getStackTraceString(ex)); db = dbHelper.getReadableDatabase(); @@ -331,8 +337,13 @@ public class PodDBAdapter { return this; } - public void close() { - // do nothing + public synchronized void close() { + int adapters = counter.decrementAndGet(); + Log.v(TAG, "Closing DB #" + adapters); + if(adapters == 0) { + Log.v(TAG, "Closing DB, really"); + db.close(); + } } public static boolean deleteDatabase() { @@ -425,34 +436,46 @@ public class PodDBAdapter { */ public long setImage(FeedImage image) { boolean startedTransaction = false; - if(false == db.inTransaction()) { - db.beginTransaction(); - startedTransaction = true; - } - ContentValues values = new ContentValues(); - values.put(KEY_TITLE, image.getTitle()); - values.put(KEY_DOWNLOAD_URL, image.getDownload_url()); - values.put(KEY_DOWNLOADED, image.isDownloaded()); - values.put(KEY_FILE_URL, image.getFile_url()); - if (image.getId() == 0) { - image.setId(db.insert(TABLE_NAME_FEED_IMAGES, null, values)); - } else { - db.update(TABLE_NAME_FEED_IMAGES, values, KEY_ID + "=?", + try { + if (!db.inTransaction()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + db.beginTransactionNonExclusive(); + } else { + db.beginTransaction(); + } + startedTransaction = true; + } + + ContentValues values = new ContentValues(); + values.put(KEY_TITLE, image.getTitle()); + values.put(KEY_DOWNLOAD_URL, image.getDownload_url()); + values.put(KEY_DOWNLOADED, image.isDownloaded()); + values.put(KEY_FILE_URL, image.getFile_url()); + if (image.getId() == 0) { + image.setId(db.insert(TABLE_NAME_FEED_IMAGES, null, values)); + } else { + db.update(TABLE_NAME_FEED_IMAGES, values, KEY_ID + "=?", new String[]{String.valueOf(image.getId())}); - } + } - final FeedComponent owner = image.getOwner(); - if (owner != null && owner.getId() != 0) { - values.clear(); - values.put(KEY_IMAGE, image.getId()); - if (owner instanceof Feed) { - db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(image.getOwner().getId())}); + final FeedComponent owner = image.getOwner(); + if (owner != null && owner.getId() != 0) { + values.clear(); + values.put(KEY_IMAGE, image.getId()); + if (owner instanceof Feed) { + db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(image.getOwner().getId())}); + } + } + if (startedTransaction) { + db.setTransactionSuccessful(); + } + } catch (SQLException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } finally { + if (startedTransaction) { + db.endTransaction(); } - } - if(startedTransaction) { - db.setTransactionSuccessful(); - db.endTransaction(); } return image.getId(); } @@ -522,20 +545,29 @@ public class PodDBAdapter { * transaction */ public void setCompleteFeed(Feed... feeds) { - db.beginTransaction(); - for (Feed feed : feeds) { - setFeed(feed); - if (feed.getItems() != null) { - for (FeedItem item : feed.getItems()) { - setFeedItem(item, false); - } + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + db.beginTransactionNonExclusive(); + } else { + db.beginTransaction(); } - if (feed.getPreferences() != null) { - setFeedPreferences(feed.getPreferences()); + for (Feed feed : feeds) { + setFeed(feed); + if (feed.getItems() != null) { + for (FeedItem item : feed.getItems()) { + setFeedItem(item, false); + } + } + if (feed.getPreferences() != null) { + setFeedPreferences(feed.getPreferences()); + } } + db.setTransactionSuccessful(); + } catch (SQLException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } finally { + db.endTransaction(); } - db.setTransactionSuccessful(); - db.endTransaction(); } /** @@ -598,19 +630,38 @@ public class PodDBAdapter { } public void setFeedItemlist(List<FeedItem> items) { - db.beginTransaction(); - for (FeedItem item : items) { - setFeedItem(item, true); + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + db.beginTransactionNonExclusive(); + } else { + db.beginTransaction(); + } + for (FeedItem item : items) { + setFeedItem(item, true); + } + db.setTransactionSuccessful(); + } catch (SQLException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } finally { + db.endTransaction(); } - db.setTransactionSuccessful(); - db.endTransaction(); } public long setSingleFeedItem(FeedItem item) { - db.beginTransaction(); - long result = setFeedItem(item, true); - db.setTransactionSuccessful(); - db.endTransaction(); + long result = 0; + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + db.beginTransactionNonExclusive(); + } else { + db.beginTransaction(); + } + result = setFeedItem(item, true); + db.setTransactionSuccessful(); + } catch (SQLException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } finally { + db.endTransaction(); + } return result; } @@ -728,20 +779,29 @@ public class PodDBAdapter { public void setFeedItemRead(int played, long itemId, long mediaId, boolean resetMediaPosition) { - db.beginTransaction(); - ContentValues values = new ContentValues(); + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + db.beginTransactionNonExclusive(); + } else { + db.beginTransaction(); + } + ContentValues values = new ContentValues(); - values.put(KEY_READ, played); - db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?", new String[]{String.valueOf(itemId)}); + values.put(KEY_READ, played); + db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?", new String[]{String.valueOf(itemId)}); - if (resetMediaPosition) { - values.clear(); - values.put(KEY_POSITION, 0); - db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?", new String[]{String.valueOf(mediaId)}); - } + if (resetMediaPosition) { + values.clear(); + values.put(KEY_POSITION, 0); + db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?", new String[]{String.valueOf(mediaId)}); + } - db.setTransactionSuccessful(); - db.endTransaction(); + db.setTransactionSuccessful(); + } catch (SQLException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } finally { + db.endTransaction(); + } } /** @@ -750,15 +810,24 @@ public class PodDBAdapter { * @param itemIds items to change the value of */ public void setFeedItemRead(int read, long... itemIds) { - db.beginTransaction(); - ContentValues values = new ContentValues(); - for (long id : itemIds) { - values.clear(); - values.put(KEY_READ, read); - db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?", new String[]{String.valueOf(id)}); + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + db.beginTransactionNonExclusive(); + } else { + db.beginTransaction(); + } + ContentValues values = new ContentValues(); + for (long id : itemIds) { + values.clear(); + values.put(KEY_READ, read); + db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?", new String[]{String.valueOf(id)}); + } + db.setTransactionSuccessful(); + } catch (SQLException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } finally { + db.endTransaction(); } - db.setTransactionSuccessful(); - db.endTransaction(); } public void setChapters(FeedItem item) { @@ -822,17 +891,26 @@ public class PodDBAdapter { public void setFavorites(List<FeedItem> favorites) { ContentValues values = new ContentValues(); - db.beginTransaction(); - db.delete(TABLE_NAME_FAVORITES, null, null); - for (int i = 0; i < favorites.size(); i++) { - FeedItem item = favorites.get(i); - values.put(KEY_ID, i); - values.put(KEY_FEEDITEM, item.getId()); - values.put(KEY_FEED, item.getFeed().getId()); - db.insertWithOnConflict(TABLE_NAME_FAVORITES, null, values, SQLiteDatabase.CONFLICT_REPLACE); + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + db.beginTransactionNonExclusive(); + } else { + db.beginTransaction(); + } + db.delete(TABLE_NAME_FAVORITES, null, null); + for (int i = 0; i < favorites.size(); i++) { + FeedItem item = favorites.get(i); + values.put(KEY_ID, i); + values.put(KEY_FEEDITEM, item.getId()); + values.put(KEY_FEED, item.getFeed().getId()); + db.insertWithOnConflict(TABLE_NAME_FAVORITES, null, values, SQLiteDatabase.CONFLICT_REPLACE); + } + db.setTransactionSuccessful(); + } catch (SQLException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } finally { + db.endTransaction(); } - db.setTransactionSuccessful(); - db.endTransaction(); } /** @@ -880,17 +958,26 @@ public class PodDBAdapter { public void setQueue(List<FeedItem> queue) { ContentValues values = new ContentValues(); - db.beginTransaction(); - db.delete(TABLE_NAME_QUEUE, null, null); - for (int i = 0; i < queue.size(); i++) { - FeedItem item = queue.get(i); - values.put(KEY_ID, i); - values.put(KEY_FEEDITEM, item.getId()); - values.put(KEY_FEED, item.getFeed().getId()); - db.insertWithOnConflict(TABLE_NAME_QUEUE, null, values, SQLiteDatabase.CONFLICT_REPLACE); + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + db.beginTransactionNonExclusive(); + } else { + db.beginTransaction(); + } + db.delete(TABLE_NAME_QUEUE, null, null); + for (int i = 0; i < queue.size(); i++) { + FeedItem item = queue.get(i); + values.put(KEY_ID, i); + values.put(KEY_FEEDITEM, item.getId()); + values.put(KEY_FEED, item.getFeed().getId()); + db.insertWithOnConflict(TABLE_NAME_QUEUE, null, values, SQLiteDatabase.CONFLICT_REPLACE); + } + db.setTransactionSuccessful(); + } catch (SQLException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } finally { + db.endTransaction(); } - db.setTransactionSuccessful(); - db.endTransaction(); } public void clearQueue() { @@ -937,23 +1024,32 @@ public class PodDBAdapter { * Remove a feed with all its FeedItems and Media entries. */ public void removeFeed(Feed feed) { - db.beginTransaction(); - if (feed.getImage() != null) { - removeFeedImage(feed.getImage()); - } - if (feed.getItems() != null) { - for (FeedItem item : feed.getItems()) { - removeFeedItem(item); + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + db.beginTransactionNonExclusive(); + } else { + db.beginTransaction(); } - } - // delete download log entries for feed - db.delete(TABLE_NAME_DOWNLOAD_LOG, KEY_FEEDFILE + "=? AND " + KEY_FEEDFILETYPE +"=?", - new String[] { String.valueOf(feed.getId()), String.valueOf(Feed.FEEDFILETYPE_FEED) }); + if (feed.getImage() != null) { + removeFeedImage(feed.getImage()); + } + if (feed.getItems() != null) { + for (FeedItem item : feed.getItems()) { + removeFeedItem(item); + } + } + // delete download log entries for feed + db.delete(TABLE_NAME_DOWNLOAD_LOG, KEY_FEEDFILE + "=? AND " + KEY_FEEDFILETYPE + "=?", + new String[]{String.valueOf(feed.getId()), String.valueOf(Feed.FEEDFILETYPE_FEED)}); - db.delete(TABLE_NAME_FEEDS, KEY_ID + "=?", + db.delete(TABLE_NAME_FEEDS, KEY_ID + "=?", new String[]{String.valueOf(feed.getId())}); - db.setTransactionSuccessful(); - db.endTransaction(); + db.setTransactionSuccessful(); + } catch (SQLException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } finally { + db.endTransaction(); + } } public void clearPlaybackHistory() { @@ -972,9 +1068,8 @@ public class PodDBAdapter { * @return The cursor of the query */ public final Cursor getAllFeedsCursor() { - Cursor c = db.query(TABLE_NAME_FEEDS, FEED_SEL_STD, null, null, null, null, + return db.query(TABLE_NAME_FEEDS, FEED_SEL_STD, null, null, null, null, KEY_TITLE + " COLLATE NOCASE ASC"); - return c; } public final Cursor getFeedCursorDownloadUrls() { @@ -992,22 +1087,19 @@ public class PodDBAdapter { } public final Cursor getAllItemsOfFeedCursor(final long feedId) { - Cursor c = db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED + return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED + "=?", new String[]{String.valueOf(feedId)}, null, null, - null - ); - return c; + null); } /** * Return a cursor with the SEL_FI_EXTRA selection of a single feeditem. */ public final Cursor getExtraInformationOfItem(final FeedItem item) { - Cursor c = db + return db .query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA, KEY_ID + "=?", new String[]{String.valueOf(item.getId())}, null, null, null); - return c; } /** @@ -1017,10 +1109,9 @@ public class PodDBAdapter { * @return The cursor of the query */ public final Cursor getFeedMediaOfItemCursor(final FeedItem item) { - Cursor c = db.query(TABLE_NAME_FEED_MEDIA, null, KEY_ID + "=?", + return db.query(TABLE_NAME_FEED_MEDIA, null, KEY_ID + "=?", new String[]{String.valueOf(item.getMedia().getId())}, null, null, null); - return c; } /** @@ -1065,25 +1156,22 @@ public class PodDBAdapter { } public final Cursor getSimpleChaptersOfFeedItemCursor(final FeedItem item) { - Cursor c = db.query(TABLE_NAME_SIMPLECHAPTERS, null, KEY_FEEDITEM + return db.query(TABLE_NAME_SIMPLECHAPTERS, null, KEY_FEEDITEM + "=?", new String[]{String.valueOf(item.getId())}, null, null, null ); - return c; } public final Cursor getDownloadLog(final int feedFileType, final long feedFileId) { final String query = "SELECT * FROM " + TABLE_NAME_DOWNLOAD_LOG + " WHERE " + KEY_FEEDFILE + "=" + feedFileId + " AND " + KEY_FEEDFILETYPE + "=" + feedFileType + " ORDER BY " + KEY_ID + " DESC"; - Cursor c = db.rawQuery(query, null); - return c; + return db.rawQuery(query, null); } public final Cursor getDownloadLogCursor(final int limit) { - Cursor c = db.query(TABLE_NAME_DOWNLOAD_LOG, null, null, null, null, + return db.query(TABLE_NAME_DOWNLOAD_LOG, null, null, null, null, null, KEY_COMPLETION_DATE + " DESC LIMIT " + limit); - return c; } /** @@ -1099,13 +1187,11 @@ public class PodDBAdapter { TABLE_NAME_QUEUE + "." + KEY_FEEDITEM, TABLE_NAME_QUEUE + "." + KEY_ID }; String query = String.format("SELECT %s FROM %s INNER JOIN %s ON %s=%s ORDER BY %s", args); - Cursor c = db.rawQuery(query, null); - return c; + return db.rawQuery(query, null); } public Cursor getQueueIDCursor() { - Cursor c = db.query(TABLE_NAME_QUEUE, new String[]{KEY_FEEDITEM}, null, null, null, null, KEY_ID + " ASC", null); - return c; + return db.query(TABLE_NAME_QUEUE, new String[]{KEY_FEEDITEM}, null, null, null, null, KEY_ID + " ASC", null); } @@ -1117,8 +1203,7 @@ public class PodDBAdapter { TABLE_NAME_FAVORITES + "." + KEY_FEEDITEM, TABLE_NAME_FEED_ITEMS + "." + KEY_PUBDATE }; String query = String.format("SELECT %s FROM %s INNER JOIN %s ON %s=%s ORDER BY %s DESC", args); - Cursor c = db.rawQuery(query, null); - return c; + return db.rawQuery(query, null); } /** @@ -1126,9 +1211,8 @@ public class PodDBAdapter { * The returned cursor uses the FEEDITEM_SEL_FI_SMALL selection. */ public final Cursor getUnreadItemsCursor() { - Cursor c = db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_READ + return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_READ + "<" + FeedItem.PLAYED, null, null, null, KEY_PUBDATE + " DESC"); - return c; } /** @@ -1141,8 +1225,7 @@ public class PodDBAdapter { + " WHERE " + KEY_FEED + "=" + feedId + " AND " + KEY_READ + "=" + FeedItem.NEW + " ORDER BY " + KEY_PUBDATE + " DESC"; - Cursor c = db.rawQuery(query, null); - return c; + return db.rawQuery(query, null); } /** @@ -1160,13 +1243,11 @@ public class PodDBAdapter { KEY_PUBDATE + " DESC" }; final String query = String.format("SELECT %s FROM %s INNER JOIN %s ON %s WHERE %s ORDER BY %s", args); - Cursor c = db.rawQuery(query, null); - return c; + return db.rawQuery(query, null); } public final Cursor getRecentlyPublishedItemsCursor(int limit) { - Cursor c = db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, null, null, null, null, KEY_PUBDATE + " DESC LIMIT " + limit); - return c; + return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, null, null, null, null, KEY_PUBDATE + " DESC LIMIT " + limit); } public Cursor getDownloadedItemsCursor() { @@ -1175,8 +1256,7 @@ public class PodDBAdapter { + " INNER JOIN " + TABLE_NAME_FEED_MEDIA + " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_ID + "=" + TABLE_NAME_FEED_MEDIA + "." + KEY_FEEDITEM + " WHERE " + TABLE_NAME_FEED_MEDIA + "." + KEY_DOWNLOADED + ">0"; - Cursor c = db.rawQuery(query, null); - return c; + return db.rawQuery(query, null); } /** @@ -1192,10 +1272,9 @@ public class PodDBAdapter { throw new IllegalArgumentException("Limit must be >= 0"); } - Cursor c = db.query(TABLE_NAME_FEED_MEDIA, null, + return db.query(TABLE_NAME_FEED_MEDIA, null, KEY_PLAYBACK_COMPLETION_DATE + " > 0", null, null, null, String.format("%s DESC LIMIT %d", KEY_PLAYBACK_COMPLETION_DATE, limit)); - return c; } public final Cursor getSingleFeedMediaCursor(long id) { @@ -1244,18 +1323,17 @@ public class PodDBAdapter { if (size == 1) { return "(?)"; } - StringBuffer buffer = new StringBuffer("("); + StringBuilder builder = new StringBuilder("("); for (int i = 0; i < size - 1; i++) { - buffer.append("?,"); + builder.append("?,"); } - buffer.append("?)"); - return buffer.toString(); + builder.append("?)"); + return builder.toString(); } public final Cursor getFeedCursor(final long id) { - Cursor c = db.query(TABLE_NAME_FEEDS, FEED_SEL_STD, KEY_ID + "=" + id, null, + return db.query(TABLE_NAME_FEEDS, FEED_SEL_STD, KEY_ID + "=" + id, null, null, null, null); - return c; } public final Cursor getFeedItemCursor(final String id) { 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 9280db8a3..66513a12e 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 @@ -47,10 +47,10 @@ public class HandlerState { public HandlerState(Feed feed) { this.feed = feed; alternateUrls = new ArrayMap<>(); - items = new ArrayList<FeedItem>(); - tagstack = new Stack<SyndElement>(); + items = new ArrayList<>(); + tagstack = new Stack<>(); namespaces = new ArrayMap<>(); - defaultNamespaces = new Stack<Namespace>(); + defaultNamespaces = new Stack<>(); tempObjects = new ArrayMap<>(); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/TypeGetter.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/TypeGetter.java index 4d56e1365..f84d6ee96 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/TypeGetter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/TypeGetter.java @@ -41,27 +41,28 @@ public class TypeGetter { while (eventType != XmlPullParser.END_DOCUMENT) { if (eventType == XmlPullParser.START_TAG) { String tag = xpp.getName(); - if (tag.equals(ATOM_ROOT)) { - feed.setType(Feed.TYPE_ATOM1); - Log.d(TAG, "Recognized type Atom"); - return Type.ATOM; - } else if (tag.equals(RSS_ROOT)) { - String strVersion = xpp.getAttributeValue(null, "version"); - if (strVersion != null) { - if (strVersion.equals("2.0")) { - feed.setType(Feed.TYPE_RSS2); - Log.d(TAG, "Recognized type RSS 2.0"); - return Type.RSS20; - } else if (strVersion.equals("0.91") - || strVersion.equals("0.92")) { - Log.d(TAG, "Recognized type RSS 0.91/0.92"); - return Type.RSS091; + switch (tag) { + case ATOM_ROOT: + feed.setType(Feed.TYPE_ATOM1); + Log.d(TAG, "Recognized type Atom"); + return Type.ATOM; + case RSS_ROOT: + String strVersion = xpp.getAttributeValue(null, "version"); + if (strVersion != null) { + if (strVersion.equals("2.0")) { + feed.setType(Feed.TYPE_RSS2); + Log.d(TAG, "Recognized type RSS 2.0"); + return Type.RSS20; + } else if (strVersion.equals("0.91") + || strVersion.equals("0.92")) { + Log.d(TAG, "Recognized type RSS 0.91/0.92"); + return Type.RSS091; + } } - } - throw new UnsupportedFeedtypeException(Type.INVALID); - } else { - Log.d(TAG, "Type is invalid"); - throw new UnsupportedFeedtypeException(Type.INVALID, tag); + throw new UnsupportedFeedtypeException(Type.INVALID); + default: + Log.d(TAG, "Type is invalid"); + throw new UnsupportedFeedtypeException(Type.INVALID, tag); } } else { eventType = xpp.next(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSContent.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSContent.java index 71bf69ffa..306b79c15 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSContent.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSContent.java @@ -1,8 +1,9 @@ package de.danoeh.antennapod.core.syndication.namespace; -import de.danoeh.antennapod.core.syndication.handler.HandlerState; import org.xml.sax.Attributes; +import de.danoeh.antennapod.core.syndication.handler.HandlerState; + public class NSContent extends Namespace { public static final String NSTAG = "content"; public static final String NSURI = "http://purl.org/rss/1.0/modules/content/"; @@ -17,7 +18,8 @@ public class NSContent extends Namespace { @Override public void handleElementEnd(String localName, HandlerState state) { - if (localName.equals(ENCODED)) { + if (ENCODED.equals(localName) && state.getCurrentItem() != null && + state.getContentBuf() != null) { state.getCurrentItem().setContentEncoded(state.getContentBuf().toString()); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSDublinCore.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSDublinCore.java index 23f76186b..59d66a97e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSDublinCore.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSDublinCore.java @@ -2,6 +2,7 @@ package de.danoeh.antennapod.core.syndication.namespace; import org.xml.sax.Attributes; +import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.syndication.handler.HandlerState; import de.danoeh.antennapod.core.util.DateUtils; @@ -21,17 +22,16 @@ public class NSDublinCore extends Namespace { @Override public void handleElementEnd(String localName, HandlerState state) { - if(state.getTagstack().size() >= 2 - && state.getContentBuf() != null) { - String content = state.getContentBuf().toString(); - SyndElement topElement = state.getTagstack().peek(); - String top = topElement.getName(); - SyndElement secondElement = state.getSecondTag(); - String second = secondElement.getName(); - if (top.equals(DATE) && second.equals(ITEM)) { - state.getCurrentItem().setPubDate( - DateUtils.parse(content)); + if (state.getCurrentItem() != null && state.getContentBuf() != null && + state.getTagstack() != null && state.getTagstack().size() >= 2) { + FeedItem currentItem = state.getCurrentItem(); + String top = state.getTagstack().peek().getName(); + String second = state.getSecondTag().getName(); + if (DATE.equals(top) && ITEM.equals(second)) { + String content = state.getContentBuf().toString(); + currentItem.setPubDate(DateUtils.parse(content)); } } } + } diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java index 769a796e3..1c424c6b5 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java @@ -1,6 +1,7 @@ package de.danoeh.antennapod.core.syndication.namespace; import android.text.TextUtils; +import android.util.Log; import org.xml.sax.Attributes; @@ -10,6 +11,7 @@ import de.danoeh.antennapod.core.feed.FeedImage; import de.danoeh.antennapod.core.syndication.handler.HandlerState; public class NSITunes extends Namespace { + public static final String NSTAG = "itunes"; public static final String NSURI = "http://www.itunes.com/dtds/podcast-1.0.dtd"; @@ -26,69 +28,82 @@ public class NSITunes extends Namespace { @Override public SyndElement handleElementStart(String localName, HandlerState state, Attributes attributes) { - if (localName.equals(IMAGE)) { + if (IMAGE.equals(localName)) { FeedImage image = new FeedImage(); image.setTitle(IMAGE_TITLE); image.setDownload_url(attributes.getValue(IMAGE_HREF)); if (state.getCurrentItem() != null) { // this is an items image - image.setTitle(state.getCurrentItem().getTitle()+IMAGE_TITLE); + image.setTitle(state.getCurrentItem().getTitle() + IMAGE_TITLE); image.setOwner(state.getCurrentItem()); state.getCurrentItem().setImage(image); - - } else { + } else { // this is the feed image // prefer to all other images - if(!TextUtils.isEmpty(image.getDownload_url())) { + if (!TextUtils.isEmpty(image.getDownload_url())) { image.setOwner(state.getFeed()); state.getFeed().setImage(image); } } - } - return new SyndElement(localName, this); } @Override public void handleElementEnd(String localName, HandlerState state) { - if (localName.equals(AUTHOR)) { - state.getFeed().setAuthor(state.getContentBuf().toString()); - } else if (localName.equals(DURATION)) { - String[] parts = state.getContentBuf().toString().trim().split(":"); + if(state.getContentBuf() == null) { + return; + } + if (AUTHOR.equals(localName)) { + if (state.getFeed() != null) { + String author = state.getContentBuf().toString(); + state.getFeed().setAuthor(author); + } + } else if (DURATION.equals(localName)) { + String durationStr = state.getContentBuf().toString(); + if(TextUtils.isEmpty(durationStr)) { + return; + } + String[] parts = durationStr.trim().split(":"); try { - int duration = 0; + int durationMs = 0; if (parts.length == 2) { - duration += TimeUnit.MINUTES.toMillis(Long.parseLong(parts[0])) + - TimeUnit.SECONDS.toMillis(Long.parseLong(parts[1])); + durationMs += TimeUnit.MINUTES.toMillis(Long.parseLong(parts[0])) + + TimeUnit.SECONDS.toMillis((long)Float.parseFloat(parts[1])); } else if (parts.length >= 3) { - duration += TimeUnit.HOURS.toMillis(Long.parseLong(parts[0])) + + durationMs += TimeUnit.HOURS.toMillis(Long.parseLong(parts[0])) + TimeUnit.MINUTES.toMillis(Long.parseLong(parts[1])) + - TimeUnit.SECONDS.toMillis(Long.parseLong(parts[2])); + TimeUnit.SECONDS.toMillis((long)Float.parseFloat(parts[2])); } else { return; } - state.getTempObjects().put(DURATION, duration); + state.getTempObjects().put(DURATION, durationMs); } catch (NumberFormatException e) { - e.printStackTrace(); + Log.e(NSTAG, "Duration \"" + durationStr + "\" could not be parsed"); } - } else if (localName.equals(SUBTITLE)) { + } else if (SUBTITLE.equals(localName)) { String subtitle = state.getContentBuf().toString(); + if (TextUtils.isEmpty(subtitle)) { + return; + } if (state.getCurrentItem() != null) { if (TextUtils.isEmpty(state.getCurrentItem().getDescription())) { state.getCurrentItem().setDescription(subtitle); } } else { - if (TextUtils.isEmpty(state.getFeed().getDescription())) { + if (state.getFeed() != null && TextUtils.isEmpty(state.getFeed().getDescription())) { state.getFeed().setDescription(subtitle); } } - } else if (localName.equals(SUMMARY)) { + } else if (SUMMARY.equals(localName)) { String summary = state.getContentBuf().toString(); + if (TextUtils.isEmpty(summary)) { + return; + } if (state.getCurrentItem() != null) { state.getCurrentItem().setDescription(summary); - } else { + } else if (state.getFeed() != null) { state.getFeed().setDescription(summary); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java index 7f03f1139..7a8b2bc03 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java @@ -1,14 +1,16 @@ package de.danoeh.antennapod.core.syndication.namespace; +import android.text.TextUtils; import android.util.Log; -import de.danoeh.antennapod.core.BuildConfig; -import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.syndication.handler.HandlerState; -import de.danoeh.antennapod.core.syndication.util.SyndTypeUtils; + import org.xml.sax.Attributes; import java.util.concurrent.TimeUnit; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.syndication.handler.HandlerState; +import de.danoeh.antennapod.core.syndication.util.SyndTypeUtils; + /** Processes tags from the http://search.yahoo.com/mrss/ namespace. */ public class NSMedia extends Namespace { private static final String TAG = "NSMedia"; @@ -25,36 +27,41 @@ public class NSMedia extends Namespace { @Override public SyndElement handleElementStart(String localName, HandlerState state, Attributes attributes) { - if (localName.equals(CONTENT)) { + if (CONTENT.equals(localName)) { String url = attributes.getValue(DOWNLOAD_URL); String type = attributes.getValue(MIME_TYPE); - if (state.getCurrentItem().getMedia() == null - && url != null - && (SyndTypeUtils.enclosureTypeValid(type) || ((type = SyndTypeUtils - .getValidMimeTypeFromUrl(url)) != null))) { - + boolean validType; + if(SyndTypeUtils.enclosureTypeValid(type)) { + validType = true; + } else { + type = SyndTypeUtils.getValidMimeTypeFromUrl(url); + validType = type != null; + } + if (state.getCurrentItem() != null && state.getCurrentItem().getMedia() == null && + url != null && validType) { long size = 0; + String sizeStr = attributes.getValue(SIZE); try { - size = Long.parseLong(attributes.getValue(SIZE)); + size = Long.parseLong(sizeStr); } catch (NumberFormatException e) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Length attribute could not be parsed."); + Log.e(TAG, "Size \"" + sizeStr + "\" could not be parsed."); } - - int duration = 0; - try { - String durationStr = attributes.getValue(DURATION); - if (durationStr != null) { - duration = (int) TimeUnit.MILLISECONDS.convert( - Long.parseLong(durationStr), TimeUnit.SECONDS); + + int durationMs = 0; + String durationStr = attributes.getValue(DURATION); + if (!TextUtils.isEmpty(durationStr)) { + try { + long duration = Long.parseLong(durationStr); + durationMs = (int) TimeUnit.MILLISECONDS.convert(duration, TimeUnit.SECONDS); + } catch (NumberFormatException e) { + Log.e(TAG, "Duration \"" + durationStr + "\" could not be parsed"); } - } catch (NumberFormatException e) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Duration attribute could not be parsed"); } - - state.getCurrentItem().setMedia( - new FeedMedia(state.getCurrentItem(), url, size, type)); + FeedMedia media = new FeedMedia(state.getCurrentItem(), url, size, type); + if(durationMs > 0) { + media.setDuration(durationMs); + } + state.getCurrentItem().setMedia(media); } } return new SyndElement(localName, this); diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java index 7e19213be..1c7952a56 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java @@ -1,10 +1,10 @@ package de.danoeh.antennapod.core.syndication.namespace; +import android.text.TextUtils; import android.util.Log; import org.xml.sax.Attributes; -import de.danoeh.antennapod.core.BuildConfig; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedImage; import de.danoeh.antennapod.core.feed.FeedItem; @@ -43,18 +43,23 @@ public class NSRSS20 extends Namespace { @Override public SyndElement handleElementStart(String localName, HandlerState state, Attributes attributes) { - if (localName.equals(ITEM)) { + if (ITEM.equals(localName)) { state.setCurrentItem(new FeedItem()); state.getItems().add(state.getCurrentItem()); state.getCurrentItem().setFeed(state.getFeed()); - } else if (localName.equals(ENCLOSURE)) { + } else if (ENCLOSURE.equals(localName)) { String type = attributes.getValue(ENC_TYPE); String url = attributes.getValue(ENC_URL); - if (state.getCurrentItem().getMedia() == null - && (SyndTypeUtils.enclosureTypeValid(type) || ((type = SyndTypeUtils - .getValidMimeTypeFromUrl(url)) != null))) { - + boolean validType; + if(SyndTypeUtils.enclosureTypeValid(type)) { + validType = true; + } else { + type = type = SyndTypeUtils.getValidMimeTypeFromUrl(url); + validType = type != null; + } + if (state.getCurrentItem() != null && state.getCurrentItem().getMedia() == null && + validType) { long size = 0; try { size = Long.parseLong(attributes.getValue(ENC_LEN)); @@ -63,19 +68,18 @@ public class NSRSS20 extends Namespace { size = 0; } } catch (NumberFormatException e) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Length attribute could not be parsed."); + Log.d(TAG, "Length attribute could not be parsed."); } state.getCurrentItem().setMedia( new FeedMedia(state.getCurrentItem(), url, size, type)); } - } else if (localName.equals(IMAGE)) { + } else if (IMAGE.equals(localName)) { if (state.getTagstack().size() >= 1) { String parent = state.getTagstack().peek().getName(); - if (parent.equals(CHANNEL)) { + if (CHANNEL.equals(parent)) { Feed feed = state.getFeed(); - if(feed.getImage() == null) { + if(feed != null && feed.getImage() == null) { feed.setImage(new FeedImage()); feed.getImage().setOwner(state.getFeed()); } @@ -87,26 +91,26 @@ public class NSRSS20 extends Namespace { @Override public void handleElementEnd(String localName, HandlerState state) { - if (localName.equals(ITEM)) { + if (ITEM.equals(localName)) { if (state.getCurrentItem() != null) { + FeedItem currentItem = state.getCurrentItem(); // the title tag is optional in RSS 2.0. The description is used // as a // title if the item has no title-tag. - if (state.getCurrentItem().getTitle() == null) { - state.getCurrentItem().setTitle( - state.getCurrentItem().getDescription()); + if (currentItem.getTitle() == null) { + currentItem.setTitle(currentItem.getDescription()); } if (state.getTempObjects().containsKey(NSITunes.DURATION)) { - if (state.getCurrentItem().hasMedia()) { - state.getCurrentItem().getMedia().setDuration((Integer) state.getTempObjects().get(NSITunes.DURATION)); + if (currentItem.hasMedia()) { + Integer duration = (Integer) state.getTempObjects().get(NSITunes.DURATION); + currentItem.getMedia().setDuration(duration); } state.getTempObjects().remove(NSITunes.DURATION); } } state.setCurrentItem(null); - } else if (state.getTagstack().size() >= 2 - && state.getContentBuf() != null) { + } else if (state.getTagstack().size() >= 2 && state.getContentBuf() != null) { String content = state.getContentBuf().toString(); SyndElement topElement = state.getTagstack().peek(); String top = topElement.getName(); @@ -116,46 +120,44 @@ public class NSRSS20 extends Namespace { if (state.getTagstack().size() >= 3) { third = state.getThirdTag().getName(); } - - if (top.equals(GUID) && second.equals(ITEM)) { + if (GUID.equals(top) && ITEM.equals(second)) { // some feed creators include an empty or non-standard guid-element in their feed, which should be ignored - if (!content.isEmpty()) { + if (!TextUtils.isEmpty(content) && state.getCurrentItem() != null) { state.getCurrentItem().setItemIdentifier(content); } - } else if (top.equals(TITLE)) { + } else if (TITLE.equals(top)) { String title = content.trim(); - if (second.equals(ITEM)) { + if (ITEM.equals(second) && state.getCurrentItem() != null) { state.getCurrentItem().setTitle(title); - } else if (second.equals(CHANNEL)) { + } else if (CHANNEL.equals(second) && state.getFeed() != null) { state.getFeed().setTitle(title); - } else if (second.equals(IMAGE) && third != null - && third.equals(CHANNEL)) { - if(state.getFeed().getImage().getTitle() == null) { + } else if (IMAGE.equals(second) && CHANNEL.equals(third)) { + if(state.getFeed() != null && state.getFeed().getImage() != null && + state.getFeed().getImage().getTitle() == null) { state.getFeed().getImage().setTitle(title); } } - } else if (top.equals(LINK)) { - if (second.equals(CHANNEL)) { + } else if (LINK.equals(top)) { + if (CHANNEL.equals(second) && state.getFeed() != null) { state.getFeed().setLink(content); - } else if (second.equals(ITEM)) { + } else if (ITEM.equals(second) && state.getCurrentItem() != null) { state.getCurrentItem().setLink(content); } - } else if (top.equals(PUBDATE) && second.equals(ITEM)) { - state.getCurrentItem().setPubDate( - DateUtils.parse(content)); - } else if (top.equals(URL) && second.equals(IMAGE) && third != null - && third.equals(CHANNEL)) { - if(state.getFeed().getImage().getDownload_url() == null) { // prefer itunes:image + } else if (PUBDATE.equals(top) && ITEM.equals(second) && state.getCurrentItem() != null) { + state.getCurrentItem().setPubDate(DateUtils.parse(content)); + } else if (URL.equals(top) && IMAGE.equals(second) && CHANNEL.equals(third)) { + // prefer itunes:image + if(state.getFeed() != null && state.getFeed().getImage() != null && + state.getFeed().getImage().getDownload_url() == null) { state.getFeed().getImage().setDownload_url(content); } - } else if (localName.equals(DESCR)) { - if (second.equals(CHANNEL)) { + } else if (DESCR.equals(localName)) { + if (CHANNEL.equals(second) && state.getFeed() != null) { state.getFeed().setDescription(content); - } else if (second.equals(ITEM)) { + } else if (ITEM.equals(second) && state.getCurrentItem() != null) { state.getCurrentItem().setDescription(content); } - - } else if (localName.equals(LANGUAGE)) { + } else if (LANGUAGE.equals(localName) && state.getFeed() != null) { state.getFeed().setLanguage(content.toLowerCase()); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java index 64b82100e..703817a35 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java @@ -6,8 +6,7 @@ import org.xml.sax.Attributes; import java.util.ArrayList; -import de.danoeh.antennapod.core.BuildConfig; -import de.danoeh.antennapod.core.feed.Chapter; +import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.SimpleChapter; import de.danoeh.antennapod.core.syndication.handler.HandlerState; import de.danoeh.antennapod.core.util.DateUtils; @@ -27,21 +26,22 @@ public class NSSimpleChapters extends Namespace { @Override public SyndElement handleElementStart(String localName, HandlerState state, Attributes attributes) { - if (localName.equals(CHAPTERS)) { - state.getCurrentItem().setChapters(new ArrayList<Chapter>()); - } else if (localName.equals(CHAPTER)) { - try { - state.getCurrentItem() - .getChapters() - .add(new SimpleChapter(DateUtils - .parseTimeString(attributes.getValue(START)), - attributes.getValue(TITLE), state.getCurrentItem(), - attributes.getValue(HREF))); - } catch (NumberFormatException e) { - if (BuildConfig.DEBUG) Log.w(TAG, "Unable to read chapter", e); + FeedItem currentItem = state.getCurrentItem(); + if(currentItem != null) { + if (localName.equals(CHAPTERS)) { + currentItem.setChapters(new ArrayList<>()); + } else if (localName.equals(CHAPTER)) { + try { + long start = DateUtils.parseTimeString(attributes.getValue(START)); + String title = attributes.getValue(TITLE); + String link = attributes.getValue(HREF); + SimpleChapter chapter = new SimpleChapter(start, title, currentItem, link); + currentItem.getChapters().add(chapter); + } catch (NumberFormatException e) { + Log.e(TAG, "Unable to read chapter", e); + } } } - return new SyndElement(localName, this); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java index b23a142af..7b5abf053 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java @@ -1,5 +1,6 @@ package de.danoeh.antennapod.core.syndication.namespace.atom; +import android.text.TextUtils; import android.util.Log; import org.xml.sax.Attributes; @@ -65,21 +66,21 @@ public class NSAtom extends Namespace { @Override public SyndElement handleElementStart(String localName, HandlerState state, Attributes attributes) { - if (localName.equals(ENTRY)) { + if (ENTRY.equals(localName)) { state.setCurrentItem(new FeedItem()); state.getItems().add(state.getCurrentItem()); state.getCurrentItem().setFeed(state.getFeed()); } else if (localName.matches(isText)) { String type = attributes.getValue(TEXT_TYPE); return new AtomText(localName, this, type); - } else if (localName.equals(LINK)) { + } else if (LINK.equals(localName)) { String href = attributes.getValue(LINK_HREF); String rel = attributes.getValue(LINK_REL); SyndElement parent = state.getTagstack().peek(); if (parent.getName().matches(isFeedItem)) { - if (rel == null || rel.equals(LINK_REL_ALTERNATE)) { + if (LINK_REL_ALTERNATE.equals(rel)) { state.getCurrentItem().setLink(href); - } else if (rel.equals(LINK_REL_ENCLOSURE)) { + } else if (LINK_REL_ENCLOSURE.equals(rel)) { String strSize = attributes.getValue(LINK_LENGTH); long size = 0; try { @@ -90,40 +91,45 @@ public class NSAtom extends Namespace { Log.d(TAG, "Length attribute could not be parsed."); } String type = attributes.getValue(LINK_TYPE); - if (SyndTypeUtils.enclosureTypeValid(type) - || (type = SyndTypeUtils.getValidMimeTypeFromUrl(href)) != null) { + boolean validType; + if(SyndTypeUtils.enclosureTypeValid(type)) { + validType = true; + } else { + type = SyndTypeUtils.getValidMimeTypeFromUrl(href); + validType = type != null; + } + if (validType) { FeedItem currItem = state.getCurrentItem(); - if(!currItem.hasMedia()) { + if(currItem != null && !currItem.hasMedia()) { currItem.setMedia(new FeedMedia(currItem, href, size, type)); } } - } else if (rel.equals(LINK_REL_PAYMENT)) { + } else if (LINK_REL_PAYMENT.equals(rel)) { state.getCurrentItem().setPaymentLink(href); } } else if (parent.getName().matches(isFeed)) { - if (rel == null || rel.equals(LINK_REL_ALTERNATE)) { + if (LINK_REL_ALTERNATE.equals(rel)) { String type = attributes.getValue(LINK_TYPE); /* * Use as link if a) no type-attribute is given and * feed-object has no link yet b) type of link is * LINK_TYPE_HTML or LINK_TYPE_XHTML */ - if ((type == null && state.getFeed().getLink() == null) - || (type != null && (type.equals(LINK_TYPE_HTML) - || type.equals(LINK_TYPE_XHTML)))) { + if (state.getFeed() != null && + ((type == null && state.getFeed().getLink() == null) || + (LINK_TYPE_HTML.equals(type) || LINK_TYPE_XHTML.equals(type)))) { state.getFeed().setLink(href); - } else if (type != null && (type.equals(LINK_TYPE_ATOM) - || type.equals(LINK_TYPE_RSS))) { + } else if (LINK_TYPE_ATOM.equals(type) || LINK_TYPE_RSS.equals(type)) { // treat as podlove alternate feed String title = attributes.getValue(LINK_TITLE); - if (title == null) { + if (TextUtils.isEmpty(title)) { title = href; } state.addAlternateFeedUrl(title, href); } - } else if (rel.equals(LINK_REL_PAYMENT)) { + } else if (LINK_REL_PAYMENT.equals(rel) && state.getFeed() != null) { state.getFeed().setPaymentLink(href); - } else if (rel.equals(LINK_REL_NEXT)) { + } else if (LINK_REL_NEXT.equals(rel) && state.getFeed() != null) { state.getFeed().setPaged(true); state.getFeed().setNextPageLink(href); } @@ -134,11 +140,13 @@ public class NSAtom extends Namespace { @Override public void handleElementEnd(String localName, HandlerState state) { - if (localName.equals(ENTRY)) { + if (ENTRY.equals(localName)) { if (state.getCurrentItem() != null && state.getTempObjects().containsKey(NSITunes.DURATION)) { - if (state.getCurrentItem().hasMedia()) { - state.getCurrentItem().getMedia().setDuration((Integer) state.getTempObjects().get(NSITunes.DURATION)); + FeedItem currentItem = state.getCurrentItem(); + if (currentItem.hasMedia()) { + Integer duration = (Integer) state.getTempObjects().get(NSITunes.DURATION); + currentItem.getMedia().setDuration(duration); } state.getTempObjects().remove(NSITunes.DURATION); } @@ -163,47 +171,32 @@ public class NSAtom extends Namespace { textElement.setContent(content); } - if (top.equals(ID)) { - if (second.equals(FEED)) { + if (ID.equals(top)) { + if (FEED.equals(second) && state.getFeed() != null) { state.getFeed().setFeedIdentifier(content); - } else if (second.equals(ENTRY)) { + } else if (ENTRY.equals(second) && state.getCurrentItem() != null) { state.getCurrentItem().setItemIdentifier(content); } - } else if (top.equals(TITLE)) { - - if (second.equals(FEED)) { + } else if (TITLE.equals(top) && textElement != null) { + if (FEED.equals(second) && state.getFeed() != null) { state.getFeed().setTitle(textElement.getProcessedContent()); - } else if (second.equals(ENTRY)) { - state.getCurrentItem().setTitle( - textElement.getProcessedContent()); - } - } else if (top.equals(SUBTITLE)) { - if (second.equals(FEED)) { - state.getFeed().setDescription( - textElement.getProcessedContent()); - } - } else if (top.equals(CONTENT)) { - if (second.equals(ENTRY)) { - state.getCurrentItem().setDescription( - textElement.getProcessedContent()); - } - } else if (top.equals(UPDATED)) { - if (second.equals(ENTRY) - && state.getCurrentItem().getPubDate() == null) { - state.getCurrentItem().setPubDate( - DateUtils.parse(content)); - } - } else if (top.equals(PUBLISHED)) { - if (second.equals(ENTRY)) { - state.getCurrentItem().setPubDate( - DateUtils.parse(content)); - } - } else if (top.equals(IMAGE)) { - if(state.getFeed().getImage() == null) { - state.getFeed().setImage(new FeedImage(state.getFeed(), content, null)); + } else if (ENTRY.equals(second) && state.getCurrentItem() != null) { + state.getCurrentItem().setTitle(textElement.getProcessedContent()); } + } else if (SUBTITLE.equals(top) && FEED.equals(second) && textElement != null && + state.getFeed() != null) { + state.getFeed().setDescription(textElement.getProcessedContent()); + } else if (CONTENT.equals(top) && ENTRY.equals(second) && textElement != null && + state.getCurrentItem() != null) { + state.getCurrentItem().setDescription(textElement.getProcessedContent()); + } else if (UPDATED.equals(top) && ENTRY.equals(second) && state.getCurrentItem() != null && + state.getCurrentItem().getPubDate() == null) { + state.getCurrentItem().setPubDate(DateUtils.parse(content)); + } else if (PUBLISHED.equals(top) && ENTRY.equals(second) && state.getCurrentItem() != null) { + state.getCurrentItem().setPubDate(DateUtils.parse(content)); + } else if (IMAGE.equals(top) && state.getFeed() != null && state.getFeed().getImage() == null) { + state.getFeed().setImage(new FeedImage(state.getFeed(), content, null)); } - } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndTypeUtils.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndTypeUtils.java index 8d1d8ffde..e84361fb2 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndTypeUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndTypeUtils.java @@ -30,8 +30,7 @@ public class SyndTypeUtils { if (url != null) { String extension = FilenameUtils.getExtension(url); if (extension != null) { - String type = MimeTypeMap.getSingleton() - .getMimeTypeFromExtension(extension); + String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); if (type != null && enclosureTypeValid(type)) { return type; } 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 8dd9ffe4b..5169f7e76 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 @@ -10,7 +10,6 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; import java.net.URL; import java.util.Collections; import java.util.List; @@ -63,11 +62,7 @@ public class ChapterUtils { } else { Log.i(TAG, "ChapterReader could not find any ID3 chapters"); } - } catch (MalformedURLException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (ID3ReaderException e) { + } catch (IOException | ID3ReaderException e) { e.printStackTrace(); } finally { if (in != null) { @@ -116,9 +111,7 @@ public class ChapterUtils { Log.i(TAG, "ChapterReader could not find any ID3 chapters"); } - } catch (IOException e) { - e.printStackTrace(); - } catch (ID3ReaderException e) { + } catch (IOException | ID3ReaderException e) { e.printStackTrace(); } finally { if (in != null) { @@ -144,8 +137,6 @@ public class ChapterUtils { if (input != null) { readOggChaptersFromInputStream(media, input); } - } catch (MalformedURLException e) { - e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/DownloadError.java b/core/src/main/java/de/danoeh/antennapod/core/util/DownloadError.java index d3f6c6b79..4ad88743f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/DownloadError.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/DownloadError.java @@ -25,7 +25,7 @@ public enum DownloadError { private final int code; private final int resId; - private DownloadError(int code, int resId) { + DownloadError(int code, int resId) { this.code = code; this.resId = resId; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/EpisodeFilter.java b/core/src/main/java/de/danoeh/antennapod/core/util/EpisodeFilter.java index 029e7fe84..89edd7dbe 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/EpisodeFilter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/EpisodeFilter.java @@ -13,7 +13,7 @@ public class EpisodeFilter { /** Return a copy of the itemlist without items which have no media. */ public static ArrayList<FeedItem> getEpisodeList(List<FeedItem> items) { - ArrayList<FeedItem> episodes = new ArrayList<FeedItem>(items); + ArrayList<FeedItem> episodes = new ArrayList<>(items); for (FeedItem item : items) { if (item.getMedia() == null) { episodes.remove(item); diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/IntList.java b/core/src/main/java/de/danoeh/antennapod/core/util/IntList.java index 1cbe7fade..f48b9169b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/IntList.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/IntList.java @@ -62,7 +62,7 @@ public final class IntList { @Override public String toString() { - StringBuffer sb = new StringBuffer(size * 5 + 10); + StringBuilder sb = new StringBuilder(size * 5 + 10); sb.append("IntList{"); for (int i = 0; i < size; i++) { if (i != 0) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/LongList.java b/core/src/main/java/de/danoeh/antennapod/core/util/LongList.java index 6ed8b820e..fdc244517 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/LongList.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/LongList.java @@ -73,7 +73,7 @@ public final class LongList { @Override public String toString() { - StringBuffer sb = new StringBuffer(size * 5 + 10); + StringBuilder sb = new StringBuilder(size * 5 + 10); sb.append("LongList{"); for (int i = 0; i < size; i++) { if (i != 0) { 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 c2cd273b8..927639e69 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 @@ -96,7 +96,7 @@ public class NetworkUtils { return Observable.create(new Observable.OnSubscribe<Long>() { @Override public void call(Subscriber<? super Long> subscriber) { - if (false == NetworkUtils.isDownloadAllowed()) { + if (!NetworkUtils.isDownloadAllowed()) { subscriber.onNext(0L); subscriber.onCompleted(); return; @@ -107,7 +107,7 @@ public class NetworkUtils { if (mediaFile.exists()) { size = mediaFile.length(); } - } else if (false == media.checkedOnSizeButUnknown()) { + } else if (!media.checkedOnSizeButUnknown()) { // only query the network if we haven't already checked String url = media.getDownload_url(); 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 71d6040ba..5dc194dbd 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 @@ -2,12 +2,12 @@ package de.danoeh.antennapod.core.util; import android.content.Context; +import java.util.Comparator; + import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.storage.DBWriter; -import java.util.Comparator; - /** * Provides method for sorting the queue according to rules. */ @@ -26,59 +26,39 @@ public class QueueSorter { switch (rule) { case ALPHA_ASC: - comparator = new Comparator<FeedItem>() { - public int compare(FeedItem f1, FeedItem f2) { - return f1.getTitle().compareTo(f2.getTitle()); - } - }; + comparator = (f1, f2) -> f1.getTitle().compareTo(f2.getTitle()); break; case ALPHA_DESC: - comparator = new Comparator<FeedItem>() { - public int compare(FeedItem f1, FeedItem f2) { - return f2.getTitle().compareTo(f1.getTitle()); - } - }; + comparator = (f1, f2) -> f2.getTitle().compareTo(f1.getTitle()); break; case DATE_ASC: - comparator = new Comparator<FeedItem>() { - public int compare(FeedItem f1, FeedItem f2) { - return f1.getPubDate().compareTo(f2.getPubDate()); - } - }; + comparator = (f1, f2) -> f1.getPubDate().compareTo(f2.getPubDate()); break; case DATE_DESC: - comparator = new Comparator<FeedItem>() { - public int compare(FeedItem f1, FeedItem f2) { - return f2.getPubDate().compareTo(f1.getPubDate()); - } - }; + comparator = (f1, f2) -> f2.getPubDate().compareTo(f1.getPubDate()); break; case DURATION_ASC: - comparator = new Comparator<FeedItem>() { - public int compare(FeedItem f1, FeedItem f2) { - FeedMedia f1Media = f1.getMedia(); - FeedMedia f2Media = f2.getMedia(); - int duration1 = f1Media != null ? f1Media.getDuration() : -1; - int duration2 = f2Media != null ? f2Media.getDuration() : -1; + comparator = (f1, f2) -> { + FeedMedia f1Media = f1.getMedia(); + FeedMedia f2Media = f2.getMedia(); + int duration1 = f1Media != null ? f1Media.getDuration() : -1; + int duration2 = f2Media != null ? f2Media.getDuration() : -1; - if (duration1 == -1 || duration2 == -1) - return duration2 - duration1; - else - return duration1 - duration2; - } + if (duration1 == -1 || duration2 == -1) + return duration2 - duration1; + else + return duration1 - duration2; }; break; case DURATION_DESC: - comparator = new Comparator<FeedItem>() { - public int compare(FeedItem f1, FeedItem f2) { + comparator = (f1, f2) -> { FeedMedia f1Media = f1.getMedia(); FeedMedia f2Media = f2.getMedia(); int duration1 = f1Media != null ? f1Media.getDuration() : -1; int duration2 = f2Media != null ? f2Media.getDuration() : -1; return -1 * (duration1 - duration2); - } - }; + }; default: } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ShownotesProvider.java b/core/src/main/java/de/danoeh/antennapod/core/util/ShownotesProvider.java index 7e7c6c08b..a4cd83f70 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/ShownotesProvider.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/ShownotesProvider.java @@ -11,6 +11,6 @@ public interface ShownotesProvider { * database, it should be done in a separate thread. After the shownotes * have been loaded, callback.onShownotesLoaded should be called. */ - public Callable<String> loadShownotes(); + Callable<String> loadShownotes(); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/URIUtil.java b/core/src/main/java/de/danoeh/antennapod/core/util/URIUtil.java index 092c06b4a..e093dc766 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/URIUtil.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/URIUtil.java @@ -1,13 +1,14 @@ package de.danoeh.antennapod.core.util; import android.util.Log; -import de.danoeh.antennapod.core.BuildConfig; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import de.danoeh.antennapod.core.BuildConfig; + /** * Utility methods for dealing with URL encoding. */ @@ -26,9 +27,7 @@ public class URIUtil { try { URL url = new URL(source); return new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef()); - } catch (MalformedURLException e) { - throw new IllegalArgumentException(e); - } catch (URISyntaxException e) { + } catch (MalformedURLException | URISyntaxException e) { throw new IllegalArgumentException(e); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrServiceCreator.java b/core/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrServiceCreator.java index e4818214e..97958eea7 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrServiceCreator.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrServiceCreator.java @@ -1,11 +1,13 @@ package de.danoeh.antennapod.core.util.flattr; import android.util.Log; -import de.danoeh.antennapod.core.BuildConfig; + import org.shredzone.flattr4j.FlattrFactory; import org.shredzone.flattr4j.FlattrService; import org.shredzone.flattr4j.oauth.AccessToken; +import de.danoeh.antennapod.core.BuildConfig; + /** Ensures that only one instance of the FlattrService class exists at a time */ public class FlattrServiceCreator { @@ -13,11 +15,14 @@ public class FlattrServiceCreator { private static volatile FlattrService flattrService; - public static FlattrService getService(AccessToken token) { - return FlattrFactory.getInstance().createFlattrService(token); + public synchronized static FlattrService getService(AccessToken token) { + if (flattrService == null) { + flattrService = FlattrFactory.getInstance().createFlattrService(token); + } + return flattrService; } - public static void deleteFlattrService() { + public synchronized static void deleteFlattrService() { if (BuildConfig.DEBUG) Log.d(TAG, "Deleting service instance"); flattrService = null; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/gui/MoreContentListFooterUtil.java b/core/src/main/java/de/danoeh/antennapod/core/util/gui/MoreContentListFooterUtil.java index d56871fd1..386f46724 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/gui/MoreContentListFooterUtil.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/gui/MoreContentListFooterUtil.java @@ -19,12 +19,9 @@ public class MoreContentListFooterUtil { public MoreContentListFooterUtil(View root) { this.root = root; - root.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (listener != null && !loading) { - listener.onClick(); - } + root.setOnClickListener(v -> { + if (listener != null && !loading) { + listener.onClick(); } }); } @@ -46,8 +43,8 @@ public class MoreContentListFooterUtil { listener = l; } - public static interface Listener { - public void onClick(); + public interface Listener { + void onClick(); } public View getRoot() { 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 9f3c4c6d5..1807421b0 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 @@ -1,11 +1,6 @@ package de.danoeh.antennapod.core.util.id3reader; import android.util.Log; -import de.danoeh.antennapod.core.BuildConfig; -import de.danoeh.antennapod.core.feed.Chapter; -import de.danoeh.antennapod.core.feed.ID3Chapter; -import de.danoeh.antennapod.core.util.id3reader.model.FrameHeader; -import de.danoeh.antennapod.core.util.id3reader.model.TagHeader; import java.io.IOException; import java.io.InputStream; @@ -13,6 +8,12 @@ import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; +import de.danoeh.antennapod.core.BuildConfig; +import de.danoeh.antennapod.core.feed.Chapter; +import de.danoeh.antennapod.core.feed.ID3Chapter; +import de.danoeh.antennapod.core.util.id3reader.model.FrameHeader; +import de.danoeh.antennapod.core.util.id3reader.model.TagHeader; + public class ChapterReader extends ID3Reader { private static final String TAG = "ID3ChapterReader"; @@ -25,7 +26,7 @@ public class ChapterReader extends ID3Reader { @Override public int onStartTagHeader(TagHeader header) { - chapters = new ArrayList<Chapter>(); + chapters = new ArrayList<>(); System.out.println(header.toString()); return ID3Reader.ACTION_DONT_SKIP; } @@ -34,49 +35,53 @@ public class ChapterReader extends ID3Reader { public int onStartFrameHeader(FrameHeader header, InputStream input) throws IOException, ID3ReaderException { System.out.println(header.toString()); - if (header.getId().equals(FRAME_ID_CHAPTER)) { - if (currentChapter != null) { - if (!hasId3Chapter(currentChapter)) { - chapters.add(currentChapter); - if (BuildConfig.DEBUG) Log.d(TAG, "Found chapter: " + currentChapter); - currentChapter = null; + switch (header.getId()) { + case FRAME_ID_CHAPTER: + if (currentChapter != null) { + if (!hasId3Chapter(currentChapter)) { + chapters.add(currentChapter); + if (BuildConfig.DEBUG) Log.d(TAG, "Found chapter: " + currentChapter); + currentChapter = null; + } } - } - StringBuffer elementId = new StringBuffer(); - readISOString(elementId, input, Integer.MAX_VALUE); - char[] startTimeSource = readBytes(input, 4); - long startTime = ((int) startTimeSource[0] << 24) - | ((int) startTimeSource[1] << 16) - | ((int) startTimeSource[2] << 8) | startTimeSource[3]; - currentChapter = new ID3Chapter(elementId.toString(), startTime); - skipBytes(input, 12); - return ID3Reader.ACTION_DONT_SKIP; - } else if (header.getId().equals(FRAME_ID_TITLE)) { - if (currentChapter != null && currentChapter.getTitle() == null) { - StringBuffer title = new StringBuffer(); - readString(title, input, header.getSize()); - currentChapter - .setTitle(title.toString()); - if (BuildConfig.DEBUG) Log.d(TAG, "Found title: " + currentChapter.getTitle()); - + StringBuffer elementId = new StringBuffer(); + readISOString(elementId, input, Integer.MAX_VALUE); + char[] startTimeSource = readBytes(input, 4); + long startTime = ((int) startTimeSource[0] << 24) + | ((int) startTimeSource[1] << 16) + | ((int) startTimeSource[2] << 8) | startTimeSource[3]; + currentChapter = new ID3Chapter(elementId.toString(), startTime); + skipBytes(input, 12); return ID3Reader.ACTION_DONT_SKIP; - } - } else if (header.getId().equals(FRAME_ID_LINK)) { - if (currentChapter != null) { - // skip description - int descriptionLength = readString(null, input, header.getSize()); - StringBuffer link = new StringBuffer(); - readISOString(link, input, header.getSize() - descriptionLength); - String decodedLink = URLDecoder.decode(link.toString(), "UTF-8"); - - currentChapter.setLink(decodedLink); - - if (BuildConfig.DEBUG) Log.d(TAG, "Found link: " + currentChapter.getLink()); - return ID3Reader.ACTION_DONT_SKIP; - } - } else if (header.getId().equals("APIC")) { - Log.d(TAG, header.toString()); - } + case FRAME_ID_TITLE: + if (currentChapter != null && currentChapter.getTitle() == null) { + StringBuffer title = new StringBuffer(); + readString(title, input, header.getSize()); + currentChapter + .setTitle(title.toString()); + if (BuildConfig.DEBUG) Log.d(TAG, "Found title: " + currentChapter.getTitle()); + + return ID3Reader.ACTION_DONT_SKIP; + } + break; + case FRAME_ID_LINK: + if (currentChapter != null) { + // skip description + int descriptionLength = readString(null, input, header.getSize()); + StringBuffer link = new StringBuffer(); + readISOString(link, input, header.getSize() - descriptionLength); + String decodedLink = URLDecoder.decode(link.toString(), "UTF-8"); + + currentChapter.setLink(decodedLink); + + if (BuildConfig.DEBUG) Log.d(TAG, "Found link: " + currentChapter.getLink()); + return ID3Reader.ACTION_DONT_SKIP; + } + break; + case "APIC": + Log.d(TAG, header.toString()); + break; + } return super.onStartFrameHeader(header, input); } 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 ec50dce7c..412a27b95 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 @@ -6,13 +6,14 @@ import android.media.MediaMetadataRetriever; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; -import de.danoeh.antennapod.core.feed.Chapter; -import de.danoeh.antennapod.core.feed.MediaType; -import de.danoeh.antennapod.core.util.ChapterUtils; import java.util.List; import java.util.concurrent.Callable; +import de.danoeh.antennapod.core.feed.Chapter; +import de.danoeh.antennapod.core.feed.MediaType; +import de.danoeh.antennapod.core.util.ChapterUtils; + /** Represents a media file that is stored on the local storage device. */ public class ExternalMedia implements Playable { @@ -106,12 +107,7 @@ public class ExternalMedia implements Playable { @Override public Callable<String> loadShownotes() { - return new Callable<String>() { - @Override - public String call() throws Exception { - return ""; - } - }; + return () -> ""; } @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 86ec4fbd0..6459d86ed 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 @@ -26,7 +26,7 @@ public interface Playable extends Parcelable, * Implementations must NOT call commit() after they have written the values * to the preferences file. */ - public void writeToPreferences(SharedPreferences.Editor prefEditor); + void writeToPreferences(SharedPreferences.Editor prefEditor); /** * This method is called from a separate thread by the PlaybackService. @@ -34,88 +34,88 @@ public interface Playable extends Parcelable, * should execute as quickly as possible and NOT load chapter marks if no * local file is available. */ - public void loadMetadata() throws PlayableException; + void loadMetadata() throws PlayableException; /** * This method is called from a separate thread by the PlaybackService. * Playable objects should load their chapter marks in this method if no * local file was available when loadMetadata() was called. */ - public void loadChapterMarks(); + void loadChapterMarks(); /** * Returns the title of the episode that this playable represents */ - public String getEpisodeTitle(); + String getEpisodeTitle(); /** * Returns a list of chapter marks or null if this Playable has no chapters. */ - public List<Chapter> getChapters(); + List<Chapter> getChapters(); /** * Returns a link to a website that is meant to be shown in a browser */ - public String getWebsiteLink(); + String getWebsiteLink(); - public String getPaymentLink(); + String getPaymentLink(); /** * Returns the title of the feed this Playable belongs to. */ - public String getFeedTitle(); + String getFeedTitle(); /** * Returns a unique identifier, for example a file url or an ID from a * database. */ - public Object getIdentifier(); + Object getIdentifier(); /** * Return duration of object or 0 if duration is unknown. */ - public int getDuration(); + int getDuration(); /** * Return position of object or 0 if position is unknown. */ - public int getPosition(); + int getPosition(); /** * Returns last time (in ms) when this playable was played or 0 * if last played time is unknown. */ - public long getLastPlayedTime(); + long getLastPlayedTime(); /** * Returns the type of media. This method should return the correct value * BEFORE loadMetadata() is called. */ - public MediaType getMediaType(); + MediaType getMediaType(); /** * Returns an url to a local file that can be played or null if this file * does not exist. */ - public String getLocalMediaUrl(); + String getLocalMediaUrl(); /** * Returns an url to a file that can be streamed by the player or null if * this url is not known. */ - public String getStreamUrl(); + String getStreamUrl(); /** * Returns true if a local file that can be played is available. getFileUrl * MUST return a non-null string if this method returns true. */ - public boolean localFileAvailable(); + boolean localFileAvailable(); /** * Returns true if a streamable file is available. getStreamUrl MUST return * a non-null string if this method returns true. */ - public boolean streamAvailable(); + boolean streamAvailable(); /** * Saves the current position of this object. Implementations can use the @@ -126,40 +126,40 @@ public interface Playable extends Parcelable, * @param newPosition new playback position in ms * @param timestamp current time in ms */ - public void saveCurrentPosition(SharedPreferences pref, int newPosition, long timestamp); + void saveCurrentPosition(SharedPreferences pref, int newPosition, long timestamp); - public void setPosition(int newPosition); + void setPosition(int newPosition); - public void setDuration(int newDuration); + void setDuration(int newDuration); /** * @param lastPlayedTimestamp timestamp in ms */ - public void setLastPlayedTime(long lastPlayedTimestamp); + void setLastPlayedTime(long lastPlayedTimestamp); /** * Is called by the PlaybackService when playback starts. */ - public void onPlaybackStart(); + void onPlaybackStart(); /** * Is called by the PlaybackService when playback is completed. */ - public void onPlaybackCompleted(); + void onPlaybackCompleted(); /** * Returns an integer that must be unique among all Playable classes. The * return value is later used by PlayableUtils to determine the type of the * Playable object that is restored. */ - public int getPlayableType(); + int getPlayableType(); - public void setChapters(List<Chapter> chapters); + void setChapters(List<Chapter> chapters); /** * Provides utility methods for Playable objects. */ - public static class PlayableUtils { + class PlayableUtils { private static final String TAG = "PlayableUtils"; /** @@ -213,7 +213,7 @@ public interface Playable extends Parcelable, } } - public static class PlayableException extends Exception { + class PlayableException extends Exception { private static final long serialVersionUID = 1L; public PlayableException() { 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 1a011a90b..016ff9a85 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 @@ -237,10 +237,9 @@ public abstract class PlaybackController { private void setupPositionObserver() { - if ((positionObserverFuture != null && positionObserverFuture - .isCancelled()) - || (positionObserverFuture != null && positionObserverFuture - .isDone()) || positionObserverFuture == null) { + if (positionObserverFuture == null || + positionObserverFuture.isCancelled() || + positionObserverFuture.isDone()) { Log.d(TAG, "Setting up position observer"); positionObserver = new MediaPositionObserver(); @@ -360,31 +359,31 @@ public abstract class PlaybackController { } }; - public void setupGUI() {}; + public void setupGUI() {} - public void onPositionObserverUpdate() {}; + public void onPositionObserverUpdate() {} - public void onPlaybackSpeedChange() {}; + public void onPlaybackSpeedChange() {} - public void onShutdownNotification() {}; + public void onShutdownNotification() {} /** * Called when the currently displayed information should be refreshed. */ - public void onReloadNotification(int code) {}; + public void onReloadNotification(int code) {} - public void onBufferStart() {}; + public void onBufferStart() {} - public void onBufferEnd() {}; + public void onBufferEnd() {} - public void onBufferUpdate(float progress) {}; + public void onBufferUpdate(float progress) {} - public void onSleepTimerUpdate() {}; + public void onSleepTimerUpdate() {} - public void handleError(int code) {}; + public void handleError(int code) {} - public void onPlaybackEnd() {}; + public void onPlaybackEnd() {} public void repeatHandleStatus() { if (status != null && playbackService != null) { @@ -484,17 +483,17 @@ public abstract class PlaybackController { public ImageButton getPlayButton() { return null; - }; + } - public void postStatusMsg(int msg) {}; + public void postStatusMsg(int msg) {} - public void clearStatusMsg() {}; + public void clearStatusMsg() {} public boolean loadMediaInfo() { return false; - }; + } - public void onAwaitingVideoSurface() {}; + public void onAwaitingVideoSurface() {} /** * Called when connection to playback service has been established or @@ -528,7 +527,7 @@ public abstract class PlaybackController { } } - public void onServiceQueried() {}; + public void onServiceQueried() {} /** * Should be used by classes which implement the OnSeekBarChanged interface. @@ -591,7 +590,7 @@ public abstract class PlaybackController { playbackService.setStartWhenPrepared(!playbackService .isStartWhenPrepared()); if (reinitOnPause - && playbackService.isStartWhenPrepared() == false) { + && !playbackService.isStartWhenPrepared()) { playbackService.reinit(); } break; @@ -677,12 +676,10 @@ public abstract class PlaybackController { } public boolean canSetPlaybackSpeed() { - if (org.antennapod.audio.MediaPlayer.isPrestoLibraryInstalled(activity.getApplicationContext()) + return org.antennapod.audio.MediaPlayer.isPrestoLibraryInstalled(activity.getApplicationContext()) || UserPreferences.useSonic() - || Build.VERSION.SDK_INT >= 23) { - return true; - } - return playbackService != null && playbackService.canSetSpeed(); + || Build.VERSION.SDK_INT >= 23 + || playbackService != null && playbackService.canSetSpeed(); } public void setPlaybackSpeed(float speed) { @@ -716,10 +713,7 @@ public abstract class PlaybackController { } public boolean isPlayingVideo() { - if (playbackService != null) { - return PlaybackService.getCurrentMediaType() == MediaType.VIDEO; - } - return false; + return playbackService != null && PlaybackService.getCurrentMediaType() == MediaType.VIDEO; } public Pair<Integer, Integer> getVideoSize() { @@ -751,9 +745,9 @@ public abstract class PlaybackController { public void reinitServiceIfPaused() { if (playbackService != null && playbackService.isStreaming() - && (playbackService.getStatus() == PlayerStatus.PAUSED || (playbackService - .getStatus() == PlayerStatus.PREPARING && playbackService - .isStartWhenPrepared() == false))) { + && (playbackService.getStatus() == PlayerStatus.PAUSED || + (playbackService.getStatus() == PlayerStatus.PREPARING && + !playbackService.isStartWhenPrepared()))) { playbackService.reinit(); } } @@ -768,13 +762,7 @@ public abstract class PlaybackController { @Override public void run() { if (playbackService != null && playbackService.getStatus() == PlayerStatus.PLAYING) { - activity.runOnUiThread(new Runnable() { - - @Override - public void run() { - onPositionObserverUpdate(); - } - }); + activity.runOnUiThread(PlaybackController.this::onPositionObserverUpdate); } } } 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 8d9151396..efdf46a97 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 @@ -68,7 +68,7 @@ public class Timeline { private static final Pattern TIMECODE_LINK_REGEX = Pattern.compile("antennapod://timecode/((\\d+))"); private static final String TIMECODE_LINK = "<a class=\"timecode\" href=\"antennapod://timecode/%d\">%s</a>"; private static final Pattern TIMECODE_REGEX = Pattern.compile("\\b(?:(?:(([0-9][0-9])):))?(([0-9][0-9])):(([0-9][0-9]))\\b"); - private static final Pattern LINE_BREAK_REGEX = Pattern.compile("<br *\\/?>"); + private static final Pattern LINE_BREAK_REGEX = Pattern.compile("<br */?>"); /** diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java index c4961a3ab..6243da5bc 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java @@ -9,7 +9,7 @@ import java.util.ArrayList; import java.util.List; public class VorbisCommentChapterReader extends VorbisCommentReader { - private static final String TAG = "VorbisCommentChapterReader"; + private static final String TAG = "VorbisCommentChptrReadr"; private static final String CHAPTER_KEY = "chapter\\d\\d\\d.*"; private static final String CHAPTER_ATTRIBUTE_TITLE = "name"; @@ -27,7 +27,7 @@ public class VorbisCommentChapterReader extends VorbisCommentReader { @Override public void onVorbisCommentHeaderFound(VorbisCommentHeader header) { - chapters = new ArrayList<Chapter>(); + chapters = new ArrayList<>(); System.out.println(header.toString()); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java index 9639b9c42..49ea18721 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java @@ -180,13 +180,13 @@ public abstract class VorbisCommentReader { private String readContentVectorKey(InputStream input, long vectorLength) throws IOException { - StringBuffer buffer = new StringBuffer(); + StringBuilder builder = new StringBuilder(); for (int i = 0; i < vectorLength; i++) { char c = (char) input.read(); if (c == '=') { - return buffer.toString(); + return builder.toString(); } else { - buffer.append(c); + builder.append(c); } } return null; // no key found diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index d7948c0a3..eaf6d09fb 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -139,6 +139,7 @@ <string name="hide_not_downloaded_episodes_label">Not downloaded</string> <string name="filtered_label">Filtered</string> <string name="refresh_failed_msg">{fa-exclamation-circle} Last Refresh failed</string> + <string name="open_podcast">Open Podcast</string> <!-- actions on feeditems --> <string name="download_label">Download</string> @@ -369,6 +370,7 @@ <string name="pref_gpodnet_sync_title">Sync now</string> <string name="pref_gpodnet_sync_sum">Sync subscriptions and episode states with gpodder.net</string> <string name="pref_gpodnet_sync_started">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_playback_speed_title">Playback Speeds</string> <string name="pref_playback_speed_sum">Customize the speeds available for variable speed audio playback</string> <string name="pref_fast_forward">Fast forward time</string> @@ -398,6 +400,8 @@ <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_known_issues">Known issues</string> + <string name="pref_no_browser_found">No web browser found."</string> <!-- Auto-Flattr dialog --> <string name="auto_flattr_enable">Enable automatic flattring</string> |