Support for bundled notifications (Android wear and Android N)

// FREEBIE
This commit is contained in:
Moxie Marlinspike
2016-12-25 15:27:59 -08:00
parent 0c6bfdbd0d
commit a9bd84c69c
9 changed files with 154 additions and 79 deletions

View File

@@ -30,14 +30,17 @@ import android.media.RingtoneManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.service.notification.StatusBarNotification;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationManagerCompat;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.StyleSpan;
import android.util.Log;
import org.thoughtcrime.redphone.ui.NotificationBarManager;
import org.thoughtcrime.redphone.util.Util;
import org.thoughtcrime.securesms.ConversationActivity;
import org.thoughtcrime.securesms.R;
@@ -84,7 +87,9 @@ public class MessageNotifier {
private static final String TAG = MessageNotifier.class.getSimpleName();
public static final String EXTRA_VOICE_REPLY = "extra_voice_reply";
public static final int NOTIFICATION_ID = 1338;
private static final int SUMMARY_NOTIFICATION_ID = 1338;
private static final String NOTIFICATION_GROUP = "messages";
private static final long MIN_AUDIBLE_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(2);
private static final long DESKTOP_ACTIVITY_PERIOD = TimeUnit.MINUTES.toMillis(1);
@@ -101,10 +106,6 @@ public class MessageNotifier {
lastDesktopActivityTimestamp = timestamp;
}
public static void cancelDelayedNotifications() {
executor.cancel();
}
public static void notifyMessageDeliveryFailed(Context context, Recipients recipients, long threadId) {
if (visibleThread == threadId) {
sendInThreadNotification(context, recipients);
@@ -120,6 +121,49 @@ public class MessageNotifier {
}
}
public static void cancelDelayedNotifications() {
executor.cancel();
}
private static void cancelActiveNotifications(@NonNull Context context) {
NotificationManager notifications = ServiceUtil.getNotificationManager(context);
notifications.cancel(SUMMARY_NOTIFICATION_ID);
if (Build.VERSION.SDK_INT >= 23) {
StatusBarNotification[] activeNotifications = notifications.getActiveNotifications();
for (StatusBarNotification activeNotification : activeNotifications) {
if (activeNotification.getId() != NotificationBarManager.RED_PHONE_NOTIFICATION) {
notifications.cancel(activeNotification.getId());
}
}
}
}
private static void cancelOrphanedNotifications(@NonNull Context context, NotificationState notificationState) {
if (Build.VERSION.SDK_INT >= 23) {
NotificationManager notifications = ServiceUtil.getNotificationManager(context);
StatusBarNotification[] activeNotifications = notifications.getActiveNotifications();
for (StatusBarNotification notification : activeNotifications) {
boolean validNotification = false;
if (notification.getId() != SUMMARY_NOTIFICATION_ID && notification.getId() != NotificationBarManager.RED_PHONE_NOTIFICATION) {
for (NotificationItem item : notificationState.getNotifications()) {
if (notification.getId() == (SUMMARY_NOTIFICATION_ID + item.getThreadId())) {
validNotification = true;
break;
}
}
if (!validNotification) {
notifications.cancel(notification.getId());
}
}
}
}
}
public static void updateNotification(@NonNull Context context, @Nullable MasterSecret masterSecret) {
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
return;
@@ -194,8 +238,7 @@ public class MessageNotifier {
if ((telcoCursor == null || telcoCursor.isAfterLast()) &&
(pushCursor == null || pushCursor.isAfterLast()))
{
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
.cancel(NOTIFICATION_ID);
cancelActiveNotifications(context);
updateBadge(context, 0);
clearReminder(context);
return;
@@ -214,11 +257,18 @@ public class MessageNotifier {
}
if (notificationState.hasMultipleThreads()) {
if (Build.VERSION.SDK_INT >= 23) {
for (long threadId : notificationState.getThreads()) {
sendSingleThreadNotification(context, masterSecret, new NotificationState(notificationState.getNotificationsForThread(threadId)), false, true);
}
}
sendMultipleThreadNotification(context, notificationState, signal);
} else {
sendSingleThreadNotification(context, masterSecret, notificationState, signal);
sendSingleThreadNotification(context, masterSecret, notificationState, signal, false);
}
cancelOrphanedNotifications(context, notificationState);
updateBadge(context, notificationState.getMessageCount());
if (signal) {
@@ -233,33 +283,35 @@ public class MessageNotifier {
private static void sendSingleThreadNotification(@NonNull Context context,
@Nullable MasterSecret masterSecret,
@NonNull NotificationState notificationState,
boolean signal)
boolean signal, boolean bundled)
{
if (notificationState.getNotifications().isEmpty()) {
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
.cancel(NOTIFICATION_ID);
if (!bundled) cancelActiveNotifications(context);
return;
}
SingleRecipientNotificationBuilder builder = new SingleRecipientNotificationBuilder(context, masterSecret, TextSecurePreferences.getNotificationPrivacy(context));
List<NotificationItem> notifications = notificationState.getNotifications();
Recipients recipients = notifications.get(0).getRecipients();
SingleRecipientNotificationBuilder builder = new SingleRecipientNotificationBuilder(context, masterSecret, TextSecurePreferences.getNotificationPrivacy(context));
List<NotificationItem> notifications = notificationState.getNotifications();
Recipients recipients = notifications.get(0).getRecipients();
int notificationId = (int) (SUMMARY_NOTIFICATION_ID + (bundled ? notifications.get(0).getThreadId() : 0));
builder.setThread(notifications.get(0).getRecipients());
builder.setMessageCount(notificationState.getMessageCount());
builder.setPrimaryMessageBody(recipients, notifications.get(0).getIndividualRecipient(),
notifications.get(0).getText(), notifications.get(0).getSlideDeck());
builder.setContentIntent(notifications.get(0).getPendingIntent(context));
builder.setGroup(NOTIFICATION_GROUP);
long timestamp = notifications.get(0).getTimestamp();
if (timestamp != 0) builder.setWhen(timestamp);
builder.addActions(masterSecret,
notificationState.getMarkAsReadIntent(context),
notificationState.getMarkAsReadIntent(context, notificationId),
notificationState.getQuickReplyIntent(context, notifications.get(0).getRecipients()),
notificationState.getWearableReplyIntent(context, notifications.get(0).getRecipients()));
builder.addAndroidAutoAction(notificationState.getAndroidAutoReplyIntent(context, notifications.get(0).getRecipients()),
notificationState.getAndroidAutoHeardIntent(context, notifications.get(0).getRecipients()), notifications.get(0).getTimestamp());
notificationState.getAndroidAutoHeardIntent(context, notificationId), notifications.get(0).getTimestamp());
ListIterator<NotificationItem> iterator = notifications.listIterator(notifications.size());
@@ -274,8 +326,11 @@ public class MessageNotifier {
notifications.get(0).getText());
}
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
.notify(NOTIFICATION_ID, builder.build());
if (!bundled) {
builder.setGroupSummary(true);
}
NotificationManagerCompat.from(context).notify(notificationId, builder.build());
}
private static void sendMultipleThreadNotification(@NonNull Context context,
@@ -287,11 +342,12 @@ public class MessageNotifier {
builder.setMessageCount(notificationState.getMessageCount(), notificationState.getThreadCount());
builder.setMostRecentSender(notifications.get(0).getIndividualRecipient());
builder.setGroup(NOTIFICATION_GROUP);
long timestamp = notifications.get(0).getTimestamp();
if (timestamp != 0) builder.setWhen(timestamp);
builder.addActions(notificationState.getMarkAsReadIntent(context));
builder.addActions(notificationState.getMarkAsReadIntent(context, SUMMARY_NOTIFICATION_ID));
ListIterator<NotificationItem> iterator = notifications.listIterator(notifications.size());
@@ -306,8 +362,7 @@ public class MessageNotifier {
notifications.get(0).getText());
}
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
.notify(NOTIFICATION_ID, builder.build());
NotificationManagerCompat.from(context).notify(SUMMARY_NOTIFICATION_ID, builder.build());
}
private static void sendInThreadNotification(Context context, Recipients recipients) {