summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordaniel oeh <daniel.oeh@gmail.com>2014-02-17 21:40:04 +0100
committerdaniel oeh <daniel.oeh@gmail.com>2014-02-17 21:40:04 +0100
commit02653918f0290dcff582987b52cd99c6ea707ed9 (patch)
tree41b1c62d9a4a839f543186b604f280d659fbb11a /src
parenta2f841c43e95c8b3743788e7bbc505c90045e73b (diff)
parent33b1f107441dc83cc3917078cf9164f00e7ff8b1 (diff)
downloadAntennaPod-02653918f0290dcff582987b52cd99c6ea707ed9.zip
Merge branch 'flattr_queue_autoflattr' into develop (#331)
Other changes: - Changed FlattrStatusFetcher into Thread-subclass - Changed auto-flattr mechanism so that it's compatible with the updated PlaybackService - Changed a couple of strings Conflicts: src/de/danoeh/antennapod/storage/DBReader.java src/de/danoeh/antennapod/storage/DBWriter.java src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java src/instrumentationTest/de/test/antennapod/storage/DBReaderTest.java
Diffstat (limited to 'src')
-rw-r--r--src/de/danoeh/antennapod/activity/MediaplayerActivity.java16
-rw-r--r--src/de/danoeh/antennapod/activity/PreferenceActivity.java10
-rw-r--r--src/de/danoeh/antennapod/asynctask/FlattrClickWorker.java297
-rw-r--r--src/de/danoeh/antennapod/asynctask/FlattrStatusFetcher.java47
-rw-r--r--src/de/danoeh/antennapod/feed/Feed.java32
-rw-r--r--src/de/danoeh/antennapod/feed/FeedItem.java17
-rw-r--r--src/de/danoeh/antennapod/feed/FeedMedia.java30
-rw-r--r--src/de/danoeh/antennapod/preferences/UserPreferences.java18
-rw-r--r--src/de/danoeh/antennapod/service/playback/PlaybackService.java29
-rw-r--r--src/de/danoeh/antennapod/storage/DBReader.java69
-rw-r--r--src/de/danoeh/antennapod/storage/DBTasks.java8
-rw-r--r--src/de/danoeh/antennapod/storage/DBWriter.java165
-rw-r--r--src/de/danoeh/antennapod/storage/PodDBAdapter.java154
-rw-r--r--src/de/danoeh/antennapod/util/flattr/FlattrStatus.java68
-rw-r--r--src/de/danoeh/antennapod/util/flattr/FlattrThing.java9
-rw-r--r--src/de/danoeh/antennapod/util/flattr/FlattrUtils.java63
-rw-r--r--src/de/danoeh/antennapod/util/flattr/SimpleFlattrThing.java30
-rw-r--r--src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java279
-rw-r--r--src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java14
-rw-r--r--src/instrumentationTest/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java2
-rw-r--r--src/instrumentationTest/de/test/antennapod/storage/DBReaderTest.java4
-rw-r--r--src/instrumentationTest/de/test/antennapod/storage/DBTasksTest.java9
-rw-r--r--src/instrumentationTest/de/test/antennapod/storage/DBTestUtils.java3
-rw-r--r--src/instrumentationTest/de/test/antennapod/storage/DBWriterTest.java12
24 files changed, 1135 insertions, 250 deletions
diff --git a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java
index 60589bdf5..4aae2b091 100644
--- a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -21,14 +21,18 @@ import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.asynctask.FlattrClickWorker;
import de.danoeh.antennapod.dialog.TimeDialog;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.service.playback.PlaybackService;
import de.danoeh.antennapod.util.Converter;
import de.danoeh.antennapod.util.ShareUtils;
import de.danoeh.antennapod.util.StorageUtils;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
import de.danoeh.antennapod.util.playback.MediaPlayerError;
import de.danoeh.antennapod.util.playback.Playable;
import de.danoeh.antennapod.util.playback.PlaybackController;
+import de.danoeh.antennapod.storage.DBWriter;
/**
* Provides general features which are both needed for playing audio and video
@@ -313,8 +317,16 @@ public abstract class MediaplayerActivity extends ActionBarActivity
startActivity(new Intent(Intent.ACTION_VIEW, uri));
break;
case R.id.support_item:
- new FlattrClickWorker(this, media.getPaymentLink())
- .executeAsync();
+ try {
+ FeedItem feedItem = ((FeedMedia) media).getItem();
+ feedItem.getFlattrStatus().setFlattrQueue();
+
+ DBWriter.setFeedItem(this, feedItem);
+ new FlattrClickWorker(this).executeAsync();
+ }
+ catch (ClassCastException e) {
+ Log.d(TAG, "Could not flattr item - most likely external media: " + e.toString());
+ }
break;
case R.id.share_link_item:
ShareUtils.shareLink(this, media.getWebsiteLink());
diff --git a/src/de/danoeh/antennapod/activity/PreferenceActivity.java b/src/de/danoeh/antennapod/activity/PreferenceActivity.java
index e6fcf5306..4a8dc1882 100644
--- a/src/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/src/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -28,7 +28,9 @@ import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
import de.danoeh.antennapod.preferences.GpodnetPreferences;
import de.danoeh.antennapod.preferences.UserPreferences;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
import de.danoeh.antennapod.util.flattr.FlattrUtils;
+import de.danoeh.antennapod.util.flattr.SimpleFlattrThing;
import java.io.File;
import java.util.ArrayList;
@@ -44,6 +46,7 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
private static final String PREF_FLATTR_THIS_APP = "prefFlattrThisApp";
private static final String PREF_FLATTR_AUTH = "pref_flattr_authenticate";
private static final String PREF_FLATTR_REVOKE = "prefRevokeAccess";
+ private static final String PREF_AUTO_FLATTR = "pref_auto_flattr";
private static final String PREF_OPML_EXPORT = "prefOpmlExport";
private static final String PREF_ABOUT = "prefAbout";
private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
@@ -78,7 +81,11 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
@Override
public boolean onPreferenceClick(Preference preference) {
new FlattrClickWorker(PreferenceActivity.this,
- FlattrUtils.APP_URL).executeAsync();
+ new SimpleFlattrThing(PreferenceActivity.this.getString(R.string.app_name),
+ FlattrUtils.APP_URL,
+ new FlattrStatus(FlattrStatus.STATUS_QUEUE)
+ )
+ ).executeAsync();
return true;
}
@@ -297,6 +304,7 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
findPreference(PREF_FLATTR_AUTH).setEnabled(!hasFlattrToken);
findPreference(PREF_FLATTR_REVOKE).setEnabled(hasFlattrToken);
+ findPreference(PREF_AUTO_FLATTR).setEnabled(hasFlattrToken);
findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)
.setEnabled(UserPreferences.isEnableAutodownload());
diff --git a/src/de/danoeh/antennapod/asynctask/FlattrClickWorker.java b/src/de/danoeh/antennapod/asynctask/FlattrClickWorker.java
index 975aa5efe..458b1261b 100644
--- a/src/de/danoeh/antennapod/asynctask/FlattrClickWorker.java
+++ b/src/de/danoeh/antennapod/asynctask/FlattrClickWorker.java
@@ -1,107 +1,310 @@
package de.danoeh.antennapod.asynctask;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.concurrent.Executor;
+
import org.shredzone.flattr4j.exception.FlattrException;
+import org.shredzone.flattr4j.model.Flattr;
import android.annotation.SuppressLint;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
+import android.content.Intent;
+import android.graphics.BitmapFactory;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.os.AsyncTask;
+import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.FeedItemlistActivity;
+import de.danoeh.antennapod.feed.Feed;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.util.flattr.FlattrThing;
import de.danoeh.antennapod.util.flattr.FlattrUtils;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
+import de.danoeh.antennapod.storage.DBReader;
+import de.danoeh.antennapod.storage.DBWriter;
/** Performs a click action in a background thread. */
-public class FlattrClickWorker extends AsyncTask<Void, Void, Void> {
+public class FlattrClickWorker extends AsyncTask<Void, String, Void> {
protected static final String TAG = "FlattrClickWorker";
protected Context context;
- protected String url;
+
+ private final int NOTIFICATION_ID = 4;
+
protected String errorMsg;
protected int exitCode;
+ protected ArrayList<String> flattrd;
+ protected ArrayList<String> flattr_failed;
+
+
+ protected NotificationCompat.Builder notificationCompatBuilder;
+ private Notification.BigTextStyle notificationBuilder;
+ protected NotificationManager notificationManager;
+
protected ProgressDialog progDialog;
- protected final static int SUCCESS = 0;
+ protected final static int EXIT_DEFAULT = 0;
protected final static int NO_TOKEN = 1;
- protected final static int FLATTR_ERROR = 2;
+ protected final static int ENQUEUED = 2;
+ protected final static int NO_THINGS = 3;
+
+ public final static int ENQUEUE_ONLY = 1;
+ public final static int FLATTR_TOAST = 2;
+ public static final int FLATTR_NOTIFICATION = 3;
+
+ private int run_mode = FLATTR_NOTIFICATION;
+
+ private FlattrThing extra_flattr_thing; // additional urls to flattr that do *not* originate from the queue
- public FlattrClickWorker(Context context, String url) {
+ /**
+ * @param context
+ * @param run_mode can be one of ENQUEUE_ONLY, FLATTR_TOAST and FLATTR_NOTIFICATION
+ */
+ public FlattrClickWorker(Context context, int run_mode) {
+ this(context);
+ this.run_mode = run_mode;
+ }
+
+ public FlattrClickWorker(Context context) {
super();
this.context = context;
- this.url = url;
- exitCode = SUCCESS;
+ exitCode = EXIT_DEFAULT;
+
+ flattrd = new ArrayList<String>();
+ flattr_failed = new ArrayList<String>();
+
errorMsg = "";
}
- protected void onNoAccessToken() {
+ /* only used in PreferencesActivity for flattring antennapod itself,
+ * can't really enqueue this thing
+ */
+ public FlattrClickWorker(Context context, FlattrThing thing) {
+ this(context);
+ extra_flattr_thing = thing;
+ run_mode = FLATTR_TOAST;
+ Log.d(TAG, "Going to flattr special thing that is not in the queue: " + thing.getTitle());
+ }
+
+ protected void onNoAccessToken() {
Log.w(TAG, "No access token was available");
- if (url.equals(FlattrUtils.APP_URL)) {
- FlattrUtils.showNoTokenDialog(context, FlattrUtils.APP_LINK);
- } else {
- FlattrUtils.showNoTokenDialog(context, url);
- }
+ FlattrUtils.showNoTokenDialog(context, "");
}
protected void onFlattrError() {
FlattrUtils.showErrorDialog(context, errorMsg);
}
+
+ protected void onFlattred() {
+ String notificationTitle = context.getString(R.string.flattrd_label);
+ String notificationText = "", notificationSubText = "", notificationBigText = "";
+
+ // text for successfully flattred items
+ if (flattrd.size() == 1)
+ notificationText = String.format(context.getString(R.string.flattr_click_success));
+ else if (flattrd.size() > 1) // flattred pending items from queue
+ notificationText = String.format(context.getString(R.string.flattr_click_success_count, flattrd.size()));
+
+ if (flattrd.size() > 0) {
+ String acc = "";
+ for (String s: flattrd)
+ acc += s + '\n';
+ acc = acc.substring(0, acc.length()-2);
+
+ notificationBigText = String.format(context.getString(R.string.flattr_click_success_queue), acc);
+ }
+
+ // add text for failures
+ if (flattr_failed.size() > 0) {
+ notificationTitle = context.getString(R.string.flattrd_failed_label);
+ notificationText = String.format(context.getString(R.string.flattr_click_failure_count), flattr_failed.size())
+ + " " + notificationText;
+
+ notificationSubText = flattr_failed.get(0);
+
+ String acc = "";
+ for (String s: flattr_failed)
+ acc += s + '\n';
+ acc = acc.substring(0, acc.length()-2);
+
+ notificationBigText = String.format(context.getString(R.string.flattr_click_failure), acc)
+ + "\n" + notificationBigText;
+ }
+
+ Log.d(TAG, "Going to post notification: " + notificationBigText);
- protected void onSuccess() {
- Toast toast = Toast.makeText(context.getApplicationContext(),
- R.string.flattr_click_success, Toast.LENGTH_LONG);
- toast.show();
+ notificationManager.cancel(NOTIFICATION_ID);
+
+ if (run_mode == FLATTR_NOTIFICATION || flattr_failed.size() > 0)
+ {
+ if (android.os.Build.VERSION.SDK_INT >= 16) {
+ notificationBuilder = new Notification.BigTextStyle(
+ new Notification.Builder(context)
+ .setOngoing(false)
+ .setContentTitle(notificationTitle)
+ .setContentText(notificationText)
+ .setSubText(notificationSubText)
+ .setSmallIcon(R.drawable.stat_notify_sync))
+ .bigText(notificationText + "\n" + notificationBigText);
+ notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
+ }
+ else
+ {
+ notificationCompatBuilder = new NotificationCompat.Builder(context) // need new notificationBuilder and cancel/renotify to get rid of progress bar
+ .setContentTitle(notificationTitle)
+ .setContentText(notificationText)
+ .setSubText(notificationBigText)
+ .setTicker(notificationTitle)
+ .setSmallIcon(R.drawable.stat_notify_sync)
+ .setOngoing(false);
+ notificationManager.notify(NOTIFICATION_ID, notificationCompatBuilder.build());
+ }
+ }
+ else if (run_mode == FLATTR_TOAST)
+ {
+ Toast.makeText(context.getApplicationContext(),
+ notificationText,
+ Toast.LENGTH_LONG)
+ .show();
+ }
+ }
+
+ protected void onEnqueue() {
+ Toast.makeText(context.getApplicationContext(),
+ R.string.flattr_click_enqueued,
+ Toast.LENGTH_LONG)
+ .show();
}
- protected void onSetupProgDialog() {
- progDialog = new ProgressDialog(context);
- progDialog.setMessage(context.getString(R.string.flattring_label));
- progDialog.setIndeterminate(true);
- progDialog.setCancelable(false);
- progDialog.show();
+ protected void onSetupNotification() {
+ if (android.os.Build.VERSION.SDK_INT >= 16) {
+ notificationBuilder = new Notification.BigTextStyle(
+ new Notification.Builder(context)
+ .setContentTitle(context.getString(R.string.flattring_label))
+ .setAutoCancel(true)
+ .setSmallIcon(R.drawable.stat_notify_sync)
+ .setProgress(0, 0, true)
+ .setOngoing(true));
+ }
+ else {
+ notificationCompatBuilder = new NotificationCompat.Builder(context)
+ .setContentTitle(context.getString(R.string.flattring_label))
+ .setAutoCancel(true)
+ .setSmallIcon(R.drawable.stat_notify_sync)
+ .setProgress(0, 0, true)
+ .setOngoing(true);
+ }
+
+ notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
@Override
protected void onPostExecute(Void result) {
if (AppConfig.DEBUG) Log.d(TAG, "Exit code was " + exitCode);
- if (progDialog != null) {
- progDialog.dismiss();
- }
+
switch (exitCode) {
case NO_TOKEN:
+ notificationManager.cancel(NOTIFICATION_ID);
onNoAccessToken();
break;
- case FLATTR_ERROR:
- onFlattrError();
+ case ENQUEUED:
+ onEnqueue();
break;
- case SUCCESS:
- onSuccess();
+ case EXIT_DEFAULT:
+ onFlattred();
+ break;
+ case NO_THINGS: // FlattrClickWorker called automatically somewhere to empty flattr queue
+ notificationManager.cancel(NOTIFICATION_ID);
break;
}
}
@Override
protected void onPreExecute() {
- onSetupProgDialog();
+ onSetupNotification();
}
+ private static boolean haveInternetAccess(Context context) {
+ ConnectivityManager cm =
+ (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ NetworkInfo networkInfo = cm.getActiveNetworkInfo();
+ return (networkInfo != null && networkInfo.isConnectedOrConnecting());
+ }
+
@Override
protected Void doInBackground(Void... params) {
if (AppConfig.DEBUG) Log.d(TAG, "Starting background work");
- if (FlattrUtils.hasToken()) {
- try {
- FlattrUtils.clickUrl(context, url);
- } catch (FlattrException e) {
- e.printStackTrace();
- exitCode = FLATTR_ERROR;
- errorMsg = e.getMessage();
- }
- } else {
+
+ exitCode = EXIT_DEFAULT;
+
+ if (!FlattrUtils.hasToken()) {
exitCode = NO_TOKEN;
}
+ else if (DBReader.getFlattrQueueEmpty(context) && extra_flattr_thing == null) {
+ exitCode = NO_THINGS;
+ }
+ else if (!haveInternetAccess(context) || run_mode == ENQUEUE_ONLY) {
+ exitCode = ENQUEUED;
+ }
+ else {
+ List<FlattrThing> flattrList = DBReader.getFlattrQueue(context);
+ Log.d(TAG, "flattrQueue processing list with " + flattrList.size() + " items.");
+
+ if (extra_flattr_thing != null)
+ flattrList.add(extra_flattr_thing);
+
+ flattrd.ensureCapacity(flattrList.size());
+
+ for (FlattrThing thing: flattrList) {
+ try {
+ Log.d(TAG, "flattrQueue processing " + thing.getTitle() + " " + thing.getPaymentLink());
+ publishProgress(String.format(context.getString(R.string.flattring_thing), thing.getTitle()));
+
+ thing.getFlattrStatus().setUnflattred(); // pop from queue to prevent unflattrable things from getting stuck in flattr queue infinitely
+
+ FlattrUtils.clickUrl(context, thing.getPaymentLink());
+ flattrd.add(thing.getTitle());
+
+ thing.getFlattrStatus().setFlattred();
+ }
+ catch (Exception e) {
+ Log.d(TAG, "flattrQueue processing exception at item " + thing.getTitle() + " " + e.getMessage());
+ flattr_failed.ensureCapacity(flattrList.size());
+ flattr_failed.add(thing.getTitle() + ": " + e.getMessage());
+ }
+ Log.d(TAG, "flattrQueue processing - going to write thing back to db with flattr_status " + Long.toString(thing.getFlattrStatus().toLong()));
+ DBWriter.setFlattredStatus(context, thing, false);
+ }
+
+ }
+
return null;
}
-
+
+ @Override
+ protected void onProgressUpdate(String... names) {
+ if (android.os.Build.VERSION.SDK_INT >= 16) {
+ notificationBuilder.setBigContentTitle(names[0]);
+ notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
+ }
+ else {
+ notificationCompatBuilder.setContentText(names[0]);
+ notificationManager.notify(NOTIFICATION_ID, notificationCompatBuilder.build());
+ }
+ }
+
@SuppressLint("NewApi")
public void executeAsync() {
FlattrUtils.hasToken();
@@ -112,4 +315,16 @@ public class FlattrClickWorker extends AsyncTask<Void, Void, Void> {
}
}
+ public void executeSync() {
+ class DirectExecutor implements Executor {
+ public void execute(Runnable r) {
+ r.run();
+ }
+ }
+ FlattrUtils.hasToken();
+ executeOnExecutor(new DirectExecutor());
+
+ }
+
+
}
diff --git a/src/de/danoeh/antennapod/asynctask/FlattrStatusFetcher.java b/src/de/danoeh/antennapod/asynctask/FlattrStatusFetcher.java
new file mode 100644
index 000000000..4974c6b56
--- /dev/null
+++ b/src/de/danoeh/antennapod/asynctask/FlattrStatusFetcher.java
@@ -0,0 +1,47 @@
+package de.danoeh.antennapod.asynctask;
+
+import android.content.Context;
+import android.util.Log;
+import de.danoeh.antennapod.AppConfig;
+import de.danoeh.antennapod.storage.DBWriter;
+import de.danoeh.antennapod.util.flattr.FlattrUtils;
+import org.shredzone.flattr4j.exception.FlattrException;
+import org.shredzone.flattr4j.model.Flattr;
+
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Fetch list of flattred things and flattr status in database in a background thread.
+ */
+
+public class FlattrStatusFetcher extends Thread {
+ protected static final String TAG = "FlattrStatusFetcher";
+ protected Context context;
+
+ public FlattrStatusFetcher(Context context) {
+ super();
+ this.context = context;
+ }
+
+ @Override
+ public void run() {
+ if (AppConfig.DEBUG) Log.d(TAG, "Starting background work: Retrieving Flattr status");
+
+ Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
+
+ try {
+ List<Flattr> flattredThings = FlattrUtils.retrieveFlattredThings();
+ DBWriter.setFlattredStatus(context, flattredThings).get();
+ } catch (FlattrException e) {
+ e.printStackTrace();
+ Log.d(TAG, "flattrQueue exception retrieving list with flattred items " + e.getMessage());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+
+ if (AppConfig.DEBUG) Log.d(TAG, "Finished background work: Retrieved Flattr status");
+ }
+}
diff --git a/src/de/danoeh/antennapod/feed/Feed.java b/src/de/danoeh/antennapod/feed/Feed.java
index a99213dc7..994446f43 100644
--- a/src/de/danoeh/antennapod/feed/Feed.java
+++ b/src/de/danoeh/antennapod/feed/Feed.java
@@ -10,13 +10,15 @@ import java.util.List;
import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.storage.DBWriter;
import de.danoeh.antennapod.util.EpisodeFilter;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
+import de.danoeh.antennapod.util.flattr.FlattrThing;
/**
* Data Object for a whole feed
*
* @author daniel
*/
-public class Feed extends FeedFile {
+public class Feed extends FeedFile implements FlattrThing {
public static final int FEEDFILETYPE_FEED = 0;
public static final String TYPE_RSS2 = "rss";
public static final String TYPE_RSS091 = "rss";
@@ -43,6 +45,7 @@ public class Feed extends FeedFile {
* Date of last refresh.
*/
private Date lastUpdate;
+ private FlattrStatus flattrStatus;
private String paymentLink;
/**
* Feed type, for example RSS 2 or Atom
@@ -59,7 +62,7 @@ public class Feed extends FeedFile {
*/
public Feed(long id, Date lastUpdate, String title, String link, String description, String paymentLink,
String author, String language, String type, String feedIdentifier, FeedImage image, String fileUrl,
- String downloadUrl, boolean downloaded) {
+ String downloadUrl, boolean downloaded, FlattrStatus status) {
super(fileUrl, downloadUrl, downloaded);
this.id = id;
this.title = title;
@@ -76,17 +79,29 @@ public class Feed extends FeedFile {
this.type = type;
this.feedIdentifier = feedIdentifier;
this.image = image;
+ this.flattrStatus = status;
items = new ArrayList<FeedItem>();
}
/**
+ * This constructor is used for test purposes and uses a default flattr status object.
+ */
+ public Feed(long id, Date lastUpdate, String title, String link, String description, String paymentLink,
+ String author, String language, String type, String feedIdentifier, FeedImage image, String fileUrl,
+ String downloadUrl, boolean downloaded) {
+ this(id, lastUpdate, title, link, description, paymentLink, author, language, type, feedIdentifier, image,
+ fileUrl, downloadUrl, downloaded, new FlattrStatus());
+ }
+
+ /**
* This constructor can be used when parsing feed data. Only the 'lastUpdate' and 'items' field are initialized.
*/
public Feed() {
super();
items = new ArrayList<FeedItem>();
lastUpdate = new Date();
+ this.flattrStatus = new FlattrStatus();
}
/**
@@ -96,6 +111,7 @@ public class Feed extends FeedFile {
public Feed(String url, Date lastUpdate) {
super(null, url, false);
this.lastUpdate = (lastUpdate != null) ? (Date) lastUpdate.clone() : null;
+ this.flattrStatus = new FlattrStatus();
}
/**
@@ -105,6 +121,7 @@ public class Feed extends FeedFile {
public Feed(String url, Date lastUpdate, String title) {
this(url, lastUpdate);
this.title = title;
+ this.flattrStatus = new FlattrStatus();
}
/**
@@ -238,6 +255,9 @@ public class Feed extends FeedFile {
if (other.paymentLink != null) {
paymentLink = other.paymentLink;
}
+ if (other.flattrStatus != null) {
+ flattrStatus = other.flattrStatus;
+ }
}
public boolean compareWithOther(Feed other) {
@@ -342,6 +362,14 @@ public class Feed extends FeedFile {
this.feedIdentifier = feedIdentifier;
}
+ public void setFlattrStatus(FlattrStatus status) {
+ this.flattrStatus = status;
+ }
+
+ public FlattrStatus getFlattrStatus() {
+ return flattrStatus;
+ }
+
public String getPaymentLink() {
return paymentLink;
}
diff --git a/src/de/danoeh/antennapod/feed/FeedItem.java b/src/de/danoeh/antennapod/feed/FeedItem.java
index 9b9375f2e..eaae6ae5e 100644
--- a/src/de/danoeh/antennapod/feed/FeedItem.java
+++ b/src/de/danoeh/antennapod/feed/FeedItem.java
@@ -10,6 +10,8 @@ import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.asynctask.ImageLoader;
import de.danoeh.antennapod.storage.DBReader;
import de.danoeh.antennapod.util.ShownotesProvider;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
+import de.danoeh.antennapod.util.flattr.FlattrThing;
/**
* Data Object for a XML message
@@ -17,7 +19,7 @@ import de.danoeh.antennapod.util.ShownotesProvider;
* @author daniel
*/
public class FeedItem extends FeedComponent implements
- ImageLoader.ImageWorkerTaskResource, ShownotesProvider {
+ ImageLoader.ImageWorkerTaskResource, ShownotesProvider, FlattrThing {
/**
* The id/guid that can be found in the rss/atom feed. Might not be set.
@@ -42,10 +44,12 @@ public class FeedItem extends FeedComponent implements
private boolean read;
private String paymentLink;
+ private FlattrStatus flattrStatus;
private List<Chapter> chapters;
public FeedItem() {
this.read = true;
+ this.flattrStatus = new FlattrStatus();
}
/**
@@ -59,6 +63,7 @@ public class FeedItem extends FeedComponent implements
this.pubDate = (pubDate != null) ? (Date) pubDate.clone() : null;
this.read = read;
this.feed = feed;
+ this.flattrStatus = new FlattrStatus();
}
public void updateFromOther(FeedItem other) {
@@ -195,7 +200,15 @@ public class FeedItem extends FeedComponent implements
this.contentEncoded = contentEncoded;
}
- public String getPaymentLink() {
+ public void setFlattrStatus(FlattrStatus status) {
+ this.flattrStatus = status;
+ }
+
+ public FlattrStatus getFlattrStatus() {
+ return flattrStatus;
+ }
+
+ public String getPaymentLink() {
return paymentLink;
}
diff --git a/src/de/danoeh/antennapod/feed/FeedMedia.java b/src/de/danoeh/antennapod/feed/FeedMedia.java
index 492867983..81cae8507 100644
--- a/src/de/danoeh/antennapod/feed/FeedMedia.java
+++ b/src/de/danoeh/antennapod/feed/FeedMedia.java
@@ -10,14 +10,17 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.preferences.PlaybackPreferences;
import de.danoeh.antennapod.storage.DBReader;
import de.danoeh.antennapod.storage.DBWriter;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.util.ChapterUtils;
import de.danoeh.antennapod.util.playback.Playable;
public class FeedMedia extends FeedFile implements Playable {
+ private static final String TAG = "FeedMedia";
public static final int FEEDFILETYPE_FEEDMEDIA = 2;
public static final int PLAYABLE_TYPE_FEEDMEDIA = 1;
@@ -27,6 +30,7 @@ public class FeedMedia extends FeedFile implements Playable {
private int duration;
private int position; // Current position in file
+ private int played_duration; // How many ms of this file have been played (for autoflattring)
private long size; // File size in Byte
private String mime_type;
private volatile FeedItem item;
@@ -45,12 +49,13 @@ public class FeedMedia extends FeedFile implements Playable {
public FeedMedia(long id, FeedItem item, int duration, int position,
long size, String mime_type, String file_url, String download_url,
- boolean downloaded, Date playbackCompletionDate) {
+ boolean downloaded, Date playbackCompletionDate, int played_duration) {
super(file_url, download_url, downloaded);
this.id = id;
this.item = item;
this.duration = duration;
this.position = position;
+ this.played_duration = played_duration;
this.size = size;
this.mime_type = mime_type;
this.playbackCompletionDate = playbackCompletionDate == null
@@ -137,12 +142,24 @@ public class FeedMedia extends FeedFile implements Playable {
this.duration = duration;
}
- public int getPosition() {
+ public int getPlayedDuration() {
+ return played_duration;
+ }
+
+ public void setPlayedDuration(int played_duration) {
+ this.played_duration = played_duration;
+ }
+
+ public int getPosition() {
return position;
}
public void setPosition(int position) {
- this.position = position;
+ final int WAITING_INTERVAL = 5000;
+ if (position > this.position)
+ played_duration += Math.min(position - this.position, 1.1*WAITING_INTERVAL);
+
+ this.position = position;
}
public long getSize() {
@@ -215,6 +232,7 @@ public class FeedMedia extends FeedFile implements Playable {
dest.writeString(download_url);
dest.writeByte((byte) ((downloaded) ? 1 : 0));
dest.writeLong((playbackCompletionDate != null) ? playbackCompletionDate.getTime() : 0);
+ dest.writeInt(played_duration);
}
@Override
@@ -313,8 +331,8 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public void saveCurrentPosition(SharedPreferences pref, int newPosition) {
- position = newPosition;
- DBWriter.setFeedMediaPlaybackInformation(PodcastApp.getInstance(), this);
+ setPosition(newPosition);
+ DBWriter.setFeedMediaPlaybackInformation(PodcastApp.getInstance(), this);
}
@Override
@@ -358,7 +376,7 @@ public class FeedMedia extends FeedFile implements Playable {
final long id = in.readLong();
final long itemID = in.readLong();
FeedMedia result = new FeedMedia(id, null, in.readInt(), in.readInt(), in.readLong(), in.readString(), in.readString(),
- in.readString(), in.readByte() != 0, new Date(in.readLong()));
+ in.readString(), in.readByte() != 0, new Date(in.readLong()), in.readInt());
result.itemID = itemID;
return result;
}
diff --git a/src/de/danoeh/antennapod/preferences/UserPreferences.java b/src/de/danoeh/antennapod/preferences/UserPreferences.java
index 69714c6a8..2b4b66362 100644
--- a/src/de/danoeh/antennapod/preferences/UserPreferences.java
+++ b/src/de/danoeh/antennapod/preferences/UserPreferences.java
@@ -40,6 +40,7 @@ public class UserPreferences implements
public static final String PREF_MOBILE_UPDATE = "prefMobileUpdate";
public static final String PREF_DISPLAY_ONLY_EPISODES = "prefDisplayOnlyEpisodes";
public static final String PREF_AUTO_DELETE = "prefAutoDelete";
+ public static final String PREF_AUTO_FLATTR = "pref_auto_flattr";
public static final String PREF_THEME = "prefTheme";
public static final String PREF_DATA_FOLDER = "prefDataFolder";
public static final String PREF_ENABLE_AUTODL = "prefEnableAutoDl";
@@ -50,6 +51,9 @@ public class UserPreferences implements
private static final String PREF_PLAYBACK_SPEED_ARRAY = "prefPlaybackSpeedArray";
public static final String PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS = "prefPauseForFocusLoss";
+ // TODO: Make this value configurable
+ private static final double PLAYED_DURATION_AUTOFLATTR_THRESHOLD = 0.8;
+
private static int EPISODE_CACHE_SIZE_UNLIMITED = -1;
private static UserPreferences instance;
@@ -63,6 +67,7 @@ public class UserPreferences implements
private boolean allowMobileUpdate;
private boolean displayOnlyEpisodes;
private boolean autoDelete;
+ private boolean autoFlattr;
private int theme;
private boolean enableAutodownload;
private boolean enableAutodownloadWifiFilter;
@@ -112,6 +117,7 @@ public class UserPreferences implements
allowMobileUpdate = sp.getBoolean(PREF_MOBILE_UPDATE, false);
displayOnlyEpisodes = sp.getBoolean(PREF_DISPLAY_ONLY_EPISODES, false);
autoDelete = sp.getBoolean(PREF_AUTO_DELETE, false);
+ autoFlattr = sp.getBoolean(PREF_AUTO_FLATTR, false);
theme = readThemeValue(sp.getString(PREF_THEME, "0"));
enableAutodownloadWifiFilter = sp.getBoolean(
PREF_ENABLE_AUTODL_WIFI_FILTER, false);
@@ -223,6 +229,11 @@ public class UserPreferences implements
instanceAvailable();
return instance.autoDelete;
}
+
+ public static boolean isAutoFlattr() {
+ instanceAvailable();
+ return instance.autoFlattr;
+ }
public static int getTheme() {
instanceAvailable();
@@ -296,6 +307,8 @@ public class UserPreferences implements
} else if (key.equals(PREF_AUTO_DELETE)) {
autoDelete = sp.getBoolean(PREF_AUTO_DELETE, false);
+ } else if (key.equals(PREF_AUTO_FLATTR)) {
+ autoFlattr = sp.getBoolean(PREF_AUTO_FLATTR, false);
} else if (key.equals(PREF_DISPLAY_ONLY_EPISODES)) {
displayOnlyEpisodes = sp.getBoolean(PREF_DISPLAY_ONLY_EPISODES,
false);
@@ -508,4 +521,9 @@ public class UserPreferences implements
instanceAvailable();
return instance.readEpisodeCacheSizeInternal(valueFromPrefs);
}
+
+ public static double getPlayedDurationAutoflattrThreshold() {
+ instanceAvailable();
+ return PLAYED_DURATION_AUTOFLATTR_THRESHOLD;
+ }
}
diff --git a/src/de/danoeh/antennapod/service/playback/PlaybackService.java b/src/de/danoeh/antennapod/service/playback/PlaybackService.java
index 211d67532..132932c93 100644
--- a/src/de/danoeh/antennapod/service/playback/PlaybackService.java
+++ b/src/de/danoeh/antennapod/service/playback/PlaybackService.java
@@ -23,6 +23,7 @@ import android.util.Pair;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import de.danoeh.antennapod.AppConfig;
+import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.AudioplayerActivity;
import de.danoeh.antennapod.activity.VideoplayerActivity;
@@ -38,6 +39,7 @@ import de.danoeh.antennapod.storage.DBTasks;
import de.danoeh.antennapod.storage.DBWriter;
import de.danoeh.antennapod.util.BitmapDecoder;
import de.danoeh.antennapod.util.QueueAccess;
+import de.danoeh.antennapod.util.flattr.FlattrUtils;
import de.danoeh.antennapod.util.playback.Playable;
import de.danoeh.antennapod.util.playback.PlaybackController;
@@ -344,7 +346,7 @@ public class PlaybackService extends Service {
private final PlaybackServiceTaskManager.PSTMCallback taskManagerCallback = new PlaybackServiceTaskManager.PSTMCallback() {
@Override
public void positionSaverTick() {
- saveCurrentPosition();
+ saveCurrentPosition(true, PlaybackServiceTaskManager.POSITION_SAVER_WAITING_INTERVAL);
}
@Override
@@ -380,7 +382,7 @@ public class PlaybackService extends Service {
case PAUSED:
taskManager.cancelPositionSaver();
- saveCurrentPosition();
+ saveCurrentPosition(false, 0);
taskManager.cancelWidgetUpdater();
stopForeground(true);
break;
@@ -714,13 +716,32 @@ public class PlaybackService extends Service {
/**
* Saves the current position of the media file to the DB
+ *
+ * @param updatePlayedDuration true if played_duration should be updated. This applies only to FeedMedia objects
+ * @param deltaPlayedDuration value by which played_duration should be increased.
*/
- private synchronized void saveCurrentPosition() {
+ private synchronized void saveCurrentPosition(boolean updatePlayedDuration, int deltaPlayedDuration) {
int position = getCurrentPosition();
+ int duration = getDuration();
final Playable playable = mediaPlayer.getPSMPInfo().playable;
- if (position != INVALID_TIME && playable != null) {
+ if (position != INVALID_TIME && duration != INVALID_TIME && playable != null) {
if (AppConfig.DEBUG)
Log.d(TAG, "Saving current position to " + position);
+ if (updatePlayedDuration && playable instanceof FeedMedia) {
+ FeedMedia m = (FeedMedia) playable;
+ FeedItem item = m.getItem();
+ m.setPlayedDuration(m.getPlayedDuration() + deltaPlayedDuration);
+ // Auto flattr
+ if (FlattrUtils.hasToken() && UserPreferences.isAutoFlattr() && item.getPaymentLink() != null && item.getFlattrStatus().getUnflattred() &&
+ (m.getPlayedDuration() > UserPreferences.getPlayedDurationAutoflattrThreshold() * duration)) {
+
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "saveCurrentPosition: performing auto flattr since played duration " + Integer.toString(m.getPlayedDuration())
+ + " is " + UserPreferences.getPlayedDurationAutoflattrThreshold() * 100 + "% of file duration " + Integer.toString(duration));
+ item.getFlattrStatus().setFlattrQueue();
+ DBWriter.setFeedItemFlattrStatus(PodcastApp.getInstance(), item, false);
+ }
+ }
playable.saveCurrentPosition(PreferenceManager
.getDefaultSharedPreferences(getApplicationContext()),
position);
diff --git a/src/de/danoeh/antennapod/storage/DBReader.java b/src/de/danoeh/antennapod/storage/DBReader.java
index d950747e6..ccbf6646f 100644
--- a/src/de/danoeh/antennapod/storage/DBReader.java
+++ b/src/de/danoeh/antennapod/storage/DBReader.java
@@ -1,22 +1,24 @@
package de.danoeh.antennapod.storage;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.util.Log;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.feed.*;
-import de.danoeh.antennapod.service.download.*;
+import de.danoeh.antennapod.service.download.DownloadStatus;
import de.danoeh.antennapod.util.DownloadError;
import de.danoeh.antennapod.util.comparator.DownloadStatusComparator;
import de.danoeh.antennapod.util.comparator.FeedItemPubdateComparator;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
+import de.danoeh.antennapod.util.flattr.FlattrThing;
import de.danoeh.antennapod.util.comparator.PlaybackCompletionDateComparator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
/**
* Provides methods for reading data from the AntennaPod database.
* In general, all database calls in DBReader-methods are executed on the caller's thread.
@@ -124,6 +126,7 @@ public final class DBReader {
* Takes a list of FeedItems and loads their corresponding Feed-objects from the database.
* The feedID-attribute of a FeedItem must be set to the ID of its feed or the method will
* not find the correct feed of an item.
+ *
* @param context A context that is used for opening a database connection.
* @param items The FeedItems whose Feed-objects should be loaded.
*/
@@ -211,7 +214,9 @@ public final class DBReader {
.getInt(PodDBAdapter.IDX_FI_SMALL_READ) > 0));
item.setItemIdentifier(itemlistCursor
.getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER));
-
+ item.setFlattrStatus(new FlattrStatus(itemlistCursor
+ .getLong(PodDBAdapter.IDX_FI_SMALL_FLATTR_STATUS)));
+
// extract chapters
boolean hasSimpleChapters = itemlistCursor
.getInt(PodDBAdapter.IDX_FI_SMALL_HAS_CHAPTERS) > 0;
@@ -302,7 +307,8 @@ public final class DBReader {
cursor.getString(PodDBAdapter.KEY_FILE_URL_INDEX),
cursor.getString(PodDBAdapter.KEY_DOWNLOAD_URL_INDEX),
cursor.getInt(PodDBAdapter.KEY_DOWNLOADED_INDEX) > 0,
- playbackCompletionDate);
+ playbackCompletionDate,
+ cursor.getInt(PodDBAdapter.KEY_PLAYED_DURATION_INDEX));
}
private static Feed extractFeedFromCursorRow(PodDBAdapter adapter,
@@ -330,7 +336,8 @@ public final class DBReader {
image,
cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_FILE_URL),
cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_DOWNLOAD_URL),
- cursor.getInt(PodDBAdapter.IDX_FEED_SEL_STD_DOWNLOADED) > 0);
+ cursor.getInt(PodDBAdapter.IDX_FEED_SEL_STD_DOWNLOADED) > 0,
+ new FlattrStatus(cursor.getLong(PodDBAdapter.IDX_FEED_SEL_STD_FLATTR_STATUS)));
if (image != null) {
image.setFeed(feed);
@@ -776,4 +783,48 @@ public final class DBReader {
return media;
}
+
+ /**
+ * Returns the flattr queue as a List of FlattrThings. The list consists of Feeds and FeedItems.
+ *
+ * @param context A context that is used for opening a database connection.
+ * @return The flattr queue as a List.
+ */
+ public static List<FlattrThing> getFlattrQueue(Context context) {
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+ List<FlattrThing> result = new ArrayList<FlattrThing>();
+
+ // load feeds
+ Cursor feedCursor = adapter.getFeedsInFlattrQueueCursor();
+ if (feedCursor.moveToFirst()) {
+ do {
+ result.add(extractFeedFromCursorRow(adapter, feedCursor));
+ } while (feedCursor.moveToNext());
+ }
+ feedCursor.close();
+
+ //load feed items
+ Cursor feedItemCursor = adapter.getFeedItemsInFlattrQueueCursor();
+ result.addAll(extractItemlistFromCursor(adapter, feedItemCursor));
+ feedItemCursor.close();
+
+ adapter.close();
+ Log.d(TAG, "Returning flattrQueueIterator for queue with " + result.size() + " items.");
+ return result;
+ }
+
+
+ /**
+ * Returns true if the flattr queue is empty.
+ *
+ * @param context A context that is used for opening a database connection.
+ */
+ public static boolean getFlattrQueueEmpty(Context context) {
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+ boolean empty = adapter.getFlattrQueueSize() == 0;
+ adapter.close();
+ return empty;
+ }
}
diff --git a/src/de/danoeh/antennapod/storage/DBTasks.java b/src/de/danoeh/antennapod/storage/DBTasks.java
index 3b6ab99ce..c6a0dad17 100644
--- a/src/de/danoeh/antennapod/storage/DBTasks.java
+++ b/src/de/danoeh/antennapod/storage/DBTasks.java
@@ -4,6 +4,8 @@ import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.util.Log;
+import de.danoeh.antennapod.asynctask.FlattrClickWorker;
+import de.danoeh.antennapod.asynctask.FlattrStatusFetcher;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.feed.*;
import de.danoeh.antennapod.preferences.UserPreferences;
@@ -151,6 +153,12 @@ public final class DBTasks {
}
isRefreshing.set(false);
+ if (AppConfig.DEBUG) Log.d(TAG, "Flattring all pending things.");
+ new FlattrClickWorker(context, FlattrClickWorker.FLATTR_NOTIFICATION).executeSync(); // flattr pending things
+
+ if (AppConfig.DEBUG) Log.d(TAG, "Fetching flattr status.");
+ new FlattrStatusFetcher(context).start();
+
GpodnetSyncService.sendSyncIntent(context);
autodownloadUndownloadedItems(context);
}
diff --git a/src/de/danoeh/antennapod/storage/DBWriter.java b/src/de/danoeh/antennapod/storage/DBWriter.java
index db498efb5..444e9ea0c 100644
--- a/src/de/danoeh/antennapod/storage/DBWriter.java
+++ b/src/de/danoeh/antennapod/storage/DBWriter.java
@@ -1,15 +1,5 @@
package de.danoeh.antennapod.storage;
-import java.io.File;
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.ThreadFactory;
-
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -17,12 +7,29 @@ import android.database.Cursor;
import android.preference.PreferenceManager;
import android.util.Log;
import de.danoeh.antennapod.AppConfig;
+import de.danoeh.antennapod.asynctask.FlattrClickWorker;
import de.danoeh.antennapod.feed.*;
import de.danoeh.antennapod.preferences.GpodnetPreferences;
import de.danoeh.antennapod.preferences.PlaybackPreferences;
-import de.danoeh.antennapod.service.playback.PlaybackService;
import de.danoeh.antennapod.service.download.DownloadStatus;
+import de.danoeh.antennapod.service.playback.PlaybackService;
import de.danoeh.antennapod.util.QueueAccess;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
+import de.danoeh.antennapod.util.flattr.FlattrThing;
+import de.danoeh.antennapod.util.flattr.SimpleFlattrThing;
+import org.shredzone.flattr4j.model.Flattr;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadFactory;
/**
* Provides methods for writing data to AntennaPod's database.
@@ -221,6 +228,9 @@ public class DBWriter {
if (AppConfig.DEBUG)
Log.d(TAG, "Adding new item to playback history");
media.setPlaybackCompletionDate(new Date());
+ // reset played_duration to 0 so that it behaves correctly when the episode is played again
+ media.setPlayedDuration(0);
+
PodDBAdapter adapter = new PodDBAdapter(context);
adapter.open();
adapter.setFeedMediaPlaybackCompletionDate(media);
@@ -445,7 +455,7 @@ public class DBWriter {
});
}
-
+
/**
* Moves the specified item to the top of the queue.
*
@@ -471,7 +481,7 @@ public class DBWriter {
}
});
}
-
+
/**
* Moves the specified item to the bottom of the queue.
*
@@ -490,7 +500,7 @@ public class DBWriter {
for (long id : queueIdList) {
if (id == itemId) {
moveQueueItemHelper(context, currentLocation, queueIdList.size() - 1,
- broadcastUpdate);
+ broadcastUpdate);
return;
}
currentLocation++;
@@ -499,7 +509,7 @@ public class DBWriter {
}
});
}
-
+
/**
* Changes the position of a FeedItem in the queue.
*
@@ -523,7 +533,7 @@ public class DBWriter {
/**
* Changes the position of a FeedItem in the queue.
- *
+ * <p/>
* This function must be run using the ExecutorService (dbExec).
*
* @param context A context that is used for opening a database connection.
@@ -534,7 +544,7 @@ public class DBWriter {
* @throws IndexOutOfBoundsException if (to < 0 || to >= queue.size()) || (from < 0 || from >= queue.size())
*/
private static void moveQueueItemHelper(final Context context, final int from,
- final int to, final boolean broadcastUpdate) {
+ final int to, final boolean broadcastUpdate) {
final PodDBAdapter adapter = new PodDBAdapter(context);
adapter.open();
final List<FeedItem> queue = DBReader
@@ -822,4 +832,125 @@ public class DBWriter {
}
return false;
}
+
+ /**
+ * Saves the FlattrStatus of a FeedItem object in the database.
+ *
+ * @param startFlattrClickWorker true if FlattrClickWorker should be started after the FlattrStatus has been saved
+ */
+ public static Future<?> setFeedItemFlattrStatus(final Context context,
+ final FeedItem item,
+ final boolean startFlattrClickWorker) {
+ return dbExec.submit(new Runnable() {
+
+ @Override
+ public void run() {
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+ adapter.setFeedItemFlattrStatus(item);
+ adapter.close();
+ if (startFlattrClickWorker) {
+ new FlattrClickWorker(context, FlattrClickWorker.FLATTR_TOAST).executeAsync();
+ }
+ }
+ });
+ }
+
+ /**
+ * Saves the FlattrStatus of a Feed object in the database.
+ *
+ * @param startFlattrClickWorker true if FlattrClickWorker should be started after the FlattrStatus has been saved
+ */
+ private static Future<?> setFeedFlattrStatus(final Context context,
+ final Feed feed,
+ final boolean startFlattrClickWorker) {
+ return dbExec.submit(new Runnable() {
+
+ @Override
+ public void run() {
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+ adapter.setFeedFlattrStatus(feed);
+ adapter.close();
+ if (startFlattrClickWorker) {
+ new FlattrClickWorker(context, FlattrClickWorker.FLATTR_TOAST).executeAsync();
+ }
+ }
+ });
+ }
+
+ /**
+ * format an url for querying the database
+ * (postfix a / and apply percent-encoding)
+ */
+ private static String formatURIForQuery(String uri) {
+ try {
+ return URLEncoder.encode(uri.endsWith("/") ? uri.substring(0, uri.length() - 1) : uri, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ Log.e(TAG, e.getMessage());
+ return "";
+ }
+ }
+
+
+ /**
+ * Set flattr status of the passed thing (either a FeedItem or a Feed)
+ *
+ * @param context
+ * @param thing
+ * @param startFlattrClickWorker true if FlattrClickWorker should be started after the FlattrStatus has been saved
+ * @return
+ */
+ public static Future<?> setFlattredStatus(Context context, FlattrThing thing, boolean startFlattrClickWorker) {
+ // must propagate this to back db
+ if (thing instanceof FeedItem)
+ return setFeedItemFlattrStatus(context, (FeedItem) thing, startFlattrClickWorker);
+ else if (thing instanceof Feed)
+ return setFeedFlattrStatus(context, (Feed) thing, startFlattrClickWorker);
+ else if (thing instanceof SimpleFlattrThing) {
+ } // SimpleFlattrThings are generated on the fly and do not have DB backing
+ else
+ Log.e(TAG, "flattrQueue processing - thing is neither FeedItem nor Feed nor SimpleFlattrThing");
+
+ return null;
+ }
+
+ /**
+ * Reset flattr status to unflattrd for all items
+ */
+ public static Future<?> clearAllFlattrStatus(final Context context) {
+ Log.d(TAG, "clearAllFlattrStatus()");
+ return dbExec.submit(new Runnable() {
+ @Override
+ public void run() {
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+ adapter.clearAllFlattrStatus();
+ adapter.close();
+ }
+ });
+ }
+
+ /**
+ * Set flattr status of the feeds/feeditems in flattrList to flattred at the given timestamp,
+ * where the information has been retrieved from the flattr API
+ */
+ public static Future<?> setFlattredStatus(final Context context, final List<Flattr> flattrList) {
+ Log.d(TAG, "setFlattredStatus to status retrieved from flattr api running with " + flattrList.size() + " items");
+ // clear flattr status in db
+ clearAllFlattrStatus(context);
+
+ // submit list with flattred things having normalized URLs to db
+ return dbExec.submit(new Runnable() {
+ @Override
+ public void run() {
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+ for (Flattr flattr : flattrList) {
+ adapter.setItemFlattrStatus(formatURIForQuery(flattr.getThing().getUrl()), new FlattrStatus(flattr.getCreated().getTime()));
+ }
+ adapter.close();
+ }
+ });
+ }
}
diff --git a/src/de/danoeh/antennapod/storage/PodDBAdapter.java b/src/de/danoeh/antennapod/storage/PodDBAdapter.java
index 049b78dc0..738ccbf50 100644
--- a/src/de/danoeh/antennapod/storage/PodDBAdapter.java
+++ b/src/de/danoeh/antennapod/storage/PodDBAdapter.java
@@ -1,8 +1,5 @@
package de.danoeh.antennapod.storage;
-import java.util.Arrays;
-import java.util.List;
-
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
@@ -16,6 +13,10 @@ import android.util.Log;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.feed.*;
import de.danoeh.antennapod.service.download.DownloadStatus;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
+
+import java.util.Arrays;
+import java.util.List;
// TODO Remove media column from feeditem table
@@ -24,7 +25,7 @@ import de.danoeh.antennapod.service.download.DownloadStatus;
*/
public class PodDBAdapter {
private static final String TAG = "PodDBAdapter";
- private static final int DATABASE_VERSION = 10;
+ private static final int DATABASE_VERSION = 11;
public static final String DATABASE_NAME = "Antennapod.db";
/**
@@ -54,6 +55,7 @@ public class PodDBAdapter {
public static final int KEY_IMAGE_INDEX = 11;
public static final int KEY_TYPE_INDEX = 12;
public static final int KEY_FEED_IDENTIFIER_INDEX = 13;
+ public static final int KEY_FEED_FLATTR_STATUS_INDEX = 14;
// ----------- FeedItem indices
public static final int KEY_CONTENT_ENCODED_INDEX = 2;
public static final int KEY_PUBDATE_INDEX = 3;
@@ -62,6 +64,7 @@ public class PodDBAdapter {
public static final int KEY_FEED_INDEX = 9;
public static final int KEY_HAS_SIMPLECHAPTERS_INDEX = 10;
public static final int KEY_ITEM_IDENTIFIER_INDEX = 11;
+ public static final int KEY_ITEM_FLATTR_STATUS_INDEX = 12;
// ---------- FeedMedia indices
public static final int KEY_DURATION_INDEX = 1;
public static final int KEY_POSITION_INDEX = 5;
@@ -69,6 +72,7 @@ public class PodDBAdapter {
public static final int KEY_MIME_TYPE_INDEX = 7;
public static final int KEY_PLAYBACK_COMPLETION_DATE_INDEX = 8;
public static final int KEY_MEDIA_FEEDITEM_INDEX = 9;
+ public static final int KEY_PLAYED_DURATION_INDEX = 10;
// --------- Download log indices
public static final int KEY_FEEDFILE_INDEX = 1;
public static final int KEY_FEEDFILETYPE_INDEX = 2;
@@ -119,12 +123,14 @@ public class PodDBAdapter {
public static final String KEY_HAS_CHAPTERS = "has_simple_chapters";
public static final String KEY_TYPE = "type";
public static final String KEY_ITEM_IDENTIFIER = "item_identifier";
+ public static final String KEY_FLATTR_STATUS = "flattr_status";
public static final String KEY_FEED_IDENTIFIER = "feed_identifier";
public static final String KEY_REASON_DETAILED = "reason_detailed";
public static final String KEY_DOWNLOADSTATUS_TITLE = "title";
public static final String KEY_CHAPTER_TYPE = "type";
public static final String KEY_PLAYBACK_COMPLETION_DATE = "playback_completion_date";
public static final String KEY_AUTO_DOWNLOAD = "auto_download";
+ public static final String KEY_PLAYED_DURATION = "played_duration";
// Table names
public static final String TABLE_NAME_FEEDS = "Feeds";
@@ -146,7 +152,8 @@ public class PodDBAdapter {
+ KEY_DESCRIPTION + " TEXT," + KEY_PAYMENT_LINK + " TEXT,"
+ KEY_LASTUPDATE + " TEXT," + KEY_LANGUAGE + " TEXT," + KEY_AUTHOR
+ " TEXT," + KEY_IMAGE + " INTEGER," + KEY_TYPE + " TEXT,"
- + KEY_FEED_IDENTIFIER + " TEXT," + KEY_AUTO_DOWNLOAD + " INTEGER DEFAULT 1)";
+ + KEY_FEED_IDENTIFIER + " TEXT," + KEY_AUTO_DOWNLOAD + " INTEGER DEFAULT 1,"
+ + KEY_FLATTR_STATUS + " INTEGER)";
private static final String CREATE_TABLE_FEED_ITEMS = "CREATE TABLE "
+ TABLE_NAME_FEED_ITEMS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
@@ -154,7 +161,8 @@ public class PodDBAdapter {
+ " INTEGER," + KEY_READ + " INTEGER," + KEY_LINK + " TEXT,"
+ KEY_DESCRIPTION + " TEXT," + KEY_PAYMENT_LINK + " TEXT,"
+ KEY_MEDIA + " INTEGER," + KEY_FEED + " INTEGER,"
- + KEY_HAS_CHAPTERS + " INTEGER," + KEY_ITEM_IDENTIFIER + " TEXT)";
+ + KEY_HAS_CHAPTERS + " INTEGER," + KEY_ITEM_IDENTIFIER + " TEXT,"
+ + KEY_FLATTR_STATUS + " INTEGER)";
private static final String CREATE_TABLE_FEED_IMAGES = "CREATE TABLE "
+ TABLE_NAME_FEED_IMAGES + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
@@ -167,7 +175,8 @@ public class PodDBAdapter {
+ " TEXT," + KEY_DOWNLOADED + " INTEGER," + KEY_POSITION
+ " INTEGER," + KEY_SIZE + " INTEGER," + KEY_MIME_TYPE + " TEXT,"
+ KEY_PLAYBACK_COMPLETION_DATE + " INTEGER,"
- + KEY_FEEDITEM + " INTEGER)";
+ + KEY_FEEDITEM + " INTEGER,"
+ + KEY_PLAYED_DURATION + " INTEGER)";
private static final String CREATE_TABLE_DOWNLOAD_LOG = "CREATE TABLE "
+ TABLE_NAME_DOWNLOAD_LOG + " (" + TABLE_PRIMARY_KEY + KEY_FEEDFILE
@@ -208,6 +217,7 @@ public class PodDBAdapter {
TABLE_NAME_FEEDS + "." + KEY_TYPE,
TABLE_NAME_FEEDS + "." + KEY_FEED_IDENTIFIER,
TABLE_NAME_FEEDS + "." + KEY_AUTO_DOWNLOAD,
+ TABLE_NAME_FEEDS + "." + KEY_FLATTR_STATUS
};
// column indices for FEED_SEL_STD
@@ -226,6 +236,7 @@ public class PodDBAdapter {
public static final int IDX_FEED_SEL_STD_TYPE = 12;
public static final int IDX_FEED_SEL_STD_FEED_IDENTIFIER = 13;
public static final int IDX_FEED_SEL_PREFERENCES_AUTO_DOWNLOAD = 14;
+ public static final int IDX_FEED_SEL_STD_FLATTR_STATUS = 15;
/**
@@ -241,7 +252,8 @@ public class PodDBAdapter {
TABLE_NAME_FEED_ITEMS + "." + KEY_PAYMENT_LINK, KEY_MEDIA,
TABLE_NAME_FEED_ITEMS + "." + KEY_FEED,
TABLE_NAME_FEED_ITEMS + "." + KEY_HAS_CHAPTERS,
- TABLE_NAME_FEED_ITEMS + "." + KEY_ITEM_IDENTIFIER};
+ TABLE_NAME_FEED_ITEMS + "." + KEY_ITEM_IDENTIFIER,
+ TABLE_NAME_FEED_ITEMS + "." + KEY_FLATTR_STATUS};
/**
* Contains FEEDITEM_SEL_FI_SMALL as comma-separated list. Useful for raw queries.
@@ -265,6 +277,7 @@ public class PodDBAdapter {
public static final int IDX_FI_SMALL_FEED = 7;
public static final int IDX_FI_SMALL_HAS_CHAPTERS = 8;
public static final int IDX_FI_SMALL_ITEM_IDENTIFIER = 9;
+ public static final int IDX_FI_SMALL_FLATTR_STATUS = 10;
/**
* Select id, description and content-encoded column from feeditems.
@@ -346,6 +359,10 @@ public class PodDBAdapter {
values.put(KEY_LASTUPDATE, feed.getLastUpdate().getTime());
values.put(KEY_TYPE, feed.getType());
values.put(KEY_FEED_IDENTIFIER, feed.getFeedIdentifier());
+
+ Log.d(TAG, "Setting feed with flattr status " + feed.getTitle() + ": " + feed.getFlattrStatus().toLong());
+
+ values.put(KEY_FLATTR_STATUS, feed.getFlattrStatus().toLong());
if (feed.getId() == 0) {
// Create new entry
if (AppConfig.DEBUG)
@@ -435,6 +452,7 @@ public class PodDBAdapter {
ContentValues values = new ContentValues();
values.put(KEY_POSITION, media.getPosition());
values.put(KEY_DURATION, media.getDuration());
+ values.put(KEY_PLAYED_DURATION, media.getPlayedDuration());
db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?",
new String[]{String.valueOf(media.getId())});
} else {
@@ -446,6 +464,7 @@ public class PodDBAdapter {
if (media.getId() != 0) {
ContentValues values = new ContentValues();
values.put(KEY_PLAYBACK_COMPLETION_DATE, media.getPlaybackCompletionDate().getTime());
+ values.put(KEY_PLAYED_DURATION, media.getPlayedDuration());
db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?",
new String[]{String.valueOf(media.getId())});
} else {
@@ -470,6 +489,56 @@ public class PodDBAdapter {
}
/**
+ * Update the flattr status of a feed
+ */
+ public void setFeedFlattrStatus(Feed feed) {
+ ContentValues values = new ContentValues();
+ values.put(KEY_FLATTR_STATUS, feed.getFlattrStatus().toLong());
+ db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(feed.getId())});
+ }
+
+ /**
+ * Get all feeds in the flattr queue.
+ */
+ public Cursor getFeedsInFlattrQueueCursor() {
+ return db.query(TABLE_NAME_FEEDS, FEED_SEL_STD, KEY_FLATTR_STATUS + "=?",
+ new String[]{String.valueOf(FlattrStatus.STATUS_QUEUE)},null, null, null);
+ }
+
+ /**
+ * Get all feed items in the flattr queue.
+ */
+ public Cursor getFeedItemsInFlattrQueueCursor() {
+ return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FLATTR_STATUS + "=?",
+ new String[]{String.valueOf(FlattrStatus.STATUS_QUEUE)},null, null, null);
+ }
+
+ /**
+ * Counts feeds and feed items in the flattr queue
+ */
+ public int getFlattrQueueSize() {
+ int res = 0;
+ Cursor c = db.rawQuery(String.format("SELECT count(*) FROM %s WHERE %s=%s",
+ TABLE_NAME_FEEDS, KEY_FLATTR_STATUS, String.valueOf(FlattrStatus.STATUS_QUEUE)), null);
+ if (c.moveToFirst()) {
+ res = c.getInt(0);
+ c.close();
+ } else {
+ Log.e(TAG, "Unable to determine size of flattr queue: Could not count number of feeds");
+ }
+ c = db.rawQuery(String.format("SELECT count(*) FROM %s WHERE %s=%s",
+ TABLE_NAME_FEED_ITEMS, KEY_FLATTR_STATUS, String.valueOf(FlattrStatus.STATUS_QUEUE)), null);
+ if (c.moveToFirst()) {
+ res += c.getInt(0);
+ c.close();
+ } else {
+ Log.e(TAG, "Unable to determine size of flattr queue: Could not count number of feed items");
+ }
+
+ return res;
+ }
+
+ /**
* Updates the download URL of a Feed.
*/
public void setFeedDownloadUrl(String original, String updated) {
@@ -496,6 +565,63 @@ public class PodDBAdapter {
}
/**
+ * Update the flattr status of a FeedItem
+ */
+ public void setFeedItemFlattrStatus(FeedItem feedItem) {
+ ContentValues values = new ContentValues();
+ values.put(KEY_FLATTR_STATUS, feedItem.getFlattrStatus().toLong());
+ db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?", new String[]{String.valueOf(feedItem.getId())});
+ }
+
+ /**
+ * Update the flattr status of a feed or feed item specified by its payment link
+ * and the new flattr status to use
+ */
+ public void setItemFlattrStatus(String url, FlattrStatus status)
+ {
+ //Log.d(TAG, "setItemFlattrStatus(" + url + ") = " + status.toString());
+ ContentValues values = new ContentValues();
+ values.put(KEY_FLATTR_STATUS, status.toLong());
+
+ // regexps in sqlite would be neat!
+ String[] query_urls = new String[]{
+ "*" + url + "&*",
+ "*" + url + "%2F&*",
+ "*" + url + "",
+ "*" + url + "%2F"
+ };
+
+ if (db.update(TABLE_NAME_FEEDS, values,
+ KEY_PAYMENT_LINK + " GLOB ?"
+ + " OR " + KEY_PAYMENT_LINK + " GLOB ?"
+ + " OR " + KEY_PAYMENT_LINK + " GLOB ?"
+ + " OR " + KEY_PAYMENT_LINK + " GLOB ?", query_urls) > 0)
+ {
+ Log.i(TAG, "setItemFlattrStatus found match for " + url + " = " + status.toLong() + " in Feeds table");
+ return;
+ }
+ if (db.update(TABLE_NAME_FEED_ITEMS, values,
+ KEY_PAYMENT_LINK + " GLOB ?"
+ + " OR " + KEY_PAYMENT_LINK + " GLOB ?"
+ + " OR " + KEY_PAYMENT_LINK + " GLOB ?"
+ + " OR " + KEY_PAYMENT_LINK + " GLOB ?", query_urls) > 0)
+ {
+ Log.i(TAG, "setItemFlattrStatus found match for " + url + " = " + status.toLong() + " in FeedsItems table");
+ }
+ }
+
+ /**
+ * Reset flattr status to unflattrd for all items
+ */
+ public void clearAllFlattrStatus()
+ {
+ ContentValues values = new ContentValues();
+ values.put(KEY_FLATTR_STATUS, 0);
+ db.update(TABLE_NAME_FEEDS, values, null, null);
+ db.update(TABLE_NAME_FEED_ITEMS, values, null, null);
+ }
+
+ /**
* Inserts or updates a feeditem entry
*
* @param item The FeedItem
@@ -522,6 +648,7 @@ public class PodDBAdapter {
values.put(KEY_READ, item.isRead());
values.put(KEY_HAS_CHAPTERS, item.getChapters() != null);
values.put(KEY_ITEM_IDENTIFIER, item.getItemIdentifier());
+ values.put(KEY_FLATTR_STATUS, item.getFlattrStatus().toLong());
if (item.getId() == 0) {
item.setId(db.insert(TABLE_NAME_FEED_ITEMS, null, values));
} else {
@@ -1170,6 +1297,17 @@ public class PodDBAdapter {
+ " ADD COLUMN " + KEY_AUTO_DOWNLOAD
+ " INTEGER DEFAULT 1");
}
+ if (oldVersion <= 10) {
+ db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS
+ + " ADD COLUMN " + KEY_FLATTR_STATUS
+ + " INTEGER");
+ db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_ITEMS
+ + " ADD COLUMN " + KEY_FLATTR_STATUS
+ + " INTEGER");
+ db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_MEDIA
+ + " ADD COLUMN " + KEY_PLAYED_DURATION
+ + " INTEGER");
+ }
}
}
}
diff --git a/src/de/danoeh/antennapod/util/flattr/FlattrStatus.java b/src/de/danoeh/antennapod/util/flattr/FlattrStatus.java
new file mode 100644
index 000000000..a1d6d3bc4
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/flattr/FlattrStatus.java
@@ -0,0 +1,68 @@
+package de.danoeh.antennapod.util.flattr;
+
+import java.util.Calendar;
+
+public class FlattrStatus {
+ public static final int STATUS_UNFLATTERED = 0;
+ public static final int STATUS_QUEUE = 1;
+ public static final int STATUS_FLATTRED = 2;
+
+ private int status = STATUS_UNFLATTERED;
+ private Calendar lastFlattred;
+
+ public FlattrStatus() {
+ status = STATUS_UNFLATTERED;
+ lastFlattred = Calendar.getInstance();
+ }
+
+ public FlattrStatus(long status) {
+ lastFlattred = Calendar.getInstance();
+ fromLong(status);
+ }
+
+ public void setFlattred() {
+ status = STATUS_FLATTRED;
+ lastFlattred = Calendar.getInstance();
+ }
+
+ public void setUnflattred() {
+ status = STATUS_UNFLATTERED;
+ }
+
+ public boolean getUnflattred() {
+ return status == STATUS_UNFLATTERED;
+ }
+
+ public void setFlattrQueue() {
+ if (flattrable())
+ status = STATUS_QUEUE;
+ }
+
+ public void fromLong(long status) {
+ if (status == STATUS_UNFLATTERED || status == STATUS_QUEUE)
+ this.status = (int) status;
+ else {
+ this.status = STATUS_FLATTRED;
+ lastFlattred.setTimeInMillis(status);
+ }
+ }
+
+ public long toLong() {
+ if (status == STATUS_UNFLATTERED || status == STATUS_QUEUE)
+ return status;
+ else {
+ return lastFlattred.getTimeInMillis();
+ }
+ }
+
+ public boolean flattrable() {
+ Calendar firstOfMonth = Calendar.getInstance();
+ firstOfMonth.set(Calendar.DAY_OF_MONTH, Calendar.getInstance().getActualMinimum(Calendar.DAY_OF_MONTH));
+
+ return (status == STATUS_UNFLATTERED) || (status == STATUS_FLATTRED && firstOfMonth.after(lastFlattred) );
+ }
+
+ public boolean getFlattrQueue() {
+ return status == STATUS_QUEUE;
+ }
+}
diff --git a/src/de/danoeh/antennapod/util/flattr/FlattrThing.java b/src/de/danoeh/antennapod/util/flattr/FlattrThing.java
new file mode 100644
index 000000000..872132517
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/flattr/FlattrThing.java
@@ -0,0 +1,9 @@
+package de.danoeh.antennapod.util.flattr;
+
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
+
+public interface FlattrThing {
+ public String getTitle();
+ public String getPaymentLink();
+ public FlattrStatus getFlattrStatus();
+}
diff --git a/src/de/danoeh/antennapod/util/flattr/FlattrUtils.java b/src/de/danoeh/antennapod/util/flattr/FlattrUtils.java
index ca2c9eb0f..215e67e55 100644
--- a/src/de/danoeh/antennapod/util/flattr/FlattrUtils.java
+++ b/src/de/danoeh/antennapod/util/flattr/FlattrUtils.java
@@ -1,9 +1,16 @@
package de.danoeh.antennapod.util.flattr;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
import java.util.EnumSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.TimeZone;
import org.shredzone.flattr4j.FlattrService;
import org.shredzone.flattr4j.exception.FlattrException;
+import org.shredzone.flattr4j.model.Flattr;
import org.shredzone.flattr4j.model.Thing;
import org.shredzone.flattr4j.oauth.AccessToken;
import org.shredzone.flattr4j.oauth.AndroidAuthenticator;
@@ -23,6 +30,7 @@ import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.FlattrAuthActivity;
import de.danoeh.antennapod.asynctask.FlattrTokenFetcher;
+import de.danoeh.antennapod.storage.DBWriter;
/** Utility methods for doing something with flattr. */
@@ -119,6 +127,58 @@ public class FlattrUtils {
Log.e(TAG, "clickUrl was called with null access token");
}
}
+
+ public static List<Flattr> retrieveFlattredThings()
+ throws FlattrException {
+ ArrayList<Flattr> myFlattrs = new ArrayList<Flattr>();
+
+ if (hasToken()) {
+ FlattrService fs = FlattrServiceCreator.getService(retrieveToken());
+
+ Calendar firstOfMonth = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ firstOfMonth.set(Calendar.MILLISECOND, 0);
+ firstOfMonth.set(Calendar.SECOND, 0);
+ firstOfMonth.set(Calendar.MINUTE, 0);
+ firstOfMonth.set(Calendar.HOUR_OF_DAY, 0);
+ firstOfMonth.set(Calendar.DAY_OF_MONTH, Calendar.getInstance().getActualMinimum(Calendar.DAY_OF_MONTH));
+
+ Date firstOfMonthDate = firstOfMonth.getTime();
+
+ // subscriptions some times get flattrd slightly before midnight - give it an hour leeway
+ firstOfMonthDate = new Date(firstOfMonthDate.getTime() - 60*60*1000);
+
+ final int FLATTR_COUNT = 30;
+ final int FLATTR_MAXPAGE = 5;
+
+ int page = 0;
+ do {
+ myFlattrs.ensureCapacity(FLATTR_COUNT*(page+1));
+
+ for (Flattr fl: fs.getMyFlattrs(FLATTR_COUNT, page)) {
+ if (fl.getCreated().after(firstOfMonthDate))
+ myFlattrs.add(fl);
+ else
+ break;
+ }
+ page++;
+ }
+ while (myFlattrs.get(myFlattrs.size()-1).getCreated().after( firstOfMonthDate ) && page < FLATTR_MAXPAGE);
+
+ if (AppConfig.DEBUG) {
+ Log.d(TAG, "Got my flattrs list of length " + Integer.toString(myFlattrs.size()) + " comparison date" + firstOfMonthDate);
+
+ for (Flattr fl: myFlattrs) {
+ Thing thing = fl.getThing();
+ Log.d(TAG, "Flattr thing: " + fl.getThingId() + " name: " + thing.getTitle() + " url: " + thing.getUrl() + " on: " + fl.getCreated());
+ }
+ }
+
+ } else {
+ Log.e(TAG, "retrieveFlattrdThings was called with null access token");
+ }
+
+ return myFlattrs;
+ }
public static void handleCallback(Context context, Uri uri) {
AndroidAuthenticator auth = createAuthenticator();
@@ -131,7 +191,8 @@ public class FlattrUtils {
deleteToken();
FlattrServiceCreator.deleteFlattrService();
showRevokeDialog(context);
- }
+ DBWriter.clearAllFlattrStatus(context);
+ }
// ------------------------------------------------ DIALOGS
diff --git a/src/de/danoeh/antennapod/util/flattr/SimpleFlattrThing.java b/src/de/danoeh/antennapod/util/flattr/SimpleFlattrThing.java
new file mode 100644
index 000000000..296610871
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/flattr/SimpleFlattrThing.java
@@ -0,0 +1,30 @@
+package de.danoeh.antennapod.util.flattr;
+
+/* SimpleFlattrThing is a trivial implementation of the FlattrThing interface */
+public class SimpleFlattrThing implements FlattrThing {
+ public SimpleFlattrThing(String title, String url, FlattrStatus status)
+ {
+ this.title = title;
+ this.url = url;
+ this.status = status;
+ }
+
+ public String getTitle()
+ {
+ return this.title;
+ }
+
+ public String getPaymentLink()
+ {
+ return this.url;
+ }
+
+ public FlattrStatus getFlattrStatus()
+ {
+ return this.status;
+ }
+
+ private String title;
+ private String url;
+ private FlattrStatus status;
+}
diff --git a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java
index 38d990b4b..510f3bae8 100644
--- a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java
+++ b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java
@@ -5,7 +5,6 @@ import android.content.Intent;
import android.net.Uri;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.asynctask.FlattrClickWorker;
import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.service.playback.PlaybackService;
import de.danoeh.antennapod.storage.DBTasks;
@@ -15,159 +14,159 @@ import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.util.QueueAccess;
import de.danoeh.antennapod.util.ShareUtils;
-/** Handles interactions with the FeedItemMenu. */
+/**
+ * Handles interactions with the FeedItemMenu.
+ */
public class FeedItemMenuHandler {
- private FeedItemMenuHandler() {
+ private static final String TAG = "FeedItemMenuHandler";
- }
+ private FeedItemMenuHandler() {
- /**
- * Used by the MenuHandler to access different types of menus through one
- * interface
- */
- public interface MenuInterface {
- /**
- * Implementations of this method should call findItem(id) on their
- * menu-object and call setVisibility(visibility) on the returned
- * MenuItem object.
- */
- abstract void setItemVisibility(int id, boolean visible);
- }
+ }
- /**
- * This method should be called in the prepare-methods of menus. It changes
- * the visibility of the menu items depending on a FeedItem's attributes.
- *
- * @param mi
- * An instance of MenuInterface that the method uses to change a
- * MenuItem's visibility
- * @param selectedItem
- * The FeedItem for which the menu is supposed to be prepared
- * @param showExtendedMenu
- * True if MenuItems that let the user share information about
- * the FeedItem and visit its website should be set visible. This
- * parameter should be set to false if the menu space is limited.
- * @param queueAccess
- * Used for testing if the queue contains the selected item
- * @return Returns true if selectedItem is not null.
- * */
- public static boolean onPrepareMenu(MenuInterface mi,
- FeedItem selectedItem, boolean showExtendedMenu, QueueAccess queueAccess) {
+ /**
+ * Used by the MenuHandler to access different types of menus through one
+ * interface
+ */
+ public interface MenuInterface {
+ /**
+ * Implementations of this method should call findItem(id) on their
+ * menu-object and call setVisibility(visibility) on the returned
+ * MenuItem object.
+ */
+ abstract void setItemVisibility(int id, boolean visible);
+ }
+
+ /**
+ * This method should be called in the prepare-methods of menus. It changes
+ * the visibility of the menu items depending on a FeedItem's attributes.
+ *
+ * @param mi An instance of MenuInterface that the method uses to change a
+ * MenuItem's visibility
+ * @param selectedItem The FeedItem for which the menu is supposed to be prepared
+ * @param showExtendedMenu True if MenuItems that let the user share information about
+ * the FeedItem and visit its website should be set visible. This
+ * parameter should be set to false if the menu space is limited.
+ * @param queueAccess Used for testing if the queue contains the selected item
+ * @return Returns true if selectedItem is not null.
+ */
+ public static boolean onPrepareMenu(MenuInterface mi,
+ FeedItem selectedItem, boolean showExtendedMenu, QueueAccess queueAccess) {
if (selectedItem == null) {
return false;
}
- DownloadRequester requester = DownloadRequester.getInstance();
- boolean hasMedia = selectedItem.getMedia() != null;
- boolean downloaded = hasMedia && selectedItem.getMedia().isDownloaded();
- boolean downloading = hasMedia
- && requester.isDownloadingFile(selectedItem.getMedia());
- boolean notLoadedAndNotLoading = hasMedia && (!downloaded)
- && (!downloading);
- boolean isPlaying = hasMedia
- && selectedItem.getState() == FeedItem.State.PLAYING;
+ DownloadRequester requester = DownloadRequester.getInstance();
+ boolean hasMedia = selectedItem.getMedia() != null;
+ boolean downloaded = hasMedia && selectedItem.getMedia().isDownloaded();
+ boolean downloading = hasMedia
+ && requester.isDownloadingFile(selectedItem.getMedia());
+ boolean notLoadedAndNotLoading = hasMedia && (!downloaded)
+ && (!downloading);
+ boolean isPlaying = hasMedia
+ && selectedItem.getState() == FeedItem.State.PLAYING;
- FeedItem.State state = selectedItem.getState();
+ FeedItem.State state = selectedItem.getState();
- if (!isPlaying) {
- mi.setItemVisibility(R.id.skip_episode_item, false);
- }
- if (!downloaded || isPlaying) {
- mi.setItemVisibility(R.id.play_item, false);
- mi.setItemVisibility(R.id.remove_item, false);
- }
- if (!notLoadedAndNotLoading) {
- mi.setItemVisibility(R.id.download_item, false);
- }
- if (!(notLoadedAndNotLoading | downloading) | isPlaying) {
- mi.setItemVisibility(R.id.stream_item, false);
- }
- if (!downloading) {
- mi.setItemVisibility(R.id.cancel_download_item, false);
- }
+ if (!isPlaying) {
+ mi.setItemVisibility(R.id.skip_episode_item, false);
+ }
+ if (!downloaded || isPlaying) {
+ mi.setItemVisibility(R.id.play_item, false);
+ mi.setItemVisibility(R.id.remove_item, false);
+ }
+ if (!notLoadedAndNotLoading) {
+ mi.setItemVisibility(R.id.download_item, false);
+ }
+ if (!(notLoadedAndNotLoading | downloading) | isPlaying) {
+ mi.setItemVisibility(R.id.stream_item, false);
+ }
+ if (!downloading) {
+ mi.setItemVisibility(R.id.cancel_download_item, false);
+ }
- boolean isInQueue = queueAccess.contains(selectedItem.getId());
- if (!isInQueue || isPlaying) {
- mi.setItemVisibility(R.id.remove_from_queue_item, false);
- }
- if (!(!isInQueue && selectedItem.getMedia() != null)) {
- mi.setItemVisibility(R.id.add_to_queue_item, false);
- }
- if (!showExtendedMenu || selectedItem.getLink() == null) {
- mi.setItemVisibility(R.id.share_link_item, false);
- }
+ boolean isInQueue = queueAccess.contains(selectedItem.getId());
+ if (!isInQueue || isPlaying) {
+ mi.setItemVisibility(R.id.remove_from_queue_item, false);
+ }
+ if (!(!isInQueue && selectedItem.getMedia() != null)) {
+ mi.setItemVisibility(R.id.add_to_queue_item, false);
+ }
+ if (!showExtendedMenu || selectedItem.getLink() == null) {
+ mi.setItemVisibility(R.id.share_link_item, false);
+ }
- if (!AppConfig.DEBUG
- || !(state == FeedItem.State.IN_PROGRESS || state == FeedItem.State.READ)) {
- mi.setItemVisibility(R.id.mark_unread_item, false);
- }
- if (!(state == FeedItem.State.NEW || state == FeedItem.State.IN_PROGRESS)) {
- mi.setItemVisibility(R.id.mark_read_item, false);
- }
+ if (!AppConfig.DEBUG
+ || !(state == FeedItem.State.IN_PROGRESS || state == FeedItem.State.READ)) {
+ mi.setItemVisibility(R.id.mark_unread_item, false);
+ }
+ if (!(state == FeedItem.State.NEW || state == FeedItem.State.IN_PROGRESS)) {
+ mi.setItemVisibility(R.id.mark_read_item, false);
+ }
- if (!showExtendedMenu || selectedItem.getLink() == null) {
- mi.setItemVisibility(R.id.visit_website_item, false);
- }
+ if (!showExtendedMenu || selectedItem.getLink() == null) {
+ mi.setItemVisibility(R.id.visit_website_item, false);
+ }
- if (selectedItem.getPaymentLink() == null) {
- mi.setItemVisibility(R.id.support_item, false);
- }
- return true;
- }
+ if (selectedItem.getPaymentLink() == null || !selectedItem.getFlattrStatus().flattrable()) {
+ mi.setItemVisibility(R.id.support_item, false);
+ }
+ return true;
+ }
- public static boolean onMenuItemClicked(Context context, int menuItemId,
- FeedItem selectedItem) throws DownloadRequestException {
- DownloadRequester requester = DownloadRequester.getInstance();
- switch (menuItemId) {
- case R.id.skip_episode_item:
- context.sendBroadcast(new Intent(
- PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
- break;
- case R.id.download_item:
- DBTasks.downloadFeedItems(context, selectedItem);
- break;
- case R.id.play_item:
- DBTasks.playMedia(context, selectedItem.getMedia(), true, true,
- false);
- break;
- case R.id.remove_item:
- DBWriter.deleteFeedMediaOfItem(context, selectedItem.getMedia().getId());
- break;
- case R.id.cancel_download_item:
- requester.cancelDownload(context, selectedItem.getMedia());
- break;
- case R.id.mark_read_item:
- DBWriter.markItemRead(context, selectedItem, true, true);
- break;
- case R.id.mark_unread_item:
- DBWriter.markItemRead(context, selectedItem, false, true);
- break;
- case R.id.add_to_queue_item:
- DBWriter.addQueueItem(context, selectedItem.getId());
- break;
- case R.id.remove_from_queue_item:
- DBWriter.removeQueueItem(context, selectedItem.getId(), true);
- break;
- case R.id.stream_item:
- DBTasks.playMedia(context, selectedItem.getMedia(), true, true,
- true);
- break;
- case R.id.visit_website_item:
- Uri uri = Uri.parse(selectedItem.getLink());
- context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
- break;
- case R.id.support_item:
- new FlattrClickWorker(context, selectedItem.getPaymentLink())
- .executeAsync();
- break;
- case R.id.share_link_item:
- ShareUtils.shareFeedItemLink(context, selectedItem);
- break;
- default:
- return false;
- }
- // Refresh menu state
+ public static boolean onMenuItemClicked(Context context, int menuItemId,
+ FeedItem selectedItem) throws DownloadRequestException {
+ DownloadRequester requester = DownloadRequester.getInstance();
+ switch (menuItemId) {
+ case R.id.skip_episode_item:
+ context.sendBroadcast(new Intent(
+ PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
+ break;
+ case R.id.download_item:
+ DBTasks.downloadFeedItems(context, selectedItem);
+ break;
+ case R.id.play_item:
+ DBTasks.playMedia(context, selectedItem.getMedia(), true, true,
+ false);
+ break;
+ case R.id.remove_item:
+ DBWriter.deleteFeedMediaOfItem(context, selectedItem.getMedia().getId());
+ break;
+ case R.id.cancel_download_item:
+ requester.cancelDownload(context, selectedItem.getMedia());
+ break;
+ case R.id.mark_read_item:
+ DBWriter.markItemRead(context, selectedItem, true, true);
+ break;
+ case R.id.mark_unread_item:
+ DBWriter.markItemRead(context, selectedItem, false, true);
+ break;
+ case R.id.add_to_queue_item:
+ DBWriter.addQueueItem(context, selectedItem.getId());
+ break;
+ case R.id.remove_from_queue_item:
+ DBWriter.removeQueueItem(context, selectedItem.getId(), true);
+ break;
+ case R.id.stream_item:
+ DBTasks.playMedia(context, selectedItem.getMedia(), true, true,
+ true);
+ break;
+ case R.id.visit_website_item:
+ Uri uri = Uri.parse(selectedItem.getLink());
+ context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
+ break;
+ case R.id.support_item:
+ selectedItem.getFlattrStatus().setFlattrQueue();
+ DBWriter.setFlattredStatus(context, selectedItem, true);
+ break;
+ case R.id.share_link_item:
+ ShareUtils.shareFeedItemLink(context, selectedItem);
+ break;
+ default:
+ return false;
+ }
+ // Refresh menu state
- return true;
- }
+ return true;
+ }
}
diff --git a/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java b/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java
index 27b1a8a8c..86808b609 100644
--- a/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java
+++ b/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java
@@ -8,6 +8,10 @@ import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.FeedInfoActivity;
@@ -19,6 +23,7 @@ import de.danoeh.antennapod.storage.DBWriter;
import de.danoeh.antennapod.storage.DownloadRequestException;
import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.util.ShareUtils;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
/** Handles interactions with the FeedItemMenu. */
public class FeedMenuHandler {
@@ -38,9 +43,10 @@ public class FeedMenuHandler {
Log.d(TAG, "Preparing options menu");
menu.findItem(R.id.mark_all_read_item).setVisible(
selectedFeed.hasNewItems(true));
- if (selectedFeed.getPaymentLink() != null) {
+ if (selectedFeed.getPaymentLink() != null && selectedFeed.getFlattrStatus().flattrable())
menu.findItem(R.id.support_item).setVisible(true);
- }
+ else
+ menu.findItem(R.id.support_item).setVisible(false);
MenuItem refresh = menu.findItem(R.id.refresh_item);
if (DownloadService.isRunning
&& DownloadRequester.getInstance().isDownloadingFile(
@@ -78,8 +84,8 @@ public class FeedMenuHandler {
context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
break;
case R.id.support_item:
- new FlattrClickWorker(context, selectedFeed.getPaymentLink())
- .executeAsync();
+ selectedFeed.getFlattrStatus().setFlattrQueue();
+ DBWriter.setFlattredStatus(context, selectedFeed, true);
break;
case R.id.share_link_item:
ShareUtils.shareFeedlink(context, selectedFeed);
diff --git a/src/instrumentationTest/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java b/src/instrumentationTest/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
index fac293693..8a270715f 100644
--- a/src/instrumentationTest/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
+++ b/src/instrumentationTest/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
@@ -108,7 +108,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
f.setItems(new ArrayList<FeedItem>());
FeedItem i = new FeedItem(0, "t", "i", "l", new Date(), false, f);
f.getItems().add(i);
- FeedMedia media = new FeedMedia(0, i, 0, 0, 0, "audio/wav", fileUrl, downloadUrl, fileUrl != null, null);
+ FeedMedia media = new FeedMedia(0, i, 0, 0, 0, "audio/wav", fileUrl, downloadUrl, fileUrl != null, null, 0);
i.setMedia(media);
PodDBAdapter adapter = new PodDBAdapter(c);
adapter.open();
diff --git a/src/instrumentationTest/de/test/antennapod/storage/DBReaderTest.java b/src/instrumentationTest/de/test/antennapod/storage/DBReaderTest.java
index a214e55bc..78fe3b701 100644
--- a/src/instrumentationTest/de/test/antennapod/storage/DBReaderTest.java
+++ b/src/instrumentationTest/de/test/antennapod/storage/DBReaderTest.java
@@ -7,6 +7,8 @@ import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.storage.DBReader;
import de.danoeh.antennapod.storage.PodDBAdapter;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
+import static instrumentationTest.de.test.antennapod.storage.DBTestUtils.*;
import java.util.ArrayList;
import java.util.Date;
@@ -41,7 +43,7 @@ public class DBReaderTest extends InstrumentationTestCase {
private void expiredFeedListTestHelper(long lastUpdate, long expirationTime, boolean shouldReturn) {
final Context context = getInstrumentation().getTargetContext();
Feed feed = new Feed(0, new Date(lastUpdate), "feed", "link", "descr", null,
- null, null, null, "feed", null, null, "url", false);
+ null, null, null, "feed", null, null, "url", false, new FlattrStatus());
feed.setItems(new ArrayList<FeedItem>());
PodDBAdapter adapter = new PodDBAdapter(context);
adapter.open();
diff --git a/src/instrumentationTest/de/test/antennapod/storage/DBTasksTest.java b/src/instrumentationTest/de/test/antennapod/storage/DBTasksTest.java
index e9b871867..2372757ce 100644
--- a/src/instrumentationTest/de/test/antennapod/storage/DBTasksTest.java
+++ b/src/instrumentationTest/de/test/antennapod/storage/DBTasksTest.java
@@ -11,6 +11,7 @@ import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.storage.DBReader;
import de.danoeh.antennapod.storage.DBTasks;
import de.danoeh.antennapod.storage.PodDBAdapter;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
import java.io.File;
import java.io.IOException;
@@ -76,7 +77,7 @@ public class DBTasksTest extends InstrumentationTestCase {
File f = new File(destFolder, "file " + i);
assertTrue(f.createNewFile());
files.add(f);
- item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true, new Date(NUM_ITEMS - i)));
+ item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true, new Date(NUM_ITEMS - i), 0));
items.add(item);
}
@@ -114,7 +115,7 @@ public class DBTasksTest extends InstrumentationTestCase {
assertTrue(f.createNewFile());
assertTrue(f.exists());
files.add(f);
- item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true, new Date(NUM_ITEMS - i)));
+ item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true, new Date(NUM_ITEMS - i), 0));
items.add(item);
}
@@ -148,7 +149,7 @@ public class DBTasksTest extends InstrumentationTestCase {
assertTrue(f.createNewFile());
assertTrue(f.exists());
files.add(f);
- item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true, new Date(NUM_ITEMS - i)));
+ item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true, new Date(NUM_ITEMS - i), 0));
items.add(item);
}
@@ -279,7 +280,7 @@ public class DBTasksTest extends InstrumentationTestCase {
final Context context = getInstrumentation().getTargetContext();
UserPreferences.setUpdateInterval(context, expirationTime);
Feed feed = new Feed(0, new Date(lastUpdate), "feed", "link", "descr", null,
- null, null, null, "feed", null, null, "url", false);
+ null, null, null, "feed", null, null, "url", false, new FlattrStatus());
feed.setItems(new ArrayList<FeedItem>());
PodDBAdapter adapter = new PodDBAdapter(context);
adapter.open();
diff --git a/src/instrumentationTest/de/test/antennapod/storage/DBTestUtils.java b/src/instrumentationTest/de/test/antennapod/storage/DBTestUtils.java
index fbb7b0386..7e9e1b908 100644
--- a/src/instrumentationTest/de/test/antennapod/storage/DBTestUtils.java
+++ b/src/instrumentationTest/de/test/antennapod/storage/DBTestUtils.java
@@ -6,6 +6,7 @@ import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.storage.PodDBAdapter;
import de.danoeh.antennapod.util.comparator.FeedItemPubdateComparator;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
import junit.framework.Assert;
import java.util.ArrayList;
@@ -31,7 +32,7 @@ public class DBTestUtils {
adapter.open();
for (int i = 0; i < numFeeds; i++) {
Feed f = new Feed(0, new Date(), "feed " + i, "link" + i, "descr", null, null,
- null, null, "id" + i, null, null, "url" + i, false);
+ null, null, "id" + i, null, null, "url" + i, false, new FlattrStatus());
f.setItems(new ArrayList<FeedItem>());
for (int j = 0; j < numItems; j++) {
FeedItem item = new FeedItem(0, "item " + j, "id" + j, "link" + j, new Date(),
diff --git a/src/instrumentationTest/de/test/antennapod/storage/DBWriterTest.java b/src/instrumentationTest/de/test/antennapod/storage/DBWriterTest.java
index 429903cba..679ae1ad3 100644
--- a/src/instrumentationTest/de/test/antennapod/storage/DBWriterTest.java
+++ b/src/instrumentationTest/de/test/antennapod/storage/DBWriterTest.java
@@ -64,7 +64,7 @@ public class DBWriterTest extends InstrumentationTestCase {
feed.setItems(items);
FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), true, feed);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", dest.getAbsolutePath(), "download_url", true, null);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", dest.getAbsolutePath(), "download_url", true, null, 0);
item.setMedia(media);
items.add(item);
@@ -108,7 +108,7 @@ public class DBWriterTest extends InstrumentationTestCase {
assertTrue(enc.createNewFile());
itemFiles.add(enc);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null, 0);
item.setMedia(media);
}
@@ -169,7 +169,7 @@ public class DBWriterTest extends InstrumentationTestCase {
assertTrue(enc.createNewFile());
itemFiles.add(enc);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null, 0);
item.setMedia(media);
}
@@ -317,7 +317,7 @@ public class DBWriterTest extends InstrumentationTestCase {
File enc = new File(destFolder, "file " + i);
itemFiles.add(enc);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", false, null);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", false, null, 0);
item.setMedia(media);
}
@@ -389,7 +389,7 @@ public class DBWriterTest extends InstrumentationTestCase {
File enc = new File(destFolder, "file " + i);
itemFiles.add(enc);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", false, null);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", false, null, 0);
item.setMedia(media);
}
@@ -430,7 +430,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Feed feed = new Feed("url", new Date(), "title");
feed.setItems(new ArrayList<FeedItem>());
FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), true, feed);
- FeedMedia media = new FeedMedia(0, item, 10, 0, 1, "mime", null, "url", false, playbackCompletionDate);
+ FeedMedia media = new FeedMedia(0, item, 10, 0, 1, "mime", null, "url", false, playbackCompletionDate, 0);
feed.getItems().add(item);
item.setMedia(media);
PodDBAdapter adapter = new PodDBAdapter(context);