package org.wordpress.android.ui.notifications.receivers; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.support.v4.app.NotificationCompat; import android.text.TextUtils; import org.wordpress.android.R; import org.wordpress.android.WordPress; import org.wordpress.android.fluxc.model.PostModel; import org.wordpress.android.fluxc.model.SiteModel; import org.wordpress.android.fluxc.store.PostStore; import org.wordpress.android.fluxc.store.SiteStore; import org.wordpress.android.push.NativeNotificationsUtils; import org.wordpress.android.push.NotificationsProcessingService; import org.wordpress.android.ui.main.WPMainActivity; import org.wordpress.android.ui.notifications.utils.PendingDraftsNotificationsUtils; import org.wordpress.android.ui.prefs.AppPrefs; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.DateTimeUtils; import java.util.List; import java.util.Random; import javax.inject.Inject; public class NotificationsPendingDraftsReceiver extends BroadcastReceiver { public static final String POST_ID_EXTRA = "postId"; public static final String IS_PAGE_EXTRA = "isPage"; public static final long ONE_DAY = 24 * 60 * 60 * 1000; public static final long ONE_WEEK = ONE_DAY * 7; public static final long ONE_MONTH = ONE_WEEK * 4; private static final long MAX_DAYS_TO_SHOW_DAYS_IN_MESSAGE = 40; // just over a month private static final int BASE_REQUEST_CODE = 100; @Inject PostStore mPostStore; @Inject SiteStore mSiteStore; @Override public void onReceive(Context context, Intent intent) { ((WordPress) context.getApplicationContext()).component().inject(this); // for the case of being spanned after device restarts, get the latest drafts // and check the lastUpdated String action = intent.getAction(); if (action != null && action.equals("android.intent.action.BOOT_COMPLETED")) { AppLog.i(AppLog.T.NOTIFS, "entering Pending Drafts Receiver from BOOT_COMPLETED"); // build notifications for existing local drafts int siteLocalId = AppPrefs.getSelectedSite(); SiteModel site = mSiteStore.getSiteByLocalId(siteLocalId); if (site != null) { List<PostModel> draftPosts = mPostStore.getPostsForSite(site); for (PostModel post : draftPosts) { // reschedule next notifications for each local draft post we have, as we have // just been rebooted PendingDraftsNotificationsUtils.scheduleNextNotifications(context, post); } } } else { AppLog.i(AppLog.T.NOTIFS, "entering Pending Drafts Receiver from alarm"); // get extras from intent in order to build notification buildNotificationForPostId(intent.getIntExtra(POST_ID_EXTRA, 0), context); } } private void buildNotificationForPostId(int postId, Context context) { if (postId != 0) { PostModel post = mPostStore.getPostByLocalPostId(postId); if (post != null) { long now = System.currentTimeMillis(); long dateLastUpdated = DateTimeUtils.timestampFromIso8601(post.getDateLocallyChanged()); long daysInDraft = (now - dateLastUpdated) / ONE_DAY; boolean isPage = post.isPage(); if (daysInDraft < MAX_DAYS_TO_SHOW_DAYS_IN_MESSAGE) { String formattedString = context.getString(R.string.pending_draft_one_generic); long one_day_ago = now - ONE_DAY; long one_week_ago = now - ONE_WEEK; long one_month_ago = now - ONE_MONTH; if (dateLastUpdated < one_month_ago) { formattedString = context.getString(R.string.pending_draft_one_month); } else if (dateLastUpdated < one_week_ago) { // use any of the available 2 string formats, randomly Random randomNum = new Random(); int result = randomNum.nextInt(2); if (result == 0) formattedString = context.getString(R.string.pending_draft_one_week_1); else formattedString = context.getString(R.string.pending_draft_one_week_2); } else if (dateLastUpdated < one_day_ago) { // use any of the available 2 string formats, randomly Random randomNum = new Random(); int result = randomNum.nextInt(2); if (result == 0) formattedString = context.getString(R.string.pending_draft_one_day_1); else formattedString = context.getString(R.string.pending_draft_one_day_2); } buildSinglePendingDraftNotification(context, post.getTitle(), formattedString, postId, isPage); } else { // if it's been more than MAX_DAYS_TO_SHOW_DAYS_IN_MESSAGE days, or if we don't know (i.e. value for lastUpdated // is zero) then just show a generic message buildSinglePendingDraftNotificationGeneric(context, post.getTitle(), postId, isPage); } } } } private String getPostTitle(Context context, String postTitle) { String title = postTitle; if (TextUtils.isEmpty(postTitle)) { title = "(" + context.getResources().getText(R.string.untitled) + ")"; } return title; } private void buildSinglePendingDraftNotification(Context context, String postTitle, String formattedMessage, int postId, boolean isPage) { buildNotificationWithIntent(context, getResultIntentForOnePost(context, postId, isPage), String.format(formattedMessage, getPostTitle(context, postTitle)), postId, isPage); } private void buildSinglePendingDraftNotificationGeneric(Context context, String postTitle, int postId, boolean isPage) { buildNotificationWithIntent(context, getResultIntentForOnePost(context, postId, isPage), String.format(context.getString(R.string.pending_draft_one_generic), getPostTitle(context, postTitle)), postId, isPage); } private PendingIntent getResultIntentForOnePost(Context context, int postId, boolean isPage) { Intent resultIntent = new Intent(context, WPMainActivity.class); resultIntent.putExtra(WPMainActivity.ARG_OPENED_FROM_PUSH, true); resultIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); resultIntent.setAction("android.intent.action.MAIN"); resultIntent.addCategory("android.intent.category.LAUNCHER"); resultIntent.putExtra(POST_ID_EXTRA, postId); resultIntent.putExtra(IS_PAGE_EXTRA, isPage); PendingIntent pendingIntent = PendingIntent.getActivity(context, BASE_REQUEST_CODE + PendingDraftsNotificationsUtils.makePendingDraftNotificationId(postId), resultIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_UPDATE_CURRENT); return pendingIntent; } private void buildNotificationWithIntent(Context context, PendingIntent intent, String message, int postId, boolean isPage) { NotificationCompat.Builder builder = NativeNotificationsUtils.getBuilder(context); builder.setContentText(message) .setPriority(NotificationCompat.PRIORITY_MAX); builder.setContentIntent(intent); if (postId != 0) { addOpenDraftActionForNotification(context, builder, postId, isPage); addIgnoreActionForNotification(context, builder, postId, isPage); } addDismissActionForNotification(context, builder, postId, isPage); NativeNotificationsUtils.showMessageToUserWithBuilder(builder, message, false, PendingDraftsNotificationsUtils.makePendingDraftNotificationId(postId), context); } private void addOpenDraftActionForNotification(Context context, NotificationCompat.Builder builder, int postId, boolean isPage) { // adding open draft action Intent openDraftIntent = new Intent(context, WPMainActivity.class); openDraftIntent.putExtra(WPMainActivity.ARG_OPENED_FROM_PUSH, true); openDraftIntent.putExtra(POST_ID_EXTRA, postId); openDraftIntent.putExtra(IS_PAGE_EXTRA, isPage); PendingIntent pendingIntent = PendingIntent.getActivity(context, // need to add + 2 so the request code is different, otherwise they overlap BASE_REQUEST_CODE + 1 + PendingDraftsNotificationsUtils.makePendingDraftNotificationId(postId), openDraftIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_UPDATE_CURRENT); builder.addAction(R.drawable.ic_pencil_white, context.getText(R.string.edit), pendingIntent); } private void addIgnoreActionForNotification(Context context, NotificationCompat.Builder builder, int postId, boolean isPage) { // Call processing service when user taps on IGNORE - we should remember this decision for this post Intent ignoreIntent = new Intent(context, NotificationsProcessingService.class); ignoreIntent.putExtra(NotificationsProcessingService.ARG_ACTION_TYPE, NotificationsProcessingService.ARG_ACTION_DRAFT_PENDING_IGNORE); ignoreIntent.putExtra(POST_ID_EXTRA, postId); ignoreIntent.putExtra(IS_PAGE_EXTRA, isPage); PendingIntent ignorePendingIntent = PendingIntent.getService(context, // need to add + 2 so the request code is different, otherwise they overlap BASE_REQUEST_CODE + 2 + PendingDraftsNotificationsUtils.makePendingDraftNotificationId(postId), ignoreIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_UPDATE_CURRENT); builder.addAction(R.drawable.ic_close_white_24dp, context.getText(R.string.ignore), ignorePendingIntent); } private void addDismissActionForNotification(Context context, NotificationCompat.Builder builder, int postId, boolean isPage) { // Call processing service when notification is dismissed Intent notificationDeletedIntent = new Intent(context, NotificationsProcessingService.class); notificationDeletedIntent.putExtra(NotificationsProcessingService.ARG_ACTION_TYPE, NotificationsProcessingService.ARG_ACTION_DRAFT_PENDING_DISMISS); notificationDeletedIntent.putExtra(POST_ID_EXTRA, postId); notificationDeletedIntent.putExtra(IS_PAGE_EXTRA, isPage); PendingIntent dismissPendingIntent = PendingIntent.getService(context, // need to add + 3 so the request code is different, otherwise they overlap BASE_REQUEST_CODE + 3 + PendingDraftsNotificationsUtils.makePendingDraftNotificationId(postId), notificationDeletedIntent, PendingIntent.FLAG_CANCEL_CURRENT); builder.setDeleteIntent(dismissPendingIntent); } }