package com.fsck.k9.notification;
import java.util.ArrayList;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import android.util.SparseBooleanArray;
import com.fsck.k9.Account;
import com.fsck.k9.activity.MessageReference;
/**
* A holder class for pending new mail notifications.
*/
class NotificationData {
// Note: As of Jellybean, phone notifications show a maximum of 5 lines, while tablet notifications show 7 lines.
static final int MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION = 5;
// Note: This class assumes MAX_NUMBER_OF_STACKED_NOTIFICATIONS >= MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION
static final int MAX_NUMBER_OF_STACKED_NOTIFICATIONS = 8;
private final Account account;
private final LinkedList<NotificationHolder> activeNotifications = new LinkedList<NotificationHolder>();
private final Deque<NotificationContent> additionalNotifications = new LinkedList<NotificationContent>();
private final SparseBooleanArray notificationIdsInUse = new SparseBooleanArray();
private int unreadMessageCount;
public NotificationData(Account account) {
this.account = account;
}
public AddNotificationResult addNotificationContent(NotificationContent content) {
int notificationId;
boolean cancelNotificationIdBeforeReuse;
if (isMaxNumberOfActiveNotificationsReached()) {
NotificationHolder notificationHolder = activeNotifications.removeLast();
addToAdditionalNotifications(notificationHolder);
notificationId = notificationHolder.notificationId;
cancelNotificationIdBeforeReuse = true;
} else {
notificationId = getNewNotificationId();
cancelNotificationIdBeforeReuse = false;
}
NotificationHolder notificationHolder = createNotificationHolder(notificationId, content);
activeNotifications.addFirst(notificationHolder);
if (cancelNotificationIdBeforeReuse) {
return AddNotificationResult.replaceNotification(notificationHolder);
} else {
return AddNotificationResult.newNotification(notificationHolder);
}
}
private boolean isMaxNumberOfActiveNotificationsReached() {
return activeNotifications.size() == MAX_NUMBER_OF_STACKED_NOTIFICATIONS;
}
private void addToAdditionalNotifications(NotificationHolder notificationHolder) {
additionalNotifications.addFirst(notificationHolder.content);
}
private int getNewNotificationId() {
for (int i = 0; i < MAX_NUMBER_OF_STACKED_NOTIFICATIONS; i++) {
int notificationId = NotificationIds.getNewMailStackedNotificationId(account, i);
if (!isNotificationInUse(notificationId)) {
markNotificationIdAsInUse(notificationId);
return notificationId;
}
}
throw new AssertionError("getNewNotificationId() called with no free notification ID");
}
private boolean isNotificationInUse(int notificationId) {
return notificationIdsInUse.get(notificationId);
}
private void markNotificationIdAsInUse(int notificationId) {
notificationIdsInUse.put(notificationId, true);
}
private void markNotificationIdAsFree(int notificationId) {
notificationIdsInUse.delete(notificationId);
}
NotificationHolder createNotificationHolder(int notificationId, NotificationContent content) {
return new NotificationHolder(notificationId, content);
}
public boolean containsStarredMessages() {
for (NotificationHolder holder : activeNotifications) {
if (holder.content.starred) {
return true;
}
}
for (NotificationContent content : additionalNotifications) {
if (content.starred) {
return true;
}
}
return false;
}
public boolean hasSummaryOverflowMessages() {
return activeNotifications.size() > MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION;
}
public int getSummaryOverflowMessagesCount() {
int activeOverflowCount = activeNotifications.size() - MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION;
if (activeOverflowCount > 0) {
return activeOverflowCount + additionalNotifications.size();
}
return additionalNotifications.size();
}
public int getNewMessagesCount() {
return activeNotifications.size() + additionalNotifications.size();
}
public boolean isSingleMessageNotification() {
return activeNotifications.size() == 1;
}
public NotificationHolder getHolderForLatestNotification() {
return activeNotifications.getFirst();
}
public List<NotificationContent> getContentForSummaryNotification() {
int size = calculateNumberOfMessagesForSummaryNotification();
List<NotificationContent> result = new ArrayList<NotificationContent>(size);
Iterator<NotificationHolder> iterator = activeNotifications.iterator();
int notificationCount = 0;
while (iterator.hasNext() && notificationCount < MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION) {
NotificationHolder holder = iterator.next();
result.add(holder.content);
notificationCount++;
}
return result;
}
private int calculateNumberOfMessagesForSummaryNotification() {
return Math.min(activeNotifications.size(), MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION);
}
public int[] getActiveNotificationIds() {
int size = activeNotifications.size();
int[] notificationIds = new int[size];
for (int i = 0; i < size; i++) {
NotificationHolder holder = activeNotifications.get(i);
notificationIds[i] = holder.notificationId;
}
return notificationIds;
}
public RemoveNotificationResult removeNotificationForMessage(MessageReference messageReference) {
NotificationHolder holder = getNotificationHolderForMessage(messageReference);
if (holder == null) {
return RemoveNotificationResult.unknownNotification();
}
activeNotifications.remove(holder);
int notificationId = holder.notificationId;
markNotificationIdAsFree(notificationId);
if (!additionalNotifications.isEmpty()) {
NotificationContent newContent = additionalNotifications.removeFirst();
NotificationHolder replacement = createNotificationHolder(notificationId, newContent);
activeNotifications.addLast(replacement);
return RemoveNotificationResult.createNotification(replacement);
}
return RemoveNotificationResult.cancelNotification(notificationId);
}
private NotificationHolder getNotificationHolderForMessage(MessageReference messageReference) {
for (NotificationHolder holder : activeNotifications) {
if (messageReference.equals(holder.content.messageReference)) {
return holder;
}
}
return null;
}
public Account getAccount() {
return account;
}
public int getUnreadMessageCount() {
return unreadMessageCount + getNewMessagesCount();
}
public void setUnreadMessageCount(int unreadMessageCount) {
this.unreadMessageCount = unreadMessageCount;
}
public ArrayList<MessageReference> getAllMessageReferences() {
int newSize = activeNotifications.size() + additionalNotifications.size();
ArrayList<MessageReference> messageReferences = new ArrayList<MessageReference>(newSize);
for (NotificationHolder holder : activeNotifications) {
messageReferences.add(holder.content.messageReference);
}
for (NotificationContent content : additionalNotifications) {
messageReferences.add(content.messageReference);
}
return messageReferences;
}
}