package com.kenny.openimgur.services; import android.app.IntentService; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.os.PowerManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.support.v4.app.RemoteInput; import android.text.Html; import android.text.TextUtils; import android.text.format.DateUtils; import com.kenny.openimgur.R; import com.kenny.openimgur.activities.SettingsActivity; import com.kenny.openimgur.api.ApiClient; import com.kenny.openimgur.api.responses.NotificationResponse; import com.kenny.openimgur.classes.ImgurAlbum; import com.kenny.openimgur.classes.ImgurBaseObject; import com.kenny.openimgur.classes.ImgurComment; import com.kenny.openimgur.classes.ImgurPhoto; import com.kenny.openimgur.classes.OpengurApp; import com.kenny.openimgur.ui.BaseNotification; import com.kenny.openimgur.ui.CircleBitmapDisplayer; import com.kenny.openimgur.util.ImageUtil; import com.kenny.openimgur.util.LogUtil; import com.kenny.openimgur.util.NetworkUtils; import com.kenny.openimgur.util.RequestCodes; import com.kenny.openimgur.util.SqlHelper; import com.nostra13.universalimageloader.core.assist.ImageSize; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import retrofit2.Response; import static android.os.Build.VERSION_CODES.N; /** * Created by kcampagna on 8/12/15. */ public class NotificationService extends IntentService { private static final String TAG = NotificationService.class.getSimpleName(); public static Intent createIntent(Context context) { return new Intent(context, NotificationService.class); } public NotificationService() { super(TAG); } @Override protected void onHandleIntent(Intent intent) { OpengurApp app = OpengurApp.getInstance(getApplicationContext()); boolean enabled = app.getPreferences().getBoolean(SettingsActivity.KEY_NOTIFICATIONS, true); if (!enabled) { LogUtil.v(TAG, "Notifications have been disabled, not fetching"); return; } // Make sure we have a valid user if (app.getUser() != null) { PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); wakeLock.acquire(); try { Response<NotificationResponse> response = ApiClient.getService().getNotifications().execute(); if (response != null && response.body() != null && response.body().hasNotifications()) { NotificationResponse notificationResponse = response.body(); SqlHelper.getInstance(getApplicationContext()).insertNotifications(notificationResponse); Notification notification = new Notification(getApplicationContext(), notificationResponse.data); notification.postNotification(); } else { LogUtil.v(TAG, "No notifications found"); } } catch (Exception ex) { LogUtil.e(TAG, "Error fetching notifications", ex); } finally { NetworkUtils.releaseWakeLock(wakeLock); } // Create the next alarm when everything is finished AlarmReceiver.createNotificationAlarm(getApplicationContext()); } else { LogUtil.w(TAG, "Can not fetch notifications, no user found"); } } private static class Notification extends BaseNotification { private static final int NOTIFICATION_ID = RequestCodes.NOTIFICATIONS; private static final int MIN_TEXT_LENGTH = 40; private static final int MAX_INBOX_LINES = 3; private String mTitle; private Uri mNotificationSound; private boolean mVibrate = false; public Notification(Context context, NotificationResponse.Data data) { super(context, false); SharedPreferences pref = app.getPreferences(); mVibrate = pref.getBoolean(SettingsActivity.KEY_NOTIFICATION_VIBRATE, true); String ringTone = pref.getString(SettingsActivity.KEY_NOTIFICATION_RINGTONE, null); if (!TextUtils.isEmpty(ringTone)) { try { mNotificationSound = Uri.parse(ringTone); } catch (Exception e) { LogUtil.e(TAG, "Unable to parse ringtone", e); mNotificationSound = null; } } buildNotification(data); build(context); } private void buildNotification(NotificationResponse.Data data) { Set<ImgurComment> replies = new HashSet<>(); for (NotificationResponse.Replies r : data.replies) { replies.add(r.content); } int replyNotifications = replies.size(); PendingIntent pendingIntent; ImgurBaseObject obj = null; boolean hasOnlyOne = replyNotifications == 1; mTitle = resources.getQuantityString(R.plurals.notification_replies, replyNotifications, replyNotifications); if (hasOnlyOne) { // Only have one reply, show its contents ImgurComment comment = replies.iterator().next(); obj = comment; int messageLength = comment.getComment().length() - MIN_TEXT_LENGTH; // Big text style won't display if less than 40 characters if (messageLength > 0) { builder.setContentText(resources.getString(R.string.notification_new_message, comment.getAuthor())); builder.setStyle(new NotificationCompat.BigTextStyle() .bigText(comment.getComment()) .setBigContentTitle(comment.getAuthor())); } else { String formatted = resources.getString(R.string.notification_preview, comment.getAuthor(), comment.getComment()); builder.setContentText(Html.fromHtml(formatted)); } String photoUrl; if (TextUtils.isEmpty(comment.getAlbumCoverId())) { photoUrl = ApiClient.IMGUR_URL + comment.getImageId() + ImgurPhoto.THUMBNAIL_MEDIUM + ".jpeg"; } else { photoUrl = String.format(ImgurAlbum.ALBUM_COVER_URL, comment.getAlbumCoverId() + ImgurPhoto.THUMBNAIL_MEDIUM); } Bitmap b = getReplyIcon(photoUrl); if (b != null) { builder.setLargeIcon(b); } else { builder.setLargeIcon(createLargeIcon(-1, comment.getAuthor())); } } else { // Multiple replies, show the first three NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle(); Iterator<ImgurComment> r = replies.iterator(); int remaining = MAX_INBOX_LINES - replyNotifications; int i = 0; while (r.hasNext() && i < MAX_INBOX_LINES) { ImgurComment comment = r.next(); style.addLine(Html.fromHtml(resources.getString(R.string.notification_preview, comment.getAuthor(), comment.getComment()))); i++; } if (remaining < 0) { style.setSummaryText(resources.getString(R.string.notification_remaining, Math.abs(remaining))); } // The Large icon will be the reply icon builder.setStyle(style); builder.setLargeIcon(createLargeIcon(R.drawable.ic_reply_all_24dp, null)); } Intent intent = NotificationReceiver.createNotificationIntent(app, obj); pendingIntent = PendingIntent.getBroadcast(app, getNotificationId(), intent, PendingIntent.FLAG_ONE_SHOT); builder.setContentIntent(pendingIntent); Intent readIntent = NotificationReceiver.createReadNotificationsIntent(app, getNotificationId()); PendingIntent readPIntent = PendingIntent.getBroadcast(app, RequestCodes.NOTIFICATIONS_READ, readIntent, PendingIntent.FLAG_ONE_SHOT); String msg = resources.getQuantityString(R.plurals.notification_mark_read, replyNotifications); builder.addAction(R.drawable.ic_done_24dp, msg, readPIntent); } @Override protected Uri getNotificationSound() { return mNotificationSound; } @Override protected long getVibration() { return mVibrate ? DateUtils.SECOND_IN_MILLIS : 0; } @NonNull @Override protected String getTitle() { return mTitle; } @Override protected int getNotificationId() { return NOTIFICATION_ID; } @Override protected void postNotification(android.app.Notification notification) { notification.flags |= android.app.Notification.FLAG_ONLY_ALERT_ONCE; super.postNotification(notification); } @Nullable private Bitmap getReplyIcon(String url) { try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Bitmap bitmap = ImageUtil.getImageLoader(app).loadImageSync(url); if (bitmap != null) return CircleBitmapDisplayer.getRoundedBitmap(bitmap); } else { int iconSize = resources.getDimensionPixelSize(R.dimen.notification_icon); return ImageUtil.getImageLoader(app).loadImageSync(url, new ImageSize(iconSize, iconSize)); } } catch (Exception ex) { LogUtil.e(TAG, "Unable to load gallery thumbnail", ex); } return null; } } }