summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--project.properties7
-rw-r--r--res/values/strings.xml17
-rw-r--r--res/xml/preferences.xml7
-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
27 files changed, 1159 insertions, 257 deletions
diff --git a/project.properties b/project.properties
index 75f295e31..57e7d75fe 100644
--- a/project.properties
+++ b/project.properties
@@ -9,7 +9,6 @@
# Project target.
proguard.config=proguard.cfg
-target=android-18
-android.library.reference.1=submodules/ActionBarSherlock/library
-android.library.reference.2=submodules/ViewPagerIndicator/library
-android.library.reference.3=submodules/dslv/library
+target=android-19
+android.library.reference.1=submodules/dslv/library
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index be20462d3..43bedadee 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -154,9 +154,20 @@
<string name="action_forbidden_msg">AntennaPod has no permission for this action. The reason for this could be that the access token of AntennaPod to your account has been revoked. You can either re-reauthenticate or visit the website of the thing instead.</string>
<string name="access_revoked_title">Access revoked</string>
<string name="access_revoked_info">You have successfully revoked AntennaPod\'s access token to your account. In order to complete the process, you have to remove this app from the list of approved applications in your account settings on the flattr website.</string>
- <string name="flattr_click_success">Successfully flattred this thing!</string>
- <string name="flattring_label">Flattring</string>
+ <!-- Flattr -->
+ <string name="flattr_click_success">Flattr\'ed one thing!</string>
+ <string name="flattr_click_success_count">Flattr\'ed %d things!</string>
+ <string name="flattr_click_success_queue">Flattr\'ed: %s.</string>
+ <string name="flattr_click_failure_count">Failed to flattr %d things!</string>
+ <string name="flattr_click_failure">Not flattr\'ed: %s.</string>
+ <string name="flattr_click_enqueued">Thing will be flattr\'ed later</string>
+ <string name="flattring_thing">Flattring %s</string>
+ <string name="flattring_label">AntennaPod is flattring</string>
+ <string name="flattrd_label">AntennaPod has flattr\'ed</string>
+ <string name="flattrd_failed_label">AntennaPod flattr failed</string>
+ <string name="flattr_retrieving_status">Retrieving flattr\'ed things</string>
+
<!-- Variable Speed -->
<string name="download_plugin_label">Download Plugin</string>
<string name="no_playback_plugin_title">Plugin Not Installed</string>
@@ -193,6 +204,8 @@
<string name="pref_flattr_this_app_sum">Support the development of AntennaPod by flattring it. Thanks!</string>
<string name="pref_revokeAccess_title">Revoke access</string>
<string name="pref_revokeAccess_sum">Revoke the access permission to your flattr account for this app.</string>
+ <string name="pref_auto_flattr_title">Automatic Flattr</string>
+ <string name="pref_auto_flattr_sum">Flattr episodes of which 80% have been played.</string>
<string name="pref_display_only_episodes_title">Display only episodes</string>
<string name="pref_display_only_episodes_sum">Display only items which also have an episode.</string>
<string name="user_interface_label">User Interface</string>
diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml
index cba297570..8e0b886de 100644
--- a/res/xml/preferences.xml
+++ b/res/xml/preferences.xml
@@ -83,6 +83,12 @@
<intent android:action=".activities.FlattrAuthActivity"/>
</PreferenceScreen>
+ <CheckBoxPreference
+ android:defaultValue="false"
+ android:enabled="false"
+ android:key="pref_auto_flattr"
+ android:summary="@string/pref_auto_flattr_sum"
+ android:title="@string/pref_auto_flattr_title" />
<Preference
android:key="prefRevokeAccess"
android:summary="@string/pref_revokeAccess_sum"
@@ -109,7 +115,6 @@
android:key="pref_gpodnet_hostname"
android:title="@string/pref_gpodnet_sethostname_title"/>
</PreferenceScreen>
-
</PreferenceCategory>
<PreferenceCategory android:title="@string/other_pref">
<Preference
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);