package de.danoeh.antennapod.asynctask; import android.annotation.TargetApi; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.support.v4.app.NotificationCompat; import android.util.Log; import android.widget.Toast; import org.shredzone.flattr4j.exception.FlattrException; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.FlattrAuthActivity; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.storage.DBReader; import de.danoeh.antennapod.storage.DBWriter; import de.danoeh.antennapod.util.NetworkUtils; import de.danoeh.antennapod.util.flattr.FlattrThing; import de.danoeh.antennapod.util.flattr.FlattrUtils; /** * Performs a click action in a background thread. *

* When started, the flattr click worker will try to flattr every item that is in the flattr queue. If no network * connection is available it will shut down immediately. The FlattrClickWorker can also be given one additional * FlattrThing which will be flattrd immediately. *

* The FlattrClickWorker will display a toast notification for every item that has been flattrd. If the FlattrClickWorker failed * to flattr something, a notification will be displayed. */ public class FlattrClickWorker extends AsyncTask { protected static final String TAG = "FlattrClickWorker"; private static final int NOTIFICATION_ID = 4; private final Context context; public static enum ExitCode {EXIT_NORMAL, NO_TOKEN, NO_NETWORK, NO_THINGS} private volatile int countFailed = 0; private volatile int countSuccess = 0; private volatile FlattrThing extraFlattrThing; /** * Only relevant if just one thing is flattrd */ private volatile FlattrException exception; /** * Creates a new FlattrClickWorker which will only flattr all things in the queue. *

* The FlattrClickWorker has to be started by calling executeAsync(). * * @param context A context for accessing the database and posting notifications. Must not be null. */ public FlattrClickWorker(Context context) { if (context == null) throw new IllegalArgumentException("context = null"); this.context = context.getApplicationContext(); } /** * Creates a new FlattrClickWorker which will flattr all things in the queue and one additional * FlattrThing. *

* The FlattrClickWorker has to be started by calling executeAsync(). * * @param context A context for accessing the database and posting notifications. Must not be null. * @param extraFlattrThing The additional thing to flattr */ public FlattrClickWorker(Context context, FlattrThing extraFlattrThing) { this(context); this.extraFlattrThing = extraFlattrThing; } @Override protected ExitCode doInBackground(Void... params) { if (!FlattrUtils.hasToken()) { return ExitCode.NO_TOKEN; } if (!NetworkUtils.networkAvailable(context)) { return ExitCode.NO_NETWORK; } final List flattrQueue = DBReader.getFlattrQueue(context); if (extraFlattrThing != null) { flattrQueue.add(extraFlattrThing); } else if (flattrQueue.size() == 1) { // if only one item is flattrd, the report can specifically mentioned that this item has failed extraFlattrThing = flattrQueue.get(0); } if (flattrQueue.isEmpty()) { return ExitCode.NO_THINGS; } List dbFutures = new LinkedList(); for (FlattrThing thing : flattrQueue) { if (BuildConfig.DEBUG) Log.d(TAG, "Processing " + thing.getTitle()); try { thing.getFlattrStatus().setUnflattred(); // pop from queue to prevent unflattrable things from getting stuck in flattr queue infinitely FlattrUtils.clickUrl(context, thing.getPaymentLink()); thing.getFlattrStatus().setFlattred(); publishProgress(R.string.flattr_click_success); countSuccess++; } catch (FlattrException e) { e.printStackTrace(); countFailed++; if (countFailed == 1) { exception = e; } } Future f = DBWriter.setFlattredStatus(context, thing, false); if (f != null) { dbFutures.add(f); } } for (Future f : dbFutures) { try { f.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } return ExitCode.EXIT_NORMAL; } @Override protected void onPostExecute(ExitCode exitCode) { super.onPostExecute(exitCode); switch (exitCode) { case EXIT_NORMAL: if (countFailed > 0) { postFlattrFailedNotification(); } break; case NO_NETWORK: postToastNotification(R.string.flattr_click_enqueued); break; case NO_TOKEN: postNoTokenNotification(); break; case NO_THINGS: // nothing to notify here break; } } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); postToastNotification(values[0]); } private void postToastNotification(int msg) { Toast.makeText(context, context.getString(msg), Toast.LENGTH_LONG).show(); } private void postNoTokenNotification() { PendingIntent contentIntent = PendingIntent.getActivity(context, 0, new Intent(context, FlattrAuthActivity.class), 0); Notification notification = new NotificationCompat.Builder(context) .setStyle(new NotificationCompat.BigTextStyle().bigText(context.getString(R.string.no_flattr_token_notification_msg))) .setContentIntent(contentIntent) .setContentTitle(context.getString(R.string.no_flattr_token_title)) .setTicker(context.getString(R.string.no_flattr_token_title)) .setSmallIcon(R.drawable.stat_notify_sync_error) .setOngoing(false) .setAutoCancel(true) .build(); ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, notification); } private void postFlattrFailedNotification() { if (countFailed == 0) { return; } PendingIntent contentIntent = PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0); String title; String subtext; if (countFailed == 1) { title = context.getString(R.string.flattrd_failed_label); String exceptionMsg = (exception.getMessage() != null) ? exception.getMessage() : ""; subtext = context.getString(R.string.flattr_click_failure, extraFlattrThing.getTitle()) + "\n" + exceptionMsg; } else { title = context.getString(R.string.flattrd_label); subtext = context.getString(R.string.flattr_click_success_count, countSuccess) + "\n" + context.getString(R.string.flattr_click_failure_count, countFailed); } Notification notification = new NotificationCompat.Builder(context) .setStyle(new NotificationCompat.BigTextStyle().bigText(subtext)) .setContentIntent(contentIntent) .setContentTitle(title) .setTicker(title) .setSmallIcon(R.drawable.stat_notify_sync_error) .setOngoing(false) .setAutoCancel(true) .build(); ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, notification); } /** * Starts the FlattrClickWorker as an AsyncTask. */ @TargetApi(11) public void executeAsync() { if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { execute(); } } }