package com.quran.labs.androidquran.service.util;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import com.crashlytics.android.Crashlytics;
import com.quran.labs.androidquran.QuranDataActivity;
import com.quran.labs.androidquran.R;
public class QuranDownloadNotifier {
// error messages
public static final int ERROR_DISK_SPACE = 1;
public static final int ERROR_PERMISSIONS = 2;
public static final int ERROR_NETWORK = 3;
public static final int ERROR_INVALID_DOWNLOAD = 4;
public static final int ERROR_CANCELLED = 5;
public static final int ERROR_GENERAL = 6;
// notification ids
private static final int DOWNLOADING_NOTIFICATION = 1;
public static final int DOWNLOADING_COMPLETE_NOTIFICATION = 2;
private static final int DOWNLOADING_ERROR_NOTIFICATION = 3;
private static final int DOWNLOADING_PROCESSING_NOTIFICATION = 4;
public static class ProgressIntent {
public static final String INTENT_NAME =
"com.quran.labs.androidquran.download.ProgressUpdate";
public static final String NAME = "notificationTitle";
public static final String DOWNLOAD_KEY = "downloadKey";
public static final String DOWNLOAD_TYPE = "downloadType";
public static final String STATE = "state";
public static final String PROGRESS = "progress";
public static final String TOTAL_SIZE = "totalSize";
public static final String DOWNLOADED_SIZE = "downloadedSize";
public static final String PROCESSED_FILES = "processedFiles";
public static final String TOTAL_FILES = "totalFiles";
public static final String ERROR_CODE = "errorCode";
public static final String SURA = "sura";
public static final String AYAH = "ayah";
// states for the intent maybe one of these values
public static final String STATE_DOWNLOADING = "downloading";
public static final String STATE_PROCESSING = "processing";
public static final String STATE_SUCCESS = "success";
public static final String STATE_ERROR = "error";
public static final String STATE_ERROR_WILL_RETRY = "errorWillRetry";
}
public static class NotificationDetails {
public String title;
public String key;
public int type;
public int currentFile;
public int totalFiles;
public int sura;
public int ayah;
public boolean sendIndeterminate;
public boolean isGapless;
public NotificationDetails(String title, String key, int type){
this.key = key;
this.title = title;
this.type = type;
sendIndeterminate = false;
}
public void setFileStatus(int current, int total){
totalFiles = total;
currentFile = current;
}
public void setIsGapless(boolean isGapless) {
this.isGapless = isGapless;
}
}
private Context mAppContext;
private NotificationManager mNotificationManager;
private LocalBroadcastManager mBroadcastManager;
private int mNotificationColor;
private int mLastProgress;
private int mLastMaximum;
public QuranDownloadNotifier(Context context) {
mAppContext = context.getApplicationContext();
mNotificationManager = (NotificationManager) mAppContext
.getSystemService(Context.NOTIFICATION_SERVICE);
mBroadcastManager = LocalBroadcastManager.getInstance(mAppContext);
mNotificationColor = ContextCompat.getColor(mAppContext, R.color.notification_color);
mLastProgress = -1;
mLastMaximum = -1;
}
public void resetNotifications() {
// hide any previous errors, canceled, etc
mLastMaximum = -1;
mLastProgress = -1;
mNotificationManager.cancel(DOWNLOADING_ERROR_NOTIFICATION);
mNotificationManager.cancel(DOWNLOADING_COMPLETE_NOTIFICATION);
mNotificationManager.cancel(DOWNLOADING_PROCESSING_NOTIFICATION);
}
public Intent notifyProgress(NotificationDetails details,
long downloadedSize, long totalSize){
int max = 100;
int progress = 0;
// send indeterminate if total size is 0 or less or the notification
// details says to always send indeterminate (never happens right now,
// so only when the total size is 0 or less).
boolean isIndeterminate = details.sendIndeterminate;
if (!isIndeterminate && totalSize <= 0){
isIndeterminate = true;
}
if (!isIndeterminate){
// calculate percentage based on files downloaded, files left,
// and percentage of this file that is left
double percent = (1.0 * downloadedSize) / (1.0 * totalSize);
if (details.isGapless) {
progress = (int)(percent * 100);
} else {
double percentPerFile = 100.0f / details.totalFiles;
progress = (int)((percentPerFile * (details.currentFile - 1)) +
(percent * percentPerFile));
}
if (details.sura > 0 && details.ayah > 0) {
progress = (int) (((float) details.currentFile / (float) details.totalFiles) * 100.0f);
}
}
showNotification(details.title,
mAppContext.getString(R.string.downloading_title),
DOWNLOADING_NOTIFICATION, true, max, progress, isIndeterminate);
// send broadcast
Intent progressIntent = new Intent(ProgressIntent.INTENT_NAME);
progressIntent.putExtra(ProgressIntent.NAME, details.title);
progressIntent.putExtra(ProgressIntent.DOWNLOAD_KEY, details.key);
progressIntent.putExtra(ProgressIntent.DOWNLOAD_TYPE, details.type);
progressIntent.putExtra(ProgressIntent.STATE,
ProgressIntent.STATE_DOWNLOADING);
if (details.sura > 0) {
progressIntent.putExtra(ProgressIntent.SURA, details.sura);
progressIntent.putExtra(ProgressIntent.AYAH, details.ayah);
}
if (!isIndeterminate){
progressIntent.putExtra(ProgressIntent.DOWNLOADED_SIZE,
downloadedSize);
progressIntent.putExtra(ProgressIntent.TOTAL_SIZE, totalSize);
progressIntent.putExtra(ProgressIntent.PROGRESS, progress);
}
mBroadcastManager.sendBroadcast(progressIntent);
return progressIntent;
}
public Intent notifyDownloadProcessing(
NotificationDetails details, int done, int total){
String processingString =
mAppContext.getString(R.string.download_processing);
mNotificationManager.cancel(DOWNLOADING_NOTIFICATION);
showNotification(details.title, processingString,
DOWNLOADING_PROCESSING_NOTIFICATION, true);
// send broadcast
Intent progressIntent = new Intent(ProgressIntent.INTENT_NAME);
progressIntent.putExtra(ProgressIntent.NAME, details.title);
progressIntent.putExtra(ProgressIntent.DOWNLOAD_KEY, details.key);
progressIntent.putExtra(ProgressIntent.DOWNLOAD_TYPE, details.type);
progressIntent.putExtra(ProgressIntent.STATE,
ProgressIntent.STATE_PROCESSING);
if (total > 0){
int progress = (int)((100.0 * done) / (1.0 * total));
progressIntent.putExtra(ProgressIntent.PROGRESS, progress);
progressIntent.putExtra(ProgressIntent.PROCESSED_FILES, done);
progressIntent.putExtra(ProgressIntent.TOTAL_FILES, total);
}
mBroadcastManager.sendBroadcast(progressIntent);
return progressIntent;
}
public Intent notifyDownloadSuccessful(NotificationDetails details){
String successString = mAppContext.getString(R.string.download_successful);
mNotificationManager.cancel(DOWNLOADING_NOTIFICATION);
mNotificationManager.cancel(DOWNLOADING_PROCESSING_NOTIFICATION);
mNotificationManager.cancel(DOWNLOADING_ERROR_NOTIFICATION);
mLastMaximum = -1;
mLastProgress = -1;
showNotification(details.title, successString,
DOWNLOADING_COMPLETE_NOTIFICATION, false);
return broadcastDownloadSuccessful(details);
}
public Intent broadcastDownloadSuccessful(NotificationDetails details){
// send broadcast
Intent progressIntent = new Intent(ProgressIntent.INTENT_NAME);
progressIntent.putExtra(ProgressIntent.NAME, details.title);
progressIntent.putExtra(ProgressIntent.STATE,
ProgressIntent.STATE_SUCCESS);
progressIntent.putExtra(ProgressIntent.DOWNLOAD_KEY, details.key);
progressIntent.putExtra(ProgressIntent.DOWNLOAD_TYPE, details.type);
mBroadcastManager.sendBroadcast(progressIntent);
return progressIntent;
}
public Intent notifyError(int errorCode, boolean isFatal,
NotificationDetails details){
int errorId;
switch (errorCode){
case ERROR_DISK_SPACE:
errorId = R.string.download_error_disk;
break;
case ERROR_NETWORK:
errorId = R.string.download_error_network;
break;
case ERROR_PERMISSIONS:
errorId = R.string.download_error_perms;
break;
case ERROR_INVALID_DOWNLOAD:
errorId = R.string.download_error_invalid_download;
if (!isFatal){
errorId = R.string.download_error_invalid_download_retry;
}
break;
case ERROR_CANCELLED:
errorId = R.string.notification_download_canceled;
break;
case ERROR_GENERAL:
default:
errorId = R.string.download_error_general;
break;
}
String errorString = mAppContext.getString(errorId);
mNotificationManager.cancel(DOWNLOADING_NOTIFICATION);
showNotification(details.title, errorString,
DOWNLOADING_ERROR_NOTIFICATION, false);
String state = isFatal? ProgressIntent.STATE_ERROR :
ProgressIntent.STATE_ERROR_WILL_RETRY;
// send broadcast
Intent progressIntent = new Intent(ProgressIntent.INTENT_NAME);
progressIntent.putExtra(ProgressIntent.NAME, details.title);
progressIntent.putExtra(ProgressIntent.DOWNLOAD_KEY, details.key);
progressIntent.putExtra(ProgressIntent.DOWNLOAD_TYPE, details.type);
progressIntent.putExtra(ProgressIntent.STATE, state);
progressIntent.putExtra(ProgressIntent.ERROR_CODE, errorCode);
mBroadcastManager.sendBroadcast(progressIntent);
return progressIntent;
}
private void showNotification(String titleString,
String statusString, int notificationId, boolean isOnGoing) {
showNotification(titleString, statusString, notificationId,
isOnGoing, 0, 0, false);
}
private void showNotification(String titleString,
String statusString, int notificationId, boolean isOnGoing,
int maximum, int progress, boolean isIndeterminate){
NotificationCompat.Builder builder =
new NotificationCompat.Builder(mAppContext);
builder.setSmallIcon(R.drawable.ic_notification)
.setColor(mNotificationColor)
.setAutoCancel(true)
.setOngoing(isOnGoing)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setContentTitle(titleString)
.setContentText(statusString);
boolean wantProgress = maximum > 0 && maximum >= progress;
if (mLastProgress == progress && mLastMaximum == maximum) {
// don't keep sending repeat notifications
return;
}
mLastProgress = progress;
mLastMaximum = maximum;
if (wantProgress) {
builder.setProgress(maximum, progress, isIndeterminate);
}
Intent notificationIntent = new Intent(mAppContext, QuranDataActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(
mAppContext, 0, notificationIntent, 0);
builder.setContentIntent(contentIntent);
try {
mNotificationManager.notify(notificationId, builder.build());
} catch (SecurityException se) {
Crashlytics.logException(se);
}
}
}