package org.wordpress.android.ui.posts.services;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.util.SparseArray;
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.model.post.PostStatus;
import org.wordpress.android.ui.notifications.ShareAndDismissNotificationReceiver;
import org.wordpress.android.ui.posts.PostsListActivity;
import org.wordpress.android.util.AppLog;
import org.wordpress.android.util.CrashlyticsUtils;
import org.wordpress.android.util.SystemServiceFactory;
import org.wordpress.android.util.WPMeShortlinks;
import java.util.Random;
public class PostUploadNotifier {
private final Context mContext;
private final PostUploadService mService;
private final NotificationManager mNotificationManager;
private final Notification.Builder mNotificationBuilder;
private final SparseArray<NotificationData> mPostIdToNotificationData = new SparseArray<>();
private class NotificationData {
int notificationId;
int notificationErrorId;
int totalMediaItems;
int currentMediaItem;
float itemProgressSize;
Bitmap latestIcon;
}
public PostUploadNotifier(Context context, PostUploadService service) {
// Add the uploader to the notification bar
mContext = context;
mService = service;
mNotificationManager = (NotificationManager) SystemServiceFactory.get(mContext,
Context.NOTIFICATION_SERVICE);
mNotificationBuilder = new Notification.Builder(mContext.getApplicationContext());
mNotificationBuilder.setSmallIcon(android.R.drawable.stat_sys_upload);
}
public void updateNotificationNewPost(PostModel post, String title, String message) {
if (title != null) {
mNotificationBuilder.setContentTitle(title);
}
if (message != null) {
mNotificationBuilder.setContentText(message);
}
int notificationId = (new Random()).nextInt() + post.getLocalSiteId();
NotificationData notificationData = new NotificationData();
notificationData.notificationId = notificationId;
mPostIdToNotificationData.put(post.getId(), notificationData);
mService.startForeground(notificationId, mNotificationBuilder.build());
}
public void updateNotificationIcon(PostModel post, Bitmap icon) {
NotificationData notificationData = mPostIdToNotificationData.get(post.getId());
if (icon != null) {
notificationData.latestIcon = icon;
mNotificationBuilder.setLargeIcon(notificationData.latestIcon);
}
doNotify(mPostIdToNotificationData.get(post.getId()).notificationId, mNotificationBuilder.build());
}
public void cancelNotification(PostModel post) {
NotificationData notificationData = mPostIdToNotificationData.get(post.getId());
if (notificationData != null) {
mNotificationManager.cancel(notificationData.notificationId);
}
}
public void updateNotificationSuccess(PostModel post, SiteModel site, boolean isFirstTimePublish) {
AppLog.d(AppLog.T.POSTS, "updateNotificationSuccess");
// Get the shareableUrl
String shareableUrl = WPMeShortlinks.getPostShortlink(site, post);
if (shareableUrl == null && !TextUtils.isEmpty(post.getLink())) {
shareableUrl = post.getLink();
}
// Notification builder
Notification.Builder notificationBuilder = new Notification.Builder(mContext.getApplicationContext());
String notificationTitle = (String) (post.isPage() ? mContext.getResources().getText(R.string
.page_published) : mContext.getResources().getText(R.string.post_published));
if (!isFirstTimePublish) {
notificationTitle = (String) (post.isPage() ? mContext.getResources().getText(R.string
.page_updated) : mContext.getResources().getText(R.string.post_updated));
}
notificationBuilder.setSmallIcon(android.R.drawable.stat_sys_upload_done);
NotificationData notificationData = mPostIdToNotificationData.get(post.getId());
if (notificationData == null || notificationData.latestIcon == null) {
notificationBuilder.setLargeIcon(BitmapFactory.decodeResource(mContext.getApplicationContext()
.getResources(),
R.mipmap.app_icon));
} else {
notificationBuilder.setLargeIcon(notificationData.latestIcon);
}
notificationBuilder.setContentTitle(notificationTitle);
notificationBuilder.setContentText(post.getTitle());
notificationBuilder.setAutoCancel(true);
// Tap notification intent (open the post list)
Intent notificationIntent = new Intent(mContext, PostsListActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
notificationIntent.putExtra(WordPress.SITE, site);
notificationIntent.putExtra(PostsListActivity.EXTRA_VIEW_PAGES, post.isPage());
PendingIntent pendingIntentPost = PendingIntent.getActivity(mContext, 0,
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.setContentIntent(pendingIntentPost);
// Share intent - started if the user tap the share link button - only if the link exist
long notificationId = getNotificationIdForPost(post);
if (shareableUrl != null && PostStatus.fromPost(post) == PostStatus.PUBLISHED) {
Intent shareIntent = new Intent(mContext, ShareAndDismissNotificationReceiver.class);
shareIntent.putExtra(ShareAndDismissNotificationReceiver.NOTIFICATION_ID_KEY, notificationId);
shareIntent.putExtra(Intent.EXTRA_TEXT, shareableUrl);
shareIntent.putExtra(Intent.EXTRA_SUBJECT, post.getTitle());
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, shareIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
notificationBuilder.addAction(R.drawable.ic_share_24dp, mContext.getString(R.string.share_action),
pendingIntent);
}
doNotify(notificationId, notificationBuilder.build());
}
private long getNotificationIdForPost(PostModel post) {
long remotePostId = post.getRemotePostId();
// We can't use the local table post id here because it can change between first post (local draft) to
// first edit (post pulled from the server)
return post.getLocalSiteId() + remotePostId;
}
public void updateNotificationError(PostModel post, SiteModel site, String errorMessage, boolean isMediaError) {
AppLog.d(AppLog.T.POSTS, "updateNotificationError: " + errorMessage);
Notification.Builder notificationBuilder = new Notification.Builder(mContext.getApplicationContext());
String postOrPage = (String) (post.isPage() ? mContext.getResources().getText(R.string.page_id)
: mContext.getResources().getText(R.string.post_id));
Intent notificationIntent = new Intent(mContext, PostsListActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
notificationIntent.putExtra(WordPress.SITE, site);
notificationIntent.putExtra(PostsListActivity.EXTRA_VIEW_PAGES, post.isPage());
notificationIntent.putExtra(PostsListActivity.EXTRA_ERROR_MSG, errorMessage);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0,
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
String errorText = mContext.getResources().getText(R.string.upload_failed).toString();
if (isMediaError) {
errorText = mContext.getResources().getText(R.string.media) + " "
+ mContext.getResources().getText(R.string.error);
}
notificationBuilder.setSmallIcon(android.R.drawable.stat_notify_error);
notificationBuilder.setContentTitle((isMediaError) ? errorText :
mContext.getResources().getText(R.string.upload_failed));
notificationBuilder.setContentText((isMediaError) ? errorMessage : postOrPage + " " + errorText
+ ": " + errorMessage);
notificationBuilder.setContentIntent(pendingIntent);
notificationBuilder.setAutoCancel(true);
NotificationData notificationData = mPostIdToNotificationData.get(post.getId());
if (notificationData.notificationErrorId == 0) {
notificationData.notificationErrorId = notificationData.notificationId + (new Random()).nextInt();
}
doNotify(notificationData.notificationErrorId, notificationBuilder.build());
}
public void updateNotificationProgress(PostModel post, float progress) {
NotificationData notificationData = mPostIdToNotificationData.get(post.getId());
if (notificationData.totalMediaItems == 0) {
return;
}
// Simple way to show progress of entire post upload
// Would be better if we could get total bytes for all media items.
double currentChunkProgress = (notificationData.itemProgressSize * progress);
if (notificationData.currentMediaItem > 1) {
currentChunkProgress += notificationData.itemProgressSize * (notificationData.currentMediaItem - 1);
}
mNotificationBuilder.setProgress(100, (int) Math.ceil(currentChunkProgress), false);
doNotify(mPostIdToNotificationData.get(post.getId()).notificationId, mNotificationBuilder.build());
}
private synchronized void doNotify(long id, Notification notification) {
try {
mNotificationManager.notify((int) id, notification);
} catch (RuntimeException runtimeException) {
CrashlyticsUtils.logException(runtimeException, AppLog.T.UTILS, "See issue #2858 / #3966");
AppLog.d(AppLog.T.POSTS, "See issue #2858 / #3966; notify failed with:" + runtimeException);
}
}
public void setTotalMediaItems(PostModel post, int totalMediaItems) {
NotificationData notificationData = mPostIdToNotificationData.get(post.getId());
if (totalMediaItems <= 0) {
totalMediaItems = 1;
}
notificationData.totalMediaItems = totalMediaItems;
notificationData.itemProgressSize = 100.0f / notificationData.totalMediaItems;
}
public void setCurrentMediaItem(PostModel post, int currentItem) {
NotificationData notificationData = mPostIdToNotificationData.get(post.getId());
notificationData.currentMediaItem = currentItem;
mNotificationBuilder.setContentText(String.format(mContext.getString(R.string.uploading_total),
currentItem, notificationData.totalMediaItems));
}
}