notifications for new messages are displayed and hidden appropriately #32

This commit is contained in:
Angelo Fuchs
2018-10-31 12:23:16 +02:00
parent c8accec761
commit 5a9220356c
6 changed files with 127 additions and 123 deletions
@@ -25,6 +25,9 @@ import android.support.annotation.NonNull;
import android.support.multidex.MultiDexApplication;
import android.util.Log;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEventCenter;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.crypto.PRNGFixes;
import org.thoughtcrime.securesms.dependencies.AxolotlStorageModule;
@@ -38,6 +41,7 @@ import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirementProvider;
import org.thoughtcrime.securesms.jobs.requirements.SqlCipherMigrationRequirementProvider;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.util.ScreenLockUtil;
@@ -93,6 +97,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
//initializeSignedPreKeyCheck(); -- keys are generated in the core, however, not sure if this is needed for the lock screen
initializePeriodicTasks();
initializeWebRtc();
initializeIncomingMessageNotifier();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@@ -137,6 +142,13 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
SignalProtocolLoggerProvider.setProvider(new AndroidSignalProtocolLogger());
}
private void initializeIncomingMessageNotifier() {
DcEventCenter dcEventCenter = dcContext.eventCenter;
dcEventCenter.addObserver((eventId, data1, data2)
-> MessageNotifier.updateNotification(dcContext.context), DcContext.DC_EVENT_INCOMING_MSG);
}
private void initializeJobManager() {
this.jobManager = JobManager.newBuilder(this)
.withName("TextSecureJobs")
@@ -6,6 +6,8 @@ import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.database.DatabaseFactory;
public class DeleteNotificationReceiver extends BroadcastReceiver {
@@ -13,24 +15,22 @@ public class DeleteNotificationReceiver extends BroadcastReceiver {
public static String DELETE_NOTIFICATION_ACTION = "org.thoughtcrime.securesms.DELETE_NOTIFICATION";
public static String EXTRA_IDS = "message_ids";
public static String EXTRA_MMS = "is_mms";
@Override
public void onReceive(final Context context, Intent intent) {
if (DELETE_NOTIFICATION_ACTION.equals(intent.getAction())) {
MessageNotifier.clearReminder(context);
final long[] ids = intent.getLongArrayExtra(EXTRA_IDS);
final boolean[] mms = intent.getBooleanArrayExtra(EXTRA_MMS);
final int[] ids = intent.getIntArrayExtra(EXTRA_IDS);
final ApplicationDcContext dcContext = DcHelper.getContext(context);
if (ids == null || mms == null || ids.length != mms.length) return;
if (ids == null || ids.length == 0) return;
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
for (int i=0;i<ids.length;i++) {
if (!mms[i]) DatabaseFactory.getSmsDatabase(context).markAsNotified(ids[i]);
else DatabaseFactory.getMmsDatabase(context).markAsNotified(ids[i]);
dcContext.marknoticedChat(dcContext.getMsg(ids[i]).getChatId());
}
return null;
@@ -11,8 +11,11 @@ import android.util.Log;
import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;
import com.b44t.messenger.DcContext;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.ExpirationInfo;
@@ -39,7 +42,7 @@ public class MarkReadReceiver extends BroadcastReceiver {
if (!CLEAR_ACTION.equals(intent.getAction()))
return;
final long[] threadIds = intent.getLongArrayExtra(THREAD_IDS_EXTRA);
final int[] threadIds = intent.getIntArrayExtra(THREAD_IDS_EXTRA);
if (threadIds != null) {
NotificationManagerCompat.from(context).cancel(intent.getIntExtra(NOTIFICATION_ID_EXTRA, -1));
@@ -49,12 +52,14 @@ public class MarkReadReceiver extends BroadcastReceiver {
protected Void doInBackground(Void... params) {
List<MarkedMessageInfo> messageIdsCollection = new LinkedList<>();
for (long threadId : threadIds) {
for (int threadId : threadIds) {
Log.w(TAG, "Marking as read: " + threadId);
List<MarkedMessageInfo> messageIds = DatabaseFactory.getThreadDatabase(context).setRead(threadId, true);
messageIdsCollection.addAll(messageIds);
ApplicationDcContext dcContext = DcHelper.getContext(context);
dcContext.marknoticedChat(threadId);
// here the messageIdsCollection had been filled by Signal code. Remove this comment as soon as it doesn't make sense.
}
// todo: the next line should be removed.
process(context, messageIdsCollection);
MessageNotifier.updateNotification(context);
@@ -23,7 +23,6 @@ import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.Ringtone;
@@ -37,17 +36,18 @@ import android.support.v4.app.NotificationManagerCompat;
import android.text.TextUtils;
import android.util.Log;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcMsg;
import org.thoughtcrime.securesms.ConversationActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.contactshare.ContactUtil;
import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.service.KeyCachingService;
@@ -193,6 +193,11 @@ public class MessageNotifier {
}
public static void updateNotification(@NonNull Context context, long threadId)
{
throw new IllegalStateException("old signal code called. thread -> chat, long -> int");
}
public static void updateNotification(@NonNull Context context, int threadId)
{
if (System.currentTimeMillis() - lastDesktopActivityTimestamp < DESKTOP_ACTIVITY_PERIOD) {
Log.w(TAG, "Scheduling delayed notification...");
@@ -204,27 +209,31 @@ public class MessageNotifier {
public static void updateNotification(@NonNull Context context,
long threadId,
boolean signal) {
throw new IllegalStateException("Old signal code called. thread -> chat & long -> int");
}
public static void updateNotification(@NonNull Context context,
int chatId,
boolean signal)
{
boolean isVisible = visibleThread == threadId;
boolean isVisible = visibleThread == chatId;
ApplicationDcContext dcContext = DcHelper.getContext(context);
ThreadDatabase threads = DatabaseFactory.getThreadDatabase(context);
Recipient recipients = DatabaseFactory.getThreadDatabase(context)
.getRecipientForThreadId(threadId);
Recipient recipient = dcContext.getRecipient(dcContext.getChat(chatId));
if (isVisible) {
List<MarkedMessageInfo> messageIds = threads.setRead(threadId, false);
MarkReadReceiver.process(context, messageIds);
dcContext.marknoticedChat(chatId);
}
if (!TextSecurePreferences.isNotificationsEnabled(context) ||
(recipients != null && recipients.isMuted()))
(recipient != null && recipient.isMuted()))
{
return;
}
if (isVisible) {
sendInThreadNotification(context, threads.getRecipientForThreadId(threadId));
sendInThreadNotification(context, recipient);
} else {
updateNotification(context, signal, 0);
}
@@ -234,51 +243,42 @@ public class MessageNotifier {
boolean signal,
int reminderCount)
{
Cursor telcoCursor = null;
Cursor pushCursor = null;
ApplicationDcContext dcContext = DcHelper.getContext(context);
int[] freshMessages = dcContext.getFreshMsgs();
try {
telcoCursor = DatabaseFactory.getMmsSmsDatabase(context).getUnread();
pushCursor = DatabaseFactory.getPushDatabase(context).getPending();
if (freshMessages.length == 0)
{
cancelActiveNotifications(context);
updateBadge(context, 0);
clearReminder(context);
return;
}
if ((telcoCursor == null || telcoCursor.isAfterLast()) &&
(pushCursor == null || pushCursor.isAfterLast()))
{
cancelActiveNotifications(context);
updateBadge(context, 0);
clearReminder(context);
return;
}
NotificationState notificationState = constructNotificationState(dcContext, freshMessages);
NotificationState notificationState = constructNotificationState(context, telcoCursor);
if (signal && (System.currentTimeMillis() - lastAudibleNotification) < MIN_AUDIBLE_PERIOD_MILLIS) {
signal = false;
} else if (signal) {
lastAudibleNotification = System.currentTimeMillis();
}
if (signal && (System.currentTimeMillis() - lastAudibleNotification) < MIN_AUDIBLE_PERIOD_MILLIS) {
signal = false;
} else if (signal) {
lastAudibleNotification = System.currentTimeMillis();
}
if (notificationState.hasMultipleThreads()) {
if (Build.VERSION.SDK_INT >= 23) {
for (long threadId : notificationState.getThreads()) {
sendSingleThreadNotification(context, new NotificationState(notificationState.getNotificationsForThread(threadId)), false, true);
}
if (notificationState.hasMultipleThreads()) {
if (Build.VERSION.SDK_INT >= 23) {
for (int threadId : notificationState.getThreads()) {
sendSingleThreadNotification(context, new NotificationState(notificationState.getNotificationsForThread(threadId)), false, true);
}
sendMultipleThreadNotification(context, notificationState, signal);
} else {
sendSingleThreadNotification(context, notificationState, signal, false);
}
cancelOrphanedNotifications(context, notificationState);
updateBadge(context, notificationState.getMessageCount());
sendMultipleThreadNotification(context, notificationState, signal);
} else {
sendSingleThreadNotification(context, notificationState, signal, false);
}
if (signal) {
scheduleReminder(context, reminderCount);
}
} finally {
if (telcoCursor != null) telcoCursor.close();
if (pushCursor != null) pushCursor.close();
cancelOrphanedNotifications(context, notificationState);
updateBadge(context, notificationState.getMessageCount());
if (signal) {
scheduleReminder(context, reminderCount);
}
}
@@ -404,51 +404,39 @@ public class MessageNotifier {
ringtone.play();
}
private static NotificationState constructNotificationState(@NonNull Context context,
@NonNull Cursor cursor)
private static NotificationState constructNotificationState(@NonNull ApplicationDcContext dcContext,
@NonNull int[] freshMessages)
{
NotificationState notificationState = new NotificationState();
MmsSmsDatabase.Reader reader = DatabaseFactory.getMmsSmsDatabase(context).readerFor(cursor);
Context context = dcContext.context;
MessageRecord record;
while ((record = reader.getNext()) != null) {
long id = record.getId();
boolean mms = record.isMms() || record.isMmsNotification();
Recipient recipient = record.getIndividualRecipient();
Recipient conversationRecipient = record.getRecipient();
long threadId = record.getThreadId();
for(int msgId : freshMessages) {
DcMsg record = dcContext.getMsg(msgId);
int id = record.getId();
boolean mms = record.isMms() || record.isMediaPending();
int chatId = record.getChatId();
CharSequence body = record.getDisplayBody();
Recipient threadRecipients = null;
SlideDeck slideDeck = null;
Recipient threadRecipients = Recipient.from(dcContext, msgId);
SlideDeck slideDeck = new SlideDeck(dcContext.context, record);
long timestamp = record.getTimestamp();
if(slideDeck.getSlides().isEmpty())
slideDeck = null;
if (threadId != -1) {
threadRecipients = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId);
}
if (KeyCachingService.isLocked(context)) {
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_locked_message));
} else if (record.isMms() && !((MmsMessageRecord) record).getSharedContacts().isEmpty()) {
Contact contact = ((MmsMessageRecord) record).getSharedContacts().get(0);
body = ContactUtil.getStringSummary(context, contact);
} else if (record.isMms() && TextUtils.isEmpty(body) && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) {
// TODO: if message content should be hidden on screen lock, do it here.
if (record.isMms() && TextUtils.isEmpty(body)) {
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_media_message));
slideDeck = ((MediaMmsMessageRecord)record).getSlideDeck();
} else if (record.isMms() && !record.isMmsNotification() && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) {
} else if (record.isMms() && !record.isMediaPending()) {
String message = context.getString(R.string.MessageNotifier_media_message_with_text, body);
int italicLength = message.length() - body.length();
body = SpanUtil.italic(message, italicLength);
slideDeck = ((MediaMmsMessageRecord)record).getSlideDeck();
}
if (threadRecipients == null || !threadRecipients.isMuted()) {
notificationState.addNotification(new NotificationItem(id, mms, recipient, conversationRecipient, threadRecipients, threadId, body, timestamp, slideDeck));
notificationState.addNotification(new NotificationItem(id, mms, threadRecipients, chatId, body, timestamp, slideDeck));
}
}
reader.close();
return notificationState;
}
@@ -511,10 +499,10 @@ public class MessageNotifier {
private final AtomicBoolean canceled = new AtomicBoolean(false);
private final Context context;
private final long threadId;
private final int threadId;
private final long delayUntil;
private DelayedNotification(Context context, long threadId) {
private DelayedNotification(Context context, int threadId) {
this.context = context;
this.threadId = threadId;
this.delayUntil = System.currentTimeMillis() + DELAY;
@@ -14,40 +14,30 @@ import org.thoughtcrime.securesms.recipients.Recipient;
public class NotificationItem {
private final long id;
private final int id;
private final boolean mms;
private final @NonNull Recipient conversationRecipient;
private final @NonNull Recipient individualRecipient;
private final @Nullable Recipient threadRecipient;
private final long threadId;
private final int chatId;
private final @Nullable CharSequence text;
private final long timestamp;
private final @Nullable SlideDeck slideDeck;
public NotificationItem(long id, boolean mms,
@NonNull Recipient individualRecipient,
@NonNull Recipient conversationRecipient,
public NotificationItem(int id, boolean mms,
@Nullable Recipient threadRecipient,
long threadId, @Nullable CharSequence text, long timestamp,
int chatId, @Nullable CharSequence text, long timestamp,
@Nullable SlideDeck slideDeck)
{
this.id = id;
this.mms = mms;
this.individualRecipient = individualRecipient;
this.conversationRecipient = conversationRecipient;
this.threadRecipient = threadRecipient;
this.text = text;
this.threadId = threadId;
this.chatId = chatId;
this.timestamp = timestamp;
this.slideDeck = slideDeck;
}
public @NonNull Recipient getRecipient() {
return threadRecipient == null ? conversationRecipient : threadRecipient;
}
public @NonNull Recipient getIndividualRecipient() {
return individualRecipient;
return threadRecipient;
}
public CharSequence getText() {
@@ -58,8 +48,21 @@ public class NotificationItem {
return timestamp;
}
public long getThreadId() {
return threadId;
public int getChatId() {
return chatId;
}
/**
* @deprecated Use getThreadRecipient instead.
*/
@Deprecated
public @NonNull Recipient getIndividualRecipient() {
return threadRecipient;
}
@Deprecated
public int getThreadId() {
return chatId;
}
public @Nullable SlideDeck getSlideDeck() {
@@ -68,9 +71,8 @@ public class NotificationItem {
public PendingIntent getPendingIntent(Context context) {
Intent intent = new Intent(context, ConversationActivity.class);
Recipient notifyRecipients = threadRecipient != null ? threadRecipient : conversationRecipient;
intent.putExtra("thread_id", threadId);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, chatId);
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
return TaskStackBuilder.create(context)
@@ -78,7 +80,7 @@ public class NotificationItem {
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
}
public long getId() {
public int getId() {
return id;
}
@@ -20,7 +20,7 @@ import java.util.List;
public class NotificationState {
private final LinkedList<NotificationItem> notifications = new LinkedList<>();
private final LinkedHashSet<Long> threads = new LinkedHashSet<>();
private final LinkedHashSet<Integer> threads = new LinkedHashSet<>();
private int notificationCount = 0;
@@ -71,7 +71,7 @@ public class NotificationState {
return threads.size() > 1;
}
public LinkedHashSet<Long> getThreads() {
public LinkedHashSet<Integer> getThreads() {
return threads;
}
@@ -87,7 +87,7 @@ public class NotificationState {
return notifications;
}
public List<NotificationItem> getNotificationsForThread(long threadId) {
public List<NotificationItem> getNotificationsForThread(int threadId) {
LinkedList<NotificationItem> list = new LinkedList<>();
for (NotificationItem item : notifications) {
@@ -98,10 +98,10 @@ public class NotificationState {
}
public PendingIntent getMarkAsReadIntent(Context context, int notificationId) {
long[] threadArray = new long[threads.size()];
int[] threadArray = new int[threads.size()];
int index = 0;
for (long thread : threads) {
for (int thread : threads) {
Log.w("NotificationState", "Added thread: " + thread);
threadArray[index++] = thread;
}
@@ -135,16 +135,16 @@ public class NotificationState {
intent.setClass(context, AndroidAutoReplyReceiver.class);
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
intent.putExtra(AndroidAutoReplyReceiver.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(AndroidAutoReplyReceiver.THREAD_ID_EXTRA, (long)threads.toArray()[0]);
intent.putExtra(AndroidAutoReplyReceiver.THREAD_ID_EXTRA, (int)threads.toArray()[0]);
intent.setPackage(context.getPackageName());
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public PendingIntent getAndroidAutoHeardIntent(Context context, int notificationId) {
long[] threadArray = new long[threads.size()];
int[] threadArray = new int[threads.size()];
int index = 0;
for (long thread : threads) {
for (int thread : threads) {
Log.w("NotificationState", "getAndroidAutoHeardIntent Added thread: " + thread);
threadArray[index++] = thread;
}
@@ -164,7 +164,7 @@ public class NotificationState {
if (threads.size() != 1) throw new AssertionError("We only support replies to single thread notifications! " + threads.size());
Intent intent = new Intent(context, ConversationPopupActivity.class);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, (long)threads.toArray()[0]);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, (Integer)(threads.toArray())[0]);
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
@@ -173,17 +173,14 @@ public class NotificationState {
public PendingIntent getDeleteIntent(Context context) {
int index = 0;
long[] ids = new long[notifications.size()];
boolean[] mms = new boolean[ids.length];
for (NotificationItem notificationItem : notifications) {
ids[index] = notificationItem.getId();
mms[index++] = notificationItem.isMms();
}
Intent intent = new Intent(context, DeleteNotificationReceiver.class);
intent.setAction(DeleteNotificationReceiver.DELETE_NOTIFICATION_ACTION);
intent.putExtra(DeleteNotificationReceiver.EXTRA_IDS, ids);
intent.putExtra(DeleteNotificationReceiver.EXTRA_MMS, mms);
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);