package com.vaguehope.onosendai.provider; import java.util.concurrent.TimeUnit; import twitter4j.TwitterException; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.support.v4.app.NotificationCompat; import com.vaguehope.onosendai.R; import com.vaguehope.onosendai.config.Account; import com.vaguehope.onosendai.model.Meta; import com.vaguehope.onosendai.model.MetaType; import com.vaguehope.onosendai.model.OutboxTweet.OutboxAction; import com.vaguehope.onosendai.model.Tweet; import com.vaguehope.onosendai.notifications.Notifications; import com.vaguehope.onosendai.provider.OutboxTask.OtRequest; import com.vaguehope.onosendai.provider.successwhale.ItemAction; import com.vaguehope.onosendai.provider.successwhale.SuccessWhaleException; import com.vaguehope.onosendai.provider.successwhale.SuccessWhaleProvider; import com.vaguehope.onosendai.provider.twitter.TwitterProvider; import com.vaguehope.onosendai.storage.DbBindingAsyncTask; import com.vaguehope.onosendai.storage.DbInterface; import com.vaguehope.onosendai.ui.OutboxActivity; import com.vaguehope.onosendai.util.LogWrapper; public class OutboxTask extends DbBindingAsyncTask<Void, Void, SendResult<OtRequest>> { private static final LogWrapper LOG = new LogWrapper("OT"); private final Context context; private final OtRequest req; private final int notificationId; private NotificationManager notificationMgr; public OutboxTask (final Context context, final OtRequest req) { super(context); this.context = context; this.req = req; this.notificationId = (int) (req.getReqId() != null ? req.getReqId() : System.currentTimeMillis()); // Probably unique. } @Override protected LogWrapper getLog () { return LOG; } @Override protected void onPreExecute () { this.notificationMgr = (NotificationManager) this.context.getSystemService(Context.NOTIFICATION_SERVICE); final Notification n = new NotificationCompat.Builder(this.context) .setSmallIcon(Notifications.notificationIcon()) .setContentTitle(String.format("%s via %s...", this.req.getAction().getUiVerb(), this.req.getAccount().getUiTitle())) //ES .setOngoing(true) .setUsesChronometer(true) .build(); this.notificationMgr.notify(this.notificationId, n); } @Override protected SendResult<OtRequest> doInBackgroundWithDb (final DbInterface db, final Void... params) { LOG.i("%s: %s", this.req.getAction().getUiVerb(), this.req); switch (this.req.getAccount().getProvider()) { case TWITTER: return viaTwitter(db); case SUCCESSWHALE: return viaSuccessWhale(db); default: return new SendResult<OtRequest>(this.req, new UnsupportedOperationException("Do not know how to " + this.req.getAction().getUiTitle() + " via account type: " + this.req.getAccount().getUiTitle())); } } private SendResult<OtRequest> viaTwitter (final DbInterface db) { final TwitterProvider p = new TwitterProvider(); try { switch (this.req.getAction()) { case RT: p.rt(this.req.getAccount(), Long.parseLong(this.req.getSid())); LOG.i("RTed tweet: sid=%s", this.req.getSid()); return new SendResult<OtRequest>(this.req); case FAV: p.fav(this.req.getAccount(), Long.parseLong(this.req.getSid())); LOG.i("Favorited tweet: sid=%s", this.req.getSid()); return new SendResult<OtRequest>(this.req); case DELETE: p.delete(this.req.getAccount(), Long.parseLong(this.req.getSid())); LOG.i("Deleted tweet: editSid=%s", this.req.getSid()); markAsDeleted(db); return new SendResult<OtRequest>(this.req); default: return new SendResult<OtRequest>(this.req, new UnsupportedOperationException("Do not know how to " + this.req.getAction().getUiTitle() + " via account type: " + this.req.getAccount().getUiTitle())); } } catch (final TwitterException e) { return new SendResult<OtRequest>(this.req, e); } finally { p.shutdown(); } } private SendResult<OtRequest> viaSuccessWhale (final DbInterface db) { final SuccessWhaleProvider p = new SuccessWhaleProvider(db); try { final ServiceRef svc = this.req.getSvc(); if (svc != null) { final NetworkType networkType = svc.getType(); if (networkType != null) { switch (networkType) { case TWITTER: switch (this.req.getAction()) { case RT: p.itemAction(this.req.getAccount(), svc, this.req.getSid(), ItemAction.RETWEET); LOG.i("RTed tweet: sid=%s", this.req.getSid()); return new SendResult<OtRequest>(this.req); case FAV: p.itemAction(this.req.getAccount(), svc, this.req.getSid(), ItemAction.FAVORITE); LOG.i("Favorited tweet: sid=%s", this.req.getSid()); return new SendResult<OtRequest>(this.req); case DELETE: p.itemAction(this.req.getAccount(), svc, this.req.getSid(), ItemAction.DELETE_TWITTER); LOG.i("Deleted SW tweet: editSid=%s", this.req.getSid()); markAsDeleted(db); return new SendResult<OtRequest>(this.req); default: return new SendResult<OtRequest>(this.req, new UnsupportedOperationException("Do not know how to " + this.req.getAction().getUiTitle() + " via account type: " + this.req.getAccount().getUiTitle())); } case FACEBOOK: switch (this.req.getAction()) { case RT: p.itemAction(this.req.getAccount(), svc, this.req.getSid(), ItemAction.LIKE); LOG.i("Liked FB update: sid=%s", this.req.getSid()); return new SendResult<OtRequest>(this.req); case DELETE: p.itemAction(this.req.getAccount(), svc, this.req.getSid(), ItemAction.DELETE_FACEBOOK); LOG.i("Deleted FB update: editSid=%s", this.req.getSid()); markAsDeleted(db); return new SendResult<OtRequest>(this.req); default: return new SendResult<OtRequest>(this.req, new UnsupportedOperationException("Do not know how to " + this.req.getAction().getUiTitle() + " via account type: " + this.req.getAccount().getUiTitle())); } default: return new SendResult<OtRequest>(this.req, new SuccessWhaleException("Unknown network type: " + networkType)); } } return new SendResult<OtRequest>(this.req, new SuccessWhaleException("Service metadata missing network type: " + svc)); } return new SendResult<OtRequest>(this.req, new SuccessWhaleException("Invalid service metadata: " + svc)); } catch (final SuccessWhaleException e) { return new SendResult<OtRequest>(this.req, e); } finally { p.shutdown(); } } private void markAsDeleted (final DbInterface db) { final Meta meta = new Meta(MetaType.DELETED, TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); for (final Tweet t : db.getTweetsWithSid(this.req.getSid())) { db.appendToTweet(t, meta); LOG.i("Marked as deleted: uid=%s sid=%s", t.getUid(), this.req.getSid()); } } @Override protected void onPostExecute (final SendResult<OtRequest> res) { switch (res.getOutcome()) { case SUCCESS: case PREVIOUS_ATTEMPT_SUCCEEDED: this.notificationMgr.cancel(this.notificationId); break; default: LOG.w("%s failed: %s", this.req.getAction().getUiTitle(), res.getE()); //ES final Notification n = new NotificationCompat.Builder(this.context) .setSmallIcon(R.drawable.exclamation_red) // TODO better icon. .setContentTitle(String.format("Failed to %s via %s.", this.req.getAction().getUiTitle(), this.req.getAccount().getUiTitle())) .setContentText(res.getEmsg()) .setAutoCancel(true) .setUsesChronometer(false) .setWhen(System.currentTimeMillis()) .setContentIntent(PendingIntent.getActivity(getContext(), this.notificationId, new Intent(getContext(), OutboxActivity.class), PendingIntent.FLAG_CANCEL_CURRENT)) .build(); this.notificationMgr.notify(this.notificationId, n); } } public static class OtRequest { private final OutboxAction action; private final Long reqId; private final Account account; private final ServiceRef svc; private final String sid; public OtRequest (final OutboxAction action, final Long reqId, final Account account, final ServiceRef svc, final String sid) { this.action = action; this.reqId = reqId; this.account = account; this.svc = svc; this.sid = sid; } public OutboxAction getAction () { return this.action; } public Long getReqId () { return this.reqId; } public Account getAccount () { return this.account; } public ServiceRef getSvc () { return this.svc; } public String getSid () { return this.sid; } @Override public String toString () { return new StringBuilder() .append("OtRequest{").append(this.action) .append(",").append(this.account) .append(",").append(this.svc) .append(",").append(this.sid) .append("}").toString(); } } }