package fi.iki.murgo.irssinotifier; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import android.util.Log; import org.json.JSONArray; import org.json.JSONObject; 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; public class IrcNotificationManager { private static final String TAG = IrcNotificationManager.class.getName(); private static IrcNotificationManager instance; public static IrcNotificationManager getInstance() { if (instance == null) { instance = new IrcNotificationManager(); } return instance; } private IrcNotificationManager() { } private Map<String, List<IrcMessage>> unread = new HashMap<String, List<IrcMessage>>(); private int perMessageNotificationId = 2; private long lastSoundDate = 0; private DataAccess da; public long getLastSoundDate() { return lastSoundDate; } public void setLastSoundDate(long time) { lastSoundDate = time; } private int getUnreadCount() { int total = 0; for (List<IrcMessage> msgs : unread.values()) { total += msgs.size(); } return total; } public int getUnreadCountForChannel(String channel) { if (!unread.containsKey(channel.toLowerCase())) return 0; return unread.get(channel.toLowerCase()).size(); } private void addUnread(IrcMessage msg) { String key = msg.getLogicalChannel().toLowerCase(); List<IrcMessage> msgs; if (unread.containsKey(key)) msgs = unread.get(key); else { msgs = new ArrayList<IrcMessage>(); unread.put(key, msgs); } msgs.add(msg); } public void handle(Context context, IrcMessage msg) { Preferences prefs = new Preferences(context); NotificationMode mode = prefs.getNotificationMode(); String tickerText; String notificationMessage; String titleText; int notificationId; long when = new Date().getTime(); int currentUnreadCount = 1; List<String> messageLines = null; try { msg.decrypt(prefs.getEncryptionPassword()); if (da == null) da = new DataAccess(context); if (!da.handleMessage(msg)) { return; } addUnread(msg); ValueList values = getValues(msg, mode); notificationMessage = values.text; titleText = values.title; notificationId = values.id; when = msg.getServerTimestamp().getTime(); currentUnreadCount = values.count; messageLines = values.messageLines; tickerText = titleText; } catch (CryptoException e) { titleText = context.getString(R.string.irssinotifier_error_title); notificationMessage = context.getString(R.string.decryption_error_notification); tickerText = context.getString(R.string.decryption_error_ticker); notificationId = 1; } IrssiNotifierActivity foregroundInstance = IrssiNotifierActivity.getForegroundInstance(); if (foregroundInstance != null) { foregroundInstance.newMessage(msg); unread.clear(); return; } if (!prefs.isNotificationsEnabled()) { return; } NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setSmallIcon(R.drawable.notification_icon); builder.setTicker(tickerText); builder.setWhen(when); builder.setAutoCancel(true); builder.setContentText(notificationMessage); builder.setContentTitle(titleText); if (currentUnreadCount > 1) { builder.setNumber(currentUnreadCount); } int defaults = 0; if (prefs.isLightsEnabled()) { if (prefs.getUseDefaultLightColor()) { defaults |= Notification.DEFAULT_LIGHTS; } else { builder.setLights(prefs.getCustomLightColor(), 300, 5000); } } if ((!prefs.isSpamFilterEnabled() || new Date().getTime() > IrcNotificationManager .getInstance().getLastSoundDate() + (1000L * prefs.getSpamFilterTime()))) { if (prefs.isSoundEnabled()) { builder.setSound(prefs.getNotificationSound()); } if (prefs.isVibrationEnabled()) { defaults |= Notification.DEFAULT_VIBRATE; } lastSoundDate = new Date().getTime(); } builder.setDefaults(defaults); Intent toLaunch = new Intent(context, IrssiNotifierActivity.class); toLaunch.putExtra("Channel", msg.getLogicalChannel()); toLaunch.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); toLaunch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent contentIntent = PendingIntent.getActivity(context, 0, toLaunch, PendingIntent.FLAG_UPDATE_CURRENT); builder.setContentIntent(contentIntent); Intent deleteIntent = new Intent(NotificationClearedReceiver.NOTIFICATION_CLEARED_INTENT); deleteIntent.putExtra("notificationMode", mode.toString()); deleteIntent.putExtra("channel", msg.getLogicalChannel()); PendingIntent pendingDeleteIntent = PendingIntent.getBroadcast(context, 0, deleteIntent, 0); builder.setDeleteIntent(pendingDeleteIntent); if (messageLines != null && messageLines.size() > 1) { NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(); for (String line : messageLines) inboxStyle.addLine(line); builder.setStyle(inboxStyle); } Notification notification = builder.build(); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(notificationId, notification); if (prefs.isPebbleEnabled()) { try { notifyPebble(context, msg); } catch (Exception e) { // don't crash from pebble notifications Log.e(TAG, "Exception while notifying pebble", e); } } } private void notifyPebble(Context context, IrcMessage msg) { Intent pebbleIntent = new Intent("com.getpebble.action.SEND_NOTIFICATION"); Map<String, String> data = new HashMap<String, String>(); ValueList values = getValues(msg, NotificationMode.PerMessage); data.put("title", values.title); data.put("body", values.text); String notificationData = new JSONArray().put(new JSONObject(data)).toString(); pebbleIntent.putExtra("messageType", "PEBBLE_ALERT"); pebbleIntent.putExtra("sender", "IrssiNotifier"); pebbleIntent.putExtra("notificationData", notificationData); context.sendBroadcast(pebbleIntent); } public boolean mainActivityOpened(Context context) { boolean hadMessages = false; if (unread != null) { hadMessages = unread.size() > 0; unread.clear(); } NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.cancelAll(); return hadMessages; } private ValueList getValues(IrcMessage msg, NotificationMode mode) { String text = null; String title = null; int id = 0; int count = 0; ArrayList<String> messageLines = new ArrayList<String>(); switch (mode) { case Single: id = 1; int unreadCount = getUnreadCount(); count = unreadCount; if (unreadCount <= 1) { if (msg.isPrivate()) { title = "Query from " + msg.getNick(); text = msg.getMessage(); } else { title = "Hilight at " + msg.getChannel(); text = "(" + msg.getNick() + ") " + msg.getMessage(); } } else { if (msg.isPrivate()) { title = "" + unreadCount + " new hilights"; text = "Last: (" + msg.getNick() + ") " + msg.getMessage(); } else { title = "" + unreadCount + " new hilights"; text = "Last: " + msg.getLogicalChannel() + " (" + msg.getNick() + ") " + msg.getMessage(); } List<IrcMessage> allMessages = new ArrayList<IrcMessage>(); for (List<IrcMessage> list : unread.values()) { allMessages.addAll(list); } Collections.sort(allMessages, new Comparator<IrcMessage>() { public int compare(IrcMessage lhs, IrcMessage rhs) { return lhs.getServerTimestamp().compareTo(rhs.getServerTimestamp()); } }); for (IrcMessage message : allMessages) { if (message.isPrivate()) { messageLines.add("(" + message.getNick() + ") " + message.getMessage()); } else { messageLines.add(message.getLogicalChannel() + " (" + message.getNick() + ") " + message.getMessage()); } } } break; case PerMessage: id = perMessageNotificationId++; count = 1; if (msg.isPrivate()) { title = "Query from " + msg.getNick(); text = msg.getMessage(); } else { title = "Hilight at " + msg.getChannel(); text = "(" + msg.getNick() + ") " + msg.getMessage(); } break; case PerChannel: int channelUnreadCount = getUnreadCountForChannel(msg.getLogicalChannel()); id = msg.getLogicalChannel().toLowerCase().hashCode(); count = channelUnreadCount; if (msg.isPrivate()) { if (channelUnreadCount <= 1) { title = "Query from " + msg.getNick(); text = msg.getMessage(); } else { title = "" + channelUnreadCount + " queries from " + msg.getNick(); text = "Last: " + msg.getMessage(); } } else { if (channelUnreadCount <= 1) { title = "Hilight at " + msg.getChannel(); text = "(" + msg.getNick() + ") " + msg.getMessage(); } else { title = "" + channelUnreadCount + " new hilights at " + msg.getChannel(); text = "Last: (" + msg.getNick() + ") " + msg.getMessage(); } } List<IrcMessage> messages = unread.get(msg.getLogicalChannel().toLowerCase()); for (IrcMessage message : messages) { messageLines.add("(" + message.getNick() + ") " + message.getMessage()); } break; } ValueList values = new ValueList(); values.text = text; values.title = title; values.id = id; values.count = count; values.messageLines = messageLines; return values; } public void notificationCleared(Context context, Intent intent) { if (unread == null) { return; } NotificationMode mode = NotificationMode.valueOf(intent.getStringExtra("notificationMode")); if (mode == NotificationMode.Single) { unread.clear(); } else if (mode == NotificationMode.PerChannel) { String channel = intent.getStringExtra("channel"); if (channel != null) { List<IrcMessage> msgs = unread.get(channel.toLowerCase()); if (msgs != null) { msgs.clear(); } } } } private class ValueList { public String text; public String title; public int id; public int count; public List<String> messageLines; } }